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...
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...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Access the comprehensive MariaDB Server reference. Find detailed documentation on SQL syntax, data types, functions, system variables, and other technical specifications.
Explore the SQL language structure in MariaDB Server. This section provides fundamental concepts, syntax rules, and common elements that form the building blocks of SQL queries and commands.
Explore the SQL structure in MariaDB Server. This section provides a fundamental overview of SQL syntax, components, and concepts that form the basis for interacting with your database.
Binary literals can be written in one of the following formats: b'value', B'value' or 0bvalue, where value is a string composed by 0 and 1 digits.
Binary literals are interpreted as binary strings, and are convenient to represent VARBINARY, BINARY or BIT values.
To convert a binary literal into an integer, just add 0.
Printing the value as a binary string:
Converting the same value into a number:
This page is licensed: CC BY-SA / Gnu FDL
SELECT 0b1000001;
+-----------+
| 0b1000001 |
+-----------+
| A |
+-----------+SELECT 0b1000001+0;
+-------------+
| 0b1000001+0 |
+-------------+
| 65 |
+-------------+Explore MariaDB Server's NoSQL capabilities. This section details how to store and query schemaless data, including JSON, and how to integrate with other NoSQL data sources, enhancing flexibility.
Explore the HANDLER statement in MariaDB Server for direct table access. This section details how to bypass the SQL optimizer for low-level row operations, useful for specific NoSQL-like interactions.
Learn about comparison operators in MariaDB Server SQL. This section details operators like =, >, <, and LIKE used to compare values in conditions, essential for filtering and joining data.
Learn about arithmetic operators in MariaDB Server SQL. This section details how to perform mathematical calculations like addition, subtraction, multiplication, and division within your queries.
Explore HandlerSocket for MariaDB Server. This plugin enables high-performance NoSQL-like access directly to InnoDB tables, bypassing SQL parsing for fast key-value operations.
Learn about assignment operators in MariaDB Server SQL. This section details how to assign values to variables and columns, essential for data manipulation and programmatic logic.
Learn about logical operators in MariaDB Server SQL. This section details operators like AND, OR, and NOT used to combine or negate conditions, essential for complex filtering and data selection.
Learn about operators in MariaDB Server SQL. This section details arithmetic, comparison, logical, and bitwise operators used in expressions and conditions for data manipulation and querying.
Learn about sequence functions in MariaDB Server. This section details SQL functions for retrieving the next or current value from a sequence, crucial for generating unique identifiers.
GIS stands for Geographic Information System.
Further reading:
OGC Simple Feature Access - the Open Geospatial Consortium's OpenGIS Simple Features Specifications For SQL.
Geo/Spatial Search with MySQL - a presentation by Alexander Rubin, from the MySQL Conference in 2006.
There are no differences between GIS in stable versions of MariaDB and GIS in MySQL. There are, however, some extensions and enhancements being worked on.
This page is licensed: CC BY-SA / Gnu FDL
Some resources and documentation about HandlerSocket.
The home of HandlerSocket is here.
The story of handlersocket can be found here.
presentation by Akira Higuchi of DeNA - June 29 2010 - DeNA Technology Seminar
presentation by Akira Higuchi of DeNA - June 29 2011 - in Japanese
This page is licensed: CC BY-SA / Gnu FDL
Hexadecimal literals can be written using any of the following syntaxes:
x'value'
X'value' (SQL standard)
0xvalue
Geometry is the base class. It is an abstract class. The instantiable subclasses of Geometry are restricted to zero-, one-, and two-dimensional geometric objects that exist in two-dimensional coordinate space. All instantiable geometry classes are defined so that valid instances of a geometry class are topologically closed (that is, all defined geometries include their boundary).
The base Geometry class has subclasses for Point, Curve, Surface, and GeometryCollection:
represents zero-dimensional objects.
Whether objects are case sensitive or not is partly determined by the underlying operating system. Unix-based systems are case sensitive, Windows is not, while Mac OS X is usually case insensitive by default, but devices can be configured as case sensitive using Disk Utility.
Database, table, table aliases, and names are affected by the system's case sensitivity, while index, column, column aliases, , and names are never case sensitive.
Log file group names are case sensitive.
This article explains how to use efficiently with tables.
If you want to scan a table for different key values, not just search for exact key values, you should create your keys with USING BTREE:
In the above table, a is a key that only supports exact matches (=) while b is a key that you can use to scan the table in key order, starting from start or from a given key value.
The limitations for HANDLER READ with MEMORY|HEAP tables are:
Explore temporal tables in MariaDB Server. This section details how to manage data with system-versioning and application-time periods, enabling historical data tracking and time-aware queries.
NEXTVAL is a synonym for .
This page is licensed: CC BY-SA / Gnu FDL
Explore vector data types. This section details how to store and manage numerical arrays, enabling efficient vector similarity search and machine learning applications within your database.
Learn about sequences in MariaDB Server. This section details how to create and manage sequences for generating unique numbers, often used for primary keys and other auto-incrementing values.
Explore geometric data types and functions in MariaDB Server. This section details how to store, query, and manipulate spatial data, enabling geospatial applications within your database.
Learn account management SQL statements for MariaDB Server. This section covers commands like CREATE USER, GRANT, and REVOKE to securely manage user access and privileges within your database.
Curve represents one-dimensional objects, and has a subclass LineString, with sub-subclasses Line and LinearRing.
Surface is designed for two-dimensional objects and has a subclass Polygon.
GeometryCollection has specialized zero-, one-, and two-dimensional collection classes named MultiPoint, MultiLineString, and MultiPolygon for modeling geometries corresponding to collections of Points, LineStrings, and Polygons, respectively. MultiCurve and MultiSurface are introduced as abstract superclasses that generalize the collection interfaces to handle Curves and Surfaces.
Geometry, Curve, Surface, MultiCurve, and MultiSurface are defined as non-instantiable classes. They define a common set of methods for their subclasses and are included for extensibility.
Point, LineString, Polygon, GeometryCollection, MultiPoint,MultiLineString, and MultiPolygon are instantiable classes.
This page is licensed: GPLv2, originally from fill_help_tables.sql
You must use all key parts when searching for a row.
You can't do a key scan of all values. You can only find all rows with the same key value.
READ NEXT gives an error 1031 if the tables changed since last read.
READ NEXT gives an error 1031 if the tables changed since last read. This limitation can be lifted in the future.
READ NEXT gives an error 1031 if the table was truncated since last READ call.
See also the limitations listed in HANDLER commands.
This page is licensed: CC BY-SA / Gnu FDL
TIME 'string'
TIMESTAMP 'string'
ODBC syntax:
{d 'string'}
{t 'string'}
{ts 'string'}
The timestamp literals are treated as DATETIME literals, because in MariaDB the range of DATETIME is closer to the TIMESTAMP range in the SQL standard.
string is a string in a proper format, as explained below.
A DATE string is a string in one of the following formats: 'YYYY-MM-DD' or 'YY-MM-DD'. Note that any punctuation character can be used as delimiter. All delimiters must consist of 1 character. Different delimiters can be used in the same string. Delimiters are optional (but if one delimiter is used, all delimiters must be used).
A DATE literal can also be an integer, in one of the following formats: YYYYMMDD or YYMMDD.
All the following DATE literals are valid, and they all represent the same value:
A DATETIME string is a string in one of the following formats: 'YYYY-MM-DD HH:MM:SS' or 'YY-MM-DD HH:MM:SS'. Note that any punctuation character can be used as delimiter for the date part and for the time part. All delimiters must consist of 1 character. Different delimiters can be used in the same string. The hours, minutes and seconds parts can consist of one character. For this reason, delimiters are mandatory for DATETIME literals.
The delimiter between the date part and the time part can be a T or any sequence of space characters (including tabs, new lines and carriage returns).
A DATETIME literal can also be a number, in one of the following formats: YYYYMMDDHHMMSS, YYMMDDHHMMSS, YYYYMMDD or YYMMDD. In this case, all the time subparts must consist of 2 digits.
All the following DATE literals are valid, and they all represent the same value:
A TIME string is a string in one of the following formats: 'D HH:MM:SS', 'HH:MM:SS, 'D HH:MM', 'HH:MM', 'D HH', or 'SS'. D is a value from 0 to 34 which represents days. : is the only allowed delimiter for TIME literals. Delimiters are mandatory, with an exception: the 'HHMMSS' format is allowed. When delimiters are used, each part of the literal can consist of one character.
A TIME literal can also be a number in one of the following formats: HHMMSS, MMSS, or SS.
The following literals are equivalent:
The year part in DATE and DATETIME literals is determined as follows:
70 - 99 = 1970 - 1999
00 - 69 = 2000 - 2069
DATETIME and TIME literals can have an optional microseconds part. For both string and numeric forms, it is expressed as a decimal part. Up to 6 decimal digits are allowed. Examples:
See Microseconds in MariaDB for details.
Unless the SQL_MODE NO_ZERO_DATE flag is set, some special values are allowed: the '0000-00-00' DATE, the '00:00:00' TIME, and the 0000-00-00 00:00:00 DATETIME.
If the ALLOW_INVALID_DATES flag is set, the invalid dates (for example, 30th February) are allowed. If not, if the NO_ZERO_DATE is set, an error is produced; otherwise, a zero-date is returned.
Unless the NO_ZERO_IN_DATE flag is set, each subpart of a date or time value (years, hours...) can be set to 0.
This page is licensed: CC BY-SA / Gnu FDL
value is a sequence of hexadecimal digits (from 0 to 9 and from A to F). The case of the digits does not matter. With the first two syntaxes, value must consist of an even number of digits. With the last syntax, digits can be even, and they are treated as if they had an extra 0 at the beginning.
Normally, hexadecimal literals are interpreted as binary string, where each pair of digits represents a character. When used in a numeric context, they are interpreted as integers. (See the example below). In no case can a hexadecimal literal be a decimal number.
The first two syntaxes; X'value' and x'value, follow the SQL standard, and behave as a string in all contexts in MariaDB. The latter syntax, 0xvalue, is a MySQL/MariaDB extension for hex hybrids and behaves as a string or as a number depending on context. MySQL treats all syntaxes the same, so there may be different results in MariaDB and MySQL (see below).
Representing the a character with the three syntaxes explained above:
Hexadecimal literals in a numeric context:
The reason for the differing results above is that when 0x31 is inserted directly to the column, it's treated as a number, while when 0x31 is passed to COALESCE(), it's treated as a string, because:
HEX values have a string data type by default.
COALESCE() has the same data type as the argument.
In MySQL (up until at least MySQL 8.0.26):
This page is licensed: CC BY-SA / Gnu FDL
Because MariaDB uses directories and files to store databases and tables, database and table names are case-sensitive if they are located on a file system that has case-sensitive file names.
Even for file systems that are not case-sensitive, such as on Windows, all references to a given table within a query must use the same lettercase.
The lower_case_table_names server system variable plays a key role. It determines whether table names, aliases, and database names are compared in a case-sensitive manner. If set to 0 (the default on Unix-based systems), table names and aliases, and database names are compared in a case-sensitive manner. If set to 1 (the default on Windows), names are stored in lowercase and not compared in a case-sensitive manner. If set to 2 (the default on Mac OS X), names are stored as declared, but compared in lowercase.
It is thus possible to make Unix-based systems behave like Windows and ignore case-sensitivity. The reverse is not true before Windows 10, as the underlying Windows filesystem could not support this. It is possible since Windows 10, although case insensitivity is still the default operating system setting.
Even on case-insensitive systems, you are required to use the same case consistently within the same statement. The following statement fails, as it refers to the table name in a different case.
For a full list of identifiers naming rules, see Identifier Names.
This page is licensed: CC BY-SA / Gnu FDL
If the return value is used in an INTEGER context or all arguments are integer-valued, they are compared as integers.
If the return value is used in a REAL context or all arguments are real-valued, they are compared as reals.
If any argument is a case-sensitive string, the arguments are compared as case-sensitive strings.
In all other cases, the arguments are compared as case-insensitive strings.
LEAST() returns NULL if any argument is NULL.
This page is licensed: GPLv2, originally from fill_help_tables.sql
LEAST(value1,value2,...)FALSEUNKNOWNThis page is licensed: GPLv2, originally from fill_help_tables.sql
IS NOT boolean_valueSELECT 1 IS NOT UNKNOWN, 0 IS NOT UNKNOWN, NULL IS NOT UNKNOWN;
+------------------+------------------+---------------------+
| 1 IS NOT UNKNOWN | 0 IS NOT UNKNOWN | NULL IS NOT UNKNOWN |
+------------------+------------------+---------------------+
| 1 | 1 | 0 |
+------------------+------------------+---------------------+This page is licensed: GPLv2, originally from fill_help_tables.sql
N % MCREATE TABLE t1 (a INT, b INT, KEY(a), KEY b USING BTREE (b)) ENGINE=memory;'19940101'
'940101'
'1994-01-01'
'94/01/01'
'1994-01/01'
'94:01!01'
19940101
940101'1994-01-01T12:30:03'
'1994/01/01\n\t 12+30+03'
'1994/01\\01\n\t 12+30-03'
'1994-01-01 12:30:3''09:05:00'
'9:05:0'
'9:5:0'
'090500''12:30:00.123456'
123000.123456SELECT x'61', X'61', 0x61;
+-------+-------+------+
| x'61' | X'61' | 0x61 |
+-------+-------+------+
| a | a | a |
+-------+-------+------+SELECT 0 + 0xF, -0xF;
+---------+------+
| 0 + 0xF | -0xF |
+---------+------+
| 15 | -15 |
+---------+------+CREATE TABLE t1 (a INT, b VARCHAR(10));
INSERT INTO t1 VALUES (0x31, 0x61),(COALESCE(0x31), COALESCE(0x61));
SELECT * FROM t1;
+------+------+
| a | b |
+------+------+
| 49 | a |
| 1 | a |
+------+------+SELECT x'0a'+0;
+---------+
| x'0a'+0 |
+---------+
| 0 |
+---------+
1 row in set, 1 warning (0.00 sec)
Warning (Code 1292): Truncated incorrect DOUBLE value: '\x0A'
SELECT X'0a'+0;
+---------+
| X'0a'+0 |
+---------+
| 0 |
+---------+
1 row in set, 1 warning (0.00 sec)
Warning (Code 1292): Truncated incorrect DOUBLE value: '\x0A'
SELECT 0x0a+0;
+--------+
| 0x0a+0 |
+--------+
| 10 |
+--------+SELECT x'0a'+0;
+---------+
| x'0a'+0 |
+---------+
| 10 |
+---------+
SELECT X'0a'+0;
+---------+
| X'0a'+0 |
+---------+
| 10 |
+---------+
SELECT 0x0a+0;
+--------+
| 0x0a+0 |
+--------+
| 10 |
+--------+SELECT * FROM a_table WHERE A_table.id>10;SELECT LEAST(2,0);
+------------+
| LEAST(2,0) |
+------------+
| 0 |
+------------+SELECT LEAST(34.0,3.0,5.0,767.0);
+---------------------------+
| LEAST(34.0,3.0,5.0,767.0) |
+---------------------------+
| 3.0 |
+---------------------------+SELECT LEAST('B','A','C');
+--------------------+
| LEAST('B','A','C') |
+--------------------+
| A |
+--------------------+SELECT NULL IS NOT TRUE, NULL IS NOT FALSE;
+------------------+-------------------+
| NULL IS NOT TRUE | NULL IS NOT FALSE |
+------------------+-------------------+
| 1 | 1 |
+------------------+-------------------+SELECT 1042 % 50;
+-----------+
| 1042 % 50 |
+-----------+
| 42 |
+-----------+NO_UNSIGNED_SUBTRACTIONFor real or string operands, the operand with the highest precision determines the result precision.
Unary minus:
This page is licensed: CC BY-SA / Gnu FDL
Qualifiers are used within SQL statements to reference data structures, such as databases, tables, or columns. For example, typically a SELECT query contains references to some columns and at least one table.
Qualifiers can be composed by one or more identifiers, where the initial parts affect the context within which the final identifier is interpreted:
For a database, only the database identifier needs to be specified.
For objects which are contained in a database (like tables, views, functions, etc.) the database identifier can be specified. If no database is specified, the current database is assumed (see USE and DATABASE() for more details). If there is no default database and no database is specified, an error is issued.
For column names, the table and the database are generally obvious from the context of the statement. It is however possible to specify the table identifier, or the database identifier plus the table identifier.
An identifier is fully-qualified if it contains all possible qualifiers, for example, the following column is fully qualified: db_name.tbl_name.col_name.
If a qualifier is composed by more than one identifier, a dot (.) must be used as a separator. All identifiers can be quoted individually. Extra spacing (including new lines and tabs) is allowed.
All the following examples are valid:
db_name.tbl_name.col_name
tbl_name
db_name.tbl_name.col_name
If a table identifier is prefixed with a dot (.), the default database is assumed. This syntax is supported for ODBC compliance, but has no practical effect on MariaDB. These qualifiers are equivalent:
tbl_name
. tbl_name
.tbl_name
. tbl_name
For DML statements, it is possible to specify a list of the partitions using the PARTITION clause. See for details.
This page is licensed: CC BY-SA / Gnu FDL
In order to make use of the HandlerSocket plugin in your applications, you will need to use the appropriate client library. The following client libraries are available:
C++
libhsclient (included with the HandlerSocket plugin source)
Perl
perl-Net-HandlerSocket (included with the HandlerSocket plugin source)
PHP
Java
Python
Ruby
JavaScript
node-handlersocket
Scala
Haskell
HandlerSocket-Haskell-Client
This page is licensed: CC BY-SA / Gnu FDL
On MyISAM, Aria and InnoDB tables, MariaDB can create spatial indexes (an R-tree index) using syntax similar to that for creating regular indexes, but extended with the SPATIAL keyword. Columns in spatial indexes must be declared NOT NULL.
Spatial indexes can be created when the table is created, or added after the fact:
CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g));ALTER TABLE geom ADD SPATIAL INDEX(g);SPATIAL INDEX creates an R-tree index. For storage engines that support non-spatial indexing of spatial columns, the engine creates a B-tree index. A B-tree index on spatial values is useful for
exact-value lookups, but not for range scans.
For more information on indexing spatial columns, see .
To drop spatial indexes, use or :
If is set to full_crc32 or strict_full_crc32, and if the table does not use , InnoDB spatial indexes are encrypted if the table is encrypted.
See for more information.
This page is licensed: GPLv2, originally from
+Addition.
If both operands are integers, the result is calculated with BIGINT precision. If either integer is unsigned, the result is also an unsigned integer.
For real or string operands, the operand with the highest precision determines the result precision.
This page is licensed: GPLv2, originally from
GREATEST(value1,value2,...)With two or more arguments, returns the largest (maximum-valued) argument. The arguments are compared using the same rules as for LEAST().
This page is licensed: GPLv2, originally from
NOT, !Logical NOT. Evaluates to 1 if the operand is 0, to 0 if the operand is non-zero, and NOT NULL returns NULL.
By default, the ! operator has a . If the HIGH_NOT_PRECEDENCE flag is set, NOT and ! have the same precedence.
This page is licensed: GPLv2, originally from
<=>NULL-safe equal operator. It performs an equality comparison like the = operator, but returns 1 rather than NULL if both operands are NULL, and 0 rather than NULL if one operand is NULL.
a <=> b is equivalent to a = b OR (a IS NULL AND b IS NULL).
When used in row comparisons, these two queries return the same results:
See also .
This page is licensed: GPLv2, originally from
>Greater than operator. Evaluates both SQL expressions and returns 1 if the left value is greater than the right value and 0 if it is not, or NULL if either expression is NULL. If the expressions return different data types, (for instance, a number and a string), performs type conversion.
When used in row comparisons these two queries return the same results:
This page is licensed: GPLv2, originally from
IS NOT NULLTests whether a value is not NULL. See also NULL Values in MariaDB.
This page is licensed: GPLv2, originally from
Tests a value against a boolean value, where boolean_value can be TRUE, FALSE, or UNKNOWN.
There is an important difference between using IS TRUE or comparing a value with TRUE using =. When using =, only 1 equals to TRUE. But when using IS TRUE, all values which are logically true (like a number > 1) return TRUE.
Difference between = and IS TRUE:
This page is licensed: GPLv2, originally from
<Less than operator. Evaluates both SQL expressions and returns 1 if the left value is less than the right value and 0 if it is not, or NULL if either expression is NULL. If the expressions return different data types, (for instance, a number and a string), performs type conversion.
When used in row comparisons, these two queries return the same results:
Type conversion:
Case insensitivity - see :
This page is licensed: GPLv2, originally from
VALUES ( row_value[, row_value...]), (...)...In Unions, Views, and subqueries, a Table Value Constructor (TVC) allows you to inject arbitrary values into the result set. The given values must have the same number of columns as the result set, otherwise it returns Error 1222.
Using TVC's with operations:
Using TVCs with a statement:
Using TVC with an clause:
Using TVC with clause:
This page is licensed: CC BY-SA / Gnu FDL
identifier = exprThe equal sign is used as both an assignment operator in certain contexts, and as a comparison operator. When used as assignment operator, the value on the right is assigned to the variable (or column, in some contexts) on the left.
Since its use can be ambiguous, unlike the , the = assignment operator cannot be used in all contexts, and is only valid as part of a statement, or the SET clause of an statement
This operator works with both and .
This page is licensed: CC BY-SA / Gnu FDL
VECTOR(N)The VECTOR data type was added as part of the feature, which permits MariaDB Server to perform as a relational vector database. N represents the fixed number of dimensions of the vector up to a maximum of 16383. The N dimension will be determined by the embedding algorithm.
This page is licensed: CC BY-SA / Gnu FDL
In MariaDB, FALSE is a synonym of 0 and TRUE is a synonym of 1. These constants are case insensitive, so TRUE, True, and true are equivalent.
These terms are not synonyms of 0 and 1 when used with the IS operator. So, for example, 10 IS TRUE returns 1, while 10 = TRUE returns 0 (because 1 != 10).
The IS operator accepts a third constant exists: UNKNOWN. It is always a synonym of .
TRUE and FALSE are , while UNKNOWN is not.
type
This page is licensed: CC BY-SA / Gnu FDL
Explore joins, subqueries, and set operations in MariaDB SQL. This section details how to combine data from multiple tables, nest queries, and perform set-based operations for complex data retrieval.
SQL (Structured Query Language) is a highly potent language used in the realm of databases and data analytics. It allows us to create, manipulate, and retrieve data stored in relational databases. While simple SQL commands can handle straightforward tasks, one must delve into advanced aspects such as multiple joins, subqueries, and set operations to unravel the full potential of SQL.
Joins are fundamental to SQL, as they enable us to combine rows from two or more tables based on related columns. Several types of joins exist, including INNER JOIN, LEFT JOIN, RIGHT JOIN
Numeric literals are written as a sequence of digits from 0 to 9. Initial zeros are ignored. A sign can always precede the digits, but it is optional for positive numbers. In decimal numbers, the integer part and the decimal part are divided with a dot (.).
If the integer part is zero, it can be omitted, but the literal must begin with a dot.
The notation with exponent can be used. The exponent is preceded by an E or e character. The exponent can be preceded by a sign and must be an integer. A number N with an exponent part X, is calculated as N * POW(10, X).
This section details the different ways to add non-executable comments to your SQL statements and script files, including single-line & multi-line comments, and MariaDB-specific conditional comments.
There are three supported comment styles in MariaDB:
From a hash sign (#) to the end of a line:
From a double dash (--) to the end of a line. The space after the two dashes is required (as in MySQL).
LASTVAL is a synonym for .
This page is licensed: CC BY-SA / Gnu FDL
Learn to select data in MariaDB Server using SQL. This section covers various SELECT statement clauses, including WHERE, GROUP BY, and ORDER BY, to retrieve and filter your data effectively.
After MariaDB is installed, use the command (as the root user) to install the HandlerSocket plugin. This command only needs to be run once, like so:
After installing the plugin, shows you first need to configure some settings. All are placed in the [mysqld] section of your my.cnf file.
At least the , and options need to be set:
After updating the configuration options, restart MariaDB.
On the client side, to make use of the plugin you will need to install the appropriate client library (that is, libhsclient for C++ applications and perl-Net-HandlerSocket for perl applications).
This page is licensed: CC BY-SA / Gnu FDL
-SELECT 96-9;
+------+
| 96-9 |
+------+
| 87 |
+------+
SELECT 15-17;
+-------+
| 15-17 |
+-------+
| -2 |
+-------+
SELECT 3.66 + 1.333;
+--------------+
| 3.66 + 1.333 |
+--------------+
| 4.993 |
+--------------+SELECT - (3+5);
+---------+
| - (3+5) |
+---------+
| -8 |
+---------+CREATE SPATIAL INDEX sp_index ON geom (g);IS boolean_valuedb_name . tbl_namedb_name. tbl_name
SELECT GREATEST(2,0);
+---------------+
| GREATEST(2,0) |
+---------------+
| 2 |
+---------------+SELECT GREATEST(34.0,3.0,5.0,767.0);
+------------------------------+
| GREATEST(34.0,3.0,5.0,767.0) |
+------------------------------+
| 767.0 |
+------------------------------+SELECT 1 NOT BETWEEN 2 AND 3;
+-----------------------+
| 1 NOT BETWEEN 2 AND 3 |
+-----------------------+
| 1 |
+-----------------------+SELECT ISNULL(1+1);
+-------------+
| ISNULL(1+1) |
+-------------+
| 0 |
+-------------+
SELECT ISNULL(1/0);
+-------------+
| ISNULL(1/0) |
+-------------+
| 1 |
+-------------+CREATE VIEW v1 AS VALUES (7, 9), (9, 10);
SELECT * FROM v1;
+---+----+
| 7 | 9 |
+---+----+
| 7 | 9 |
| 9 | 10 |
+---+----+INSTALL PLUGIN handlersocket SONAME 'handlersocket.so';handlersocket_address="127.0.0.1"
handlersocket_port="9998"
handlersocket_port_wr="9999"FULL JOINIn real-world scenarios, finding database schemas with multiple tables linked through relationships is common. In such cases, we often need to write SQL queries with multiple joins to fetch the required data.
For instance, consider a database for a bookstore with three tables: Books, Authors, and Publishers. If we want to get a list of books along with their author names and publishers, you would require multiple joins.
In that query, we used two INNER JOIN operations to combine data from the three tables.
A subquery, also known as a nested query or inner query, is a query embedded within another SQL query. The result of the subquery can be used in the outer query. Subqueries can be used in SELECT, INSERT, UPDATE, and DELETE statements and also in conjunction with WHERE and HAVING clauses.
Subqueries can prove powerful in many scenarios. For example, suppose we want to find books that are above the average price in our bookstore database. We could achieve this using a subquery.
In this query, the subquery calculates the average book price, which the outer query then uses to filter books that are priced above average.
SQL also provides several set operations to combine rows from two or more tables, including UNION, UNION ALL, INTERSECT, and EXCEPT. These operations are instrumental when dealing with large databases where data is spread across multiple tables and we need to perform set-based operations.
For example, suppose we have two tables, Books_2019 and Books_2020, listing the books sold in the respective years. If we want to find books sold in both years, we can use the INTERSECT operation.
In the above query, INTERSECT returns the common book titles sold in both 2019 and 2020.
Advanced SQL queries that involve multiple joins, subqueries, and set operations can be daunting at first glance. However, these incredibly powerful tools in our SQL toolkit enable us to craft complex data retrieval and manipulation commands. To truly excel in data analytics, mastering these aspects of SQL is not only beneficial but essential.
Remember, practice is the key to mastering these advanced SQL concepts, like any other technical skill. Write queries, solve problems, make mistakes, and learn from them. Over time, you'll find yourself not only comfortable but proficient in creating intricate SQL queries.
This page is licensed: CC BY-SA / Gnu FDL
PI()+0.0000000000 expression (with 10 zeroes) returns a number with 10 decimal digits.Hexadecimal literals are interpreted as numbers when used in numeric contexts.
All these literals are equivalent:
With exponents:
This page is licensed: CC BY-SA / Gnu FDL
10
+10
-100.1
.1
+0.1
+.1NULLNULLWhen used in row comparisons, these two queries return the same results:
This page is licensed: GPLv2, originally from fill_help_tables.sql
>=NULL00NULLFor this operator, short-circuit evaluation can be used.
This page is licensed: GPLv2, originally from fill_help_tables.sql
NULLNULLWhen used in row comparisons these two queries return the same results:
This page is licensed: GPLv2, originally from fill_help_tables.sql
<>, !=IN0exprIf expr is NULL, IN always returns NULL. If at least one of the values in the list is NULL, and one of the comparisons is true, the result is 1. If at least one of the values in the list is NULL and none of the comparisons is true, the result is NULL.
Type conversion:
This page is licensed: GPLv2, originally from fill_help_tables.sql
NULLNULL10In the following example, the right 1 XOR 1 is evaluated first, and returns 0. Then, 1 XOR 0 is evaluated, and 1 is returned.
This page is licensed: GPLv2, originally from fill_help_tables.sql
This operator works with both user-defined variables and local variables.
When assigning the same value to several variables, LAST_VALUE() can be useful.
This page is licensed: CC BY-SA / Gnu FDL
DROP ROLE does not disable roles for connections which selected them with SET ROLE. If a role has previously been set as a default role, DROP ROLE does not remove the record of the default role from the mysql.user table. If the role is subsequently recreated and granted, it will again be the user's default. Use SET DEFAULT ROLE NONE to explicitly remove this.
If any of the specified user accounts do not exist, ERROR 1396 (HY000)results. If an error occurs, DROP ROLE will still drop the roles that do not result in an error. Only one error is produced for all roles which have not been dropped:
Failed CREATE or DROP operations, for both users and roles, produce the same error code.
If the IF EXISTS clause is used, MariaDB will return a warning instead of an error if the role does not exist.
The same thing using the optional IF EXISTS clause:
This page is licensed: CC BY-SA / Gnu FDL
ALTER TABLE geom DROP INDEX g;DROP INDEX sp_index ON geom;SELECT 3+5;
+-----+
| 3+5 |
+-----+
| 8 |
+-----+SELECT GREATEST('B','A','C');
+-----------------------+
| GREATEST('B','A','C') |
+-----------------------+
| C |
+-----------------------+SELECT NOT 10;
+--------+
| NOT 10 |
+--------+
| 0 |
+--------+
SELECT NOT 0;
+-------+
| NOT 0 |
+-------+
| 1 |
+-------+
SELECT NOT NULL;
+----------+
| NOT NULL |
+----------+
| NULL |
+----------+
SELECT ! (1+1);
+---------+
| ! (1+1) |
+---------+
| 0 |
+---------+
SELECT ! 1+1;
+-------+
| ! 1+1 |
+-------+
| 1 |
+-------+SELECT (t1.a, t1.b) <=> (t2.x, t2.y)
FROM t1 INNER JOIN t2;
SELECT (t1.a <=> t2.x) AND (t1.b <=> t2.y)
FROM t1 INNER JOIN t2;SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
+---------+---------------+------------+
| 1 <=> 1 | NULL <=> NULL | 1 <=> NULL |
+---------+---------------+------------+
| 1 | 1 | 0 |
+---------+---------------+------------+
SELECT 1 = 1, NULL = NULL, 1 = NULL;
+-------+-------------+----------+
| 1 = 1 | NULL = NULL | 1 = NULL |
+-------+-------------+----------+
| 1 | NULL | NULL |
+-------+-------------+----------+SELECT 7*6;
+-----+
| 7*6 |
+-----+
| 42 |
+-----+
SELECT 1234567890*9876543210;
+-----------------------+
| 1234567890*9876543210 |
+-----------------------+
| -6253480962446024716 |
+-----------------------+
SELECT 18014398509481984*18014398509481984.0;
+---------------------------------------+
| 18014398509481984*18014398509481984.0 |
+---------------------------------------+
| 324518553658426726783156020576256.0 |
+---------------------------------------+
SELECT 18014398509481984*18014398509481984;
+-------------------------------------+
| 18014398509481984*18014398509481984 |
+-------------------------------------+
| 0 |
+-------------------------------------+SELECT 'b' NOT BETWEEN 'a' AND 'c';
+-----------------------------+
| 'b' NOT BETWEEN 'a' AND 'c' |
+-----------------------------+
| 0 |
+-----------------------------+SELECT 1 NOT BETWEEN 1 AND NULL;
+--------------------------+
| 1 NOT BETWEEN 1 AND NULL |
+--------------------------+
| NULL |
+--------------------------+SELECT (t1.a, t1.b) > (t2.x, t2.y)
FROM t1 INNER JOIN t2;
SELECT (t1.a > t2.x) OR ((t1.a = t2.x) AND (t1.b > t2.y))
FROM t1 INNER JOIN t2;SELECT 2 > 2;
+-------+
| 2 > 2 |
+-------+
| 0 |
+-------+
SELECT 'b' > 'a';
+-----------+
| 'b' > 'a' |
+-----------+
| 1 |
+-----------+SELECT 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;
+---------------+---------------+------------------+
| 1 IS NOT NULL | 0 IS NOT NULL | NULL IS NOT NULL |
+---------------+---------------+------------------+
| 1 | 1 | 0 |
+---------------+---------------+------------------+SELECT 1 IS TRUE, 0 IS FALSE, NULL IS UNKNOWN;
+-----------+------------+-----------------+
| 1 IS TRUE | 0 IS FALSE | NULL IS UNKNOWN |
+-----------+------------+-----------------+
| 1 | 1 | 1 |
+-----------+------------+-----------------+SELECT 2 = TRUE, 2 IS TRUE;
+----------+-----------+
| 2 = TRUE | 2 IS TRUE |
+----------+-----------+
| 0 | 1 |
+----------+-----------+SELECT (t1.a, t1.b) < (t2.x, t2.y)
FROM t1 INNER JOIN t2;
SELECT (t1.a < t2.x) OR ((t1.a = t2.x) AND (t1.b < t2.y))
FROM t1 INNER JOIN t2;SELECT 2 < 2;
+-------+
| 2 < 2 |
+-------+
| 0 |
+-------+SELECT 3<'4';
+-------+
| 3<'4' |
+-------+
| 1 |
+-------+SELECT 'a'<'A';
+---------+
| 'a'<'A' |
+---------+
| 0 |
+---------+CREATE TABLE test.t1 (val1 INT, val2 INT);
INSERT INTO test.t1 VALUES(5, 8), (3, 4), (1, 2);
SELECT * FROM test.t1
UNION
VALUES (70, 90), (100, 110);
+------+------+
| val1 | val2 |
+------+------+
| 5 | 8 |
| 3 | 4 |
| 1 | 2 |
| 70 | 90 |
| 100 | 110 |
+------+------+SELECT * FROM test.t1
UNION
VALUES (10, 20), (30, 40), (50, 60), (70, 80)
ORDER BY val1 DESC;SELECT * FROM test.t1
UNION
VALUES (10, 20), (30, 40), (50, 60), (70, 80)
LIMIT 2 OFFSET 4;
+------+------+
| val1 | val2 |
+------+------+
| 30 | 40 |
| 50 | 60 |
+------+------+UPDATE table_name SET x = 2 WHERE x > 100;SET @x = 1, @y := 2;CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY, v VECTOR(5) NOT NULL,
VECTOR INDEX (v));SELECT Books.title, Authors.name, Publishers.name
FROM Books
INNER JOIN Authors ON Books.author_id = Authors.id
INNER JOIN Publishers ON Books.publisher_id = Publishers.id;SELECT title, price
FROM Books
WHERE price > (SELECT AVG(price) FROM Books);SELECT title FROM Books_2019
INTERSECT
SELECT title FROM Books_2020;0.2E3 -- 0.2 * POW(10, 3) = 200
.2e3
.2e+2
1.1e-10 -- 0.00000000011
-1.1e10 -- -11000000000SELECT (t1.a, t1.b) >= (t2.x, t2.y)
FROM t1 INNER JOIN t2;
SELECT (t1.a > t2.x) OR ((t1.a = t2.x) AND (t1.b >= t2.y))
FROM t1 INNER JOIN t2;SELECT 2 >= 2;
+--------+
| 2 >= 2 |
+--------+
| 1 |
+--------+
SELECT 'A' >= 'a';
+------------+
| 'A' >= 'a' |
+------------+
| 1 |
+------------+AND, &&SELECT 1 && 1;
+--------+
| 1 && 1 |
+--------+
| 1 |
+--------+
SELECT 1 && 0;
+--------+
| 1 && 0 |
+--------+
| 0 |
+--------+
SELECT 1 && NULL;
+-----------+
| 1 && NULL |
+-----------+
| NULL |
+-----------+
SELECT 0 && NULL;
+-----------+
| 0 && NULL |
+-----------+
| 0 |
+-----------+
SELECT NULL && 0;
+-----------+
| NULL && 0 |
+-----------+
| 0 |
+-----------+SELECT (t1.a, t1.b) != (t2.x, t2.y)
FROM t1 INNER JOIN t2;
SELECT (t1.a != t2.x) OR (t1.b != t2.y)
FROM t1 INNER JOIN t2;SELECT '.01' <> '0.01';
+-----------------+
| '.01' <> '0.01' |
+-----------------+
| 1 |
+-----------------+
SELECT .01 <> '0.01';
+---------------+
| .01 <> '0.01' |
+---------------+
| 0 |
+---------------+
SELECT 'zapp' <> 'zappp';
+-------------------+
| 'zapp' <> 'zappp' |
+-------------------+
| 1 |
+-------------------+expr IN (value,...)SELECT 2 IN (0,3,5,7);
+----------------+
| 2 IN (0,3,5,7) |
+----------------+
| 0 |
+----------------+SELECT 'wefwf' IN ('wee','wefwf','weg');
+----------------------------------+
| 'wefwf' IN ('wee','wefwf','weg') |
+----------------------------------+
| 1 |
+----------------------------------+SELECT 1 IN ('1', '2', '3');
+----------------------+
| 1 IN ('1', '2', '3') |
+----------------------+
| 1 |
+----------------------+SELECT NULL IN (1, 2, 3);
+-------------------+
| NULL IN (1, 2, 3) |
+-------------------+
| NULL |
+-------------------+
SELECT 1 IN (1, 2, NULL);
+-------------------+
| 1 IN (1, 2, NULL) |
+-------------------+
| 1 |
+-------------------+
SELECT 5 IN (1, 2, NULL);
+-------------------+
| 5 IN (1, 2, NULL) |
+-------------------+
| NULL |
+-------------------+XORSELECT 1 XOR 1;
+---------+
| 1 XOR 1 |
+---------+
| 0 |
+---------+
SELECT 1 XOR 0;
+---------+
| 1 XOR 0 |
+---------+
| 1 |
+---------+
SELECT 1 XOR NULL;
+------------+
| 1 XOR NULL |
+------------+
| NULL |
+------------+SELECT 1 XOR 1 XOR 1;
+---------------+
| 1 XOR 1 XOR 1 |
+---------------+
| 1 |
+---------------+var_name := exprSELECT @x := 10;
+----------+
| @x := 10 |
+----------+
| 10 |
+----------+
SELECT @x, @y := @x;
+------+----------+
| @x | @y := @x |
+------+----------+
| 10 | 10 |
+------+----------+DROP ROLE [IF EXISTS] role_name [,role_name ...]ERROR 1396 (HY000): Operation DROP ROLE failed for 'a','b','c'DROP ROLE journalist;DROP ROLE journalist;
ERROR 1396 (HY000): Operation DROP ROLE failed for 'journalist'
DROP ROLE IF EXISTS journalist;
Query OK, 0 rows affected, 1 warning (0.00 sec)
Note (Code 1975): Can't drop role 'journalist'; it doesn't existC style comments from an opening '/*' to a closing '*/'. Comments of this form can span multiple lines:
Nested comments are possible in some situations, but they are not supported or recommended.
As an aid to portability between different databases, MariaDB supports executable comments. These special comments allow you to embed SQL code which will not execute when run on other databases, but will execute when run on MariaDB.
MariaDB supports both MySQL's executable comment format, and a slightly modified version specific to MariaDB. This way, if you have SQL code that works on MySQL and MariaDB, but not other databases, you can wrap it in a MySQL executable comment, and if you have code that specifically takes advantage of features only available in MariaDB you can use the MariaDB specific format to hide the code from MySQL.
MySQL and MariaDB executable comment syntax:
Code that should be executed only starting from a specific MySQL or MariaDB version:
The numbers, represented by '######' in the syntax examples above specify the specific the minimum versions of MySQL and MariaDB that should execute the comment. The first number is the major version, the second 2 numbers are the minor version and the last 2 is the patch level.
For example, if you want to embed some code that should only execute on MySQL or MariaDB starting from 5.1.0, you would do the following:
MariaDB-only executable comment syntax (starting from ):
MariaDB ignores MySQL-style executable comments that have a version number in the range 50700..99999. This is needed to skip features introduced in MySQL-5.7 that are not ported to MariaDB 10.x yet.
Note: comments which have a version number in the range 50700..99999 that use MariaDB-style executable comment syntax are still executed.
Statement delimiters cannot be used within executable comments.
In MySQL all the following will return 2: In MariaDB, the last 2 queries would return 3.
The following executable statement will not work due to the delimiter inside the executable portion:
Instead, the delimiter should be placed outside the executable portion:
This page is licensed: CC BY-SA / Gnu FDL
Important: When a table is dropped, user privileges on the table are not automatically dropped. See GRANT.
If another connection is using the sequence, a metadata lock is active, and this statement will wait until the lock is released. This is also true for non-transactional tables.
For each referenced sequence, DROP SEQUENCE drops a temporary sequence with that name, if it exists. If it does not exist, and the TEMPORARY keyword is not used, it drops a non-temporary sequence with the same name, if it exists. The TEMPORARY keyword ensures that a non-temporary sequence will not accidentally be dropped.
Use IF EXISTS to prevent an error from occurring for sequences that do not exist. A NOTE is generated for each non-existent sequence when using IF EXISTS. See SHOW WARNINGS.
DROP SEQUENCE requires the DROP privilege.
DROP SEQUENCE only removes sequences, not tables. However, DROP TABLE can remove both sequences and tables.
This page is licensed: CC BY-SA / Gnu FDL
Some ODBC applications use the syntax auto_increment_field IS NOT NULL to find the latest row that was inserted with an autogenerated key value. If your applications need this, you can set the sql_auto_is_null variable to 1.
This page is licensed: GPLv2, originally from fill_help_tables.sql
User-defined variables are variables which can be created by the user and exist in the session. This means that no one can access user-defined variables that have been set by another user, and when the session is closed these variables expire. However, these variables can be shared between several queries and stored programs.
User-defined variables names must be preceded by a single at character (@). While it is safe to use a reserved word as a user-variable name, the only allowed characters are ASCII letters, digits, dollar sign ($), underscore (_) and dot (.). If other characters are used, the name can be quoted in one of the following ways:
@var_name
@'var_name'
@"var_name"
These characters can be escaped as usual.
User-variables names are case insensitive.
User-defined variables cannot be declared. They can be read even if no value has been set yet; in that case, they are NULL. To set a value for a user-defined variable you can use:
statement;
operator within a SQL statement;
.
Since user-defined variables type cannot be declared, the only way to force their type is using or :
If a variable has not been used yet, its value is NULL:
It is unsafe to read a user-defined variable and set its value in the same statement (unless the command is SET), because the order of these actions is undefined.
User-defined variables can be used in most MariaDB's statements and clauses which accept an SQL expression. However there are some exceptions, like the clause.
They must be used to a prepared statement:
Another common use is to include a counter in a query:
User-defined variables can be viewed by either querying the , or by running SHOW USER_VARIABLES.
User-defined variables are reset and the emptied with the statement.
This page is licensed: CC BY-SA / Gnu FDL
Logical OR. When both operands are non-NULL, the result is 1 if any operand is non-zero, and 0 otherwise. With a NULL operand, the result is 1 if the other operand is non-zero, and NULL otherwise. If both operands are NULL, the result is NULL.
For this operator, can be used.
Note that, if the PIPES_AS_CONCAT is set, || is used as a string concatenation operator. This means that a || b is the same as CONCAT(a,b). See for details.
In , || ignores .
In :
This page is licensed: GPLv2, originally from
Create tables optimized for vector storage. Learn to define columns with the VECTOR data type and configure vector indexes for similarity search.
MariaDB has a dedicated VECTOR(N) data type with a built-in data validation. N is the number of dimensions that all vector values in the column have.
Consider the following table:
To have a fast vector search, you have to index the vector column, creating a VECTOR index:
Note that there can be only one vector index in the table, and the indexed vector column must be NOT NULL.
There are two options that can be used to configure the vector index:
M — Larger values mean slower SELECT and INSERT statements, larger index size and higher memory consumption, but more accurate results. The valid range is from 3 to 200.
DISTANCE — Distance function to build the vector index for. Searches using a different distance function will not be able to use a vector index. Valid values are cosine and euclidean
This page is licensed: CC BY-SA / Gnu FDL
<=Less than or equal operator. Evaluates both SQL expressions and returns 1 if the left value is less than or equal to the right value and 0 if it is not, or NULL if either expression is NULL. If the expressions return different data types, (for instance, a number and a string), performs type conversion.
When used in row comparisons these two queries return the same results:
This page is licensed: GPLv2, originally from
Bitemporal tables are tables that use versioning both at the system and application-time period levels.
To create a bitemporal table, use:
CREATE TABLE test.t3 (
date_1 DATE,
date_2 DATE,
row_start TIMESTAMP(6) AS ROW START INVISIBLE,
row_end TIMESTAMP(6) AS ROW END INVISIBLE,
PERIOD FOR application_time(date_1, date_2),
PERIOD FOR system_time(row_start, row_end))
WITH SYSTEM VERSIONING;Note that, while system_time here is also a time period, it cannot be used in DELETE FOR PORTION or UPDATE FOR PORTION statements:
DELETE FROM test.t3
FOR PORTION OF system_time
FROM '2000-01-01' TO '2018-01-01';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds
to your MariaDB server version for the right syntax to use near
'of system_time from '2000-01-01' to '2018-01-01'' at line 1This page is licensed: CC BY-SA / Gnu FDL
MariaDB Vector has integrations in several frameworks.
LangChain, MariaDB Vector Store - Python
- Node.js
- Java
- Python
- Python
- Java
- benchmarking for vector databases
- Agent to agent, Python
- private LLM, vector search and text2sql, see , Python
- Workflow, not accepting external integrations anymore, Python
- machine learning (not GenAI), Python
For further alternatives, see .
This page is licensed: CC BY-SA / Gnu FDL
Some identifiers map to a file name on the filesystem. Databases each have their own directory, while, depending on the , table names and index names may map to a file name.
Not all characters that are allowed in table names can be used in file names. Every filesystem has its own rules of what characters can be used in file names. To let the user create tables using all characters allowed in the SQL Standard and to not depend on whatever particular filesystem a particular database resides, MariaDB encodes "potentially unsafe" characters in the table name to derive the corresponding file name.
This is implemented using a special character set. MariaDB converts a table name to the "filename" character set to get the file name for this table. And it converts the file name from the "filename" character set to, for example, utf8 to get the table name for this file name.
The conversion rules are as follows: if the identifier is made up only of basic Latin numbers, letters and/or the underscore character, the encoding matches the name (see however ). Otherwise they are encoded according to the following table:
GIS stands for .
MySQL operates on spatial data based on the OpenGIS standards, particularly the (Simple feature access, SQL option).
Initial support was based on version 05-134 of the standard. MariaDB implements a subset of the 'SQL with Geometry Types' environment proposed by the OGC. And the SQL environment was extended with a set of geometry types.
MariaDB supports spatial extensions to operate on spatial features. These features are available for , , , NDB, and tables.
For spatial columns, Aria and MyISAM supports both and non-SPATIAL indexes. Other storage engines support non-SPATIAL indexes.
We aim at meeting the OpenGIS requirements. One thing missed in previous MariaDB versions is that the functions which check spatial relations didn't consider the actual shape of an object, instead they operate only on their bounding rectangles. These legacy functions have been left as they are and new, properly-working functions are named with an 'ST_' prefix, in accordance with the latest OpenGIS requirements. Also, operations over geometry features were added.
Understand operator precedence in MariaDB Server SQL. This section details the order in which operators are evaluated within expressions, crucial for writing accurate and predictable queries.
The precedence is the order in which the SQL operators are evaluated.
The following list shows the SQL operator precedence. Operators that appear first in the list have a higher precedence. Operators which are listed together have the same precedence.
,
SELECT * FROM users;
# This is a comment
SELECT * FROM users; -- This is a commentSELECT * FROM users; /* This is a
multi-line
comment *//*! MySQL or MariaDB-specific code *//*!##### MySQL or MariaDB-specific code *//*!50100 MySQL and MariaDB 5.1.0 (and above) code goes here. *//*M! MariaDB-specific code */
/*M!###### MariaDB-specific code *//*!50701 MariaDB-10.x ignores MySQL-5.7 specific code *//*M!50701 MariaDB-10.x does not ignore this */SELECT 2 /* +1 */;
SELECT 1 /*! +1 */;
SELECT 1 /*!50101 +1 */;
SELECT 2 /*M! +1 */;
SELECT 2 /*M!50301 +1 */;/*M!100100 select 1 ; */
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1/*M!100100 select 1 */;
+---+
| 1 |
+---+
| 1 |
+---+DROP [TEMPORARY] SEQUENCE [IF EXISTS] [/*COMMENT TO SAVE*/]
sequence_name [, sequence_name] ...IS NULLSELECT 1 IS NULL, 0 IS NULL, NULL IS NULL;
+-----------+-----------+--------------+
| 1 IS NULL | 0 IS NULL | NULL IS NULL |
+-----------+-----------+--------------+
| 0 | 0 | 1 |
+-----------+-----------+--------------+SET @@sql_auto_is_null=1;
CREATE TABLE t1 (auto_increment_column INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1 WHERE auto_increment_column IS NULL;
+-----------------------+
| auto_increment_column |
+-----------------------+
| 1 |
+-----------------------+OR, ||SELECT 2 NOT IN (0,3,5,7);
+--------------------+
| 2 NOT IN (0,3,5,7) |
+--------------------+
| 1 |
+--------------------+NULL. If the expressions return different data types (for example, a number and a string), a type conversion is performed.When used in row comparisons these two queries are synonymous and return the same results:
To perform a NULL-safe comparison, use the <=> operator.
= can also be used as an assignment operator.
This page is licensed: GPLv2, originally from fill_help_tables.sql
- (unary minus), bitwise not (unary bit inversion)
|| (string concatenation)
^ (bitwise XOR)
& (bitwise AND)
| (bitwise OR)
Functions precedence is always higher than operators precedence.
If the HIGH_NOT_PRECEDENCE SQL_MODE is set, NOT has the same precedence as !.
The || operator's precedence, as well as its meaning, depends on the PIPES_AS_CONCAT SQL_MODE flag: if it is on, || can be used to concatenate strings (like the CONCAT() function) and has a higher precedence.
The = operator's precedence depends on the context - it is higher when = is used as a comparison operator.
Parentheses can be used to modify the operators precedence in an expression.
The AND, OR, && and || operators support short-circuit evaluation. This means that, in some cases, the expression on the right of those operators is not evaluated, because its result cannot affect the result. In the following cases, short-circuit evaluation is used and x() is not evaluated:
FALSE AND x()
FALSE && x()
TRUE OR x()
TRUE || x()
NULL BETWEEN x() AND x()
Note however that the short-circuit evaluation does not apply to NULL AND x(). Also, BETWEEN's right operands are not evaluated if the left operand is NULL, but in all other cases all the operands are evaluated.
This is a speed optimization. Also, since functions can have side-effects, this behavior can be used to choose whether execute them or not using a concise syntax:
This page is licensed: CC BY-SA / Gnu FDL
N0 < N11N1 <= N0 < N22N2 <= N0 < N3-1N0NULLN1 <= N2 <= N3 <= ... <= NnThis page is licensed: GPLv2, originally from fill_help_tables.sql
INTERVAL(N0,N1,N2,N3,...)SET @str = CAST(123 AS CHAR(5));SELECT @x IS NULL;
+------------+
| @x IS NULL |
+------------+
| 1 |
+------------+@sql = 'DELETE FROM my_table WHERE c>1;';
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;SET @var = 0;
SELECT a, b, c, (@var:=@var+1) AS counter FROM my_table;SET @v1 = 0;
SET @v2 = 'abc';
SET @v3 = CAST(123 AS CHAR(5));
SHOW USER_VARIABLES;
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| v3 | 123 |
| v2 | abc |
| v1 | 0 |
+---------------+-------+
SELECT * FROM information_schema.USER_VARIABLES ORDER BY VARIABLE_NAME;
+---------------+----------------+---------------+--------------------+
| VARIABLE_NAME | VARIABLE_VALUE | VARIABLE_TYPE | CHARACTER_SET_NAME |
+---------------+----------------+---------------+--------------------+
| v1 | 0 | INT | latin1 |
| v2 | abc | VARCHAR | utf8 |
| v3 | 123 | VARCHAR | utf8 |
+---------------+----------------+---------------+--------------------+
FLUSH USER_VARIABLES;
SELECT * FROM information_schema.USER_VARIABLES ORDER BY VARIABLE_NAME;
Empty set (0.000 sec)SELECT 'wefwf' NOT IN ('wee','wefwf','weg');
+--------------------------------------+
| 'wefwf' NOT IN ('wee','wefwf','weg') |
+--------------------------------------+
| 0 |
+--------------------------------------+SELECT 1 NOT IN ('1', '2', '3');
+--------------------------+
| 1 NOT IN ('1', '2', '3') |
+--------------------------+
| 0 |
+--------------------------+SELECT NULL NOT IN (1, 2, 3);
+-----------------------+
| NULL NOT IN (1, 2, 3) |
+-----------------------+
| NULL |
+-----------------------+
SELECT 1 NOT IN (1, 2, NULL);
+-----------------------+
| 1 NOT IN (1, 2, NULL) |
+-----------------------+
| 0 |
+-----------------------+
SELECT 5 NOT IN (1, 2, NULL);
+-----------------------+
| 5 NOT IN (1, 2, NULL) |
+-----------------------+
| NULL |
+-----------------------+SELECT (t1.a, t1.b) <= (t2.x, t2.y)
FROM t1 INNER JOIN t2;
SELECT (t1.a < t2.x) OR ((t1.a = t2.x) AND (t1.b <= t2.y))
FROM t1 INNER JOIN t2;SELECT 0.1 <= 2;
+----------+
| 0.1 <= 2 |
+----------+
| 1 |
+----------+SELECT 'a'<='A';
+----------+
| 'a'<='A' |
+----------+
| 1 |
+----------+left_expr = right_exprSELECT (t1.a, t1.b) = (t2.x, t2.y) FROM t1 INNER JOIN t2;
SELECT (t1.a = t2.x) AND (t1.b = t2.y) FROM t1 INNER JOIN t2;SELECT 1 = 0;
+-------+
| 1 = 0 |
+-------+
| 0 |
+-------+
SELECT '0' = 0;
+---------+
| '0' = 0 |
+---------+
| 1 |
+---------+
SELECT '0.0' = 0;
+-----------+
| '0.0' = 0 |
+-----------+
| 1 |
+-----------+
SELECT '0.01' = 0;
+------------+
| '0.01' = 0 |
+------------+
| 0 |
+------------+
SELECT '.01' = 0.01;
+--------------+
| '.01' = 0.01 |
+--------------+
| 1 |
+--------------+
SELECT (5 * 2) = CONCAT('1', '0');
+----------------------------+
| (5 * 2) = CONCAT('1', '0') |
+----------------------------+
| 1 |
+----------------------------+
SELECT 1 = NULL;
+----------+
| 1 = NULL |
+----------+
| NULL |
+----------+
SELECT NULL = NULL;
+-------------+
| NULL = NULL |
+-------------+
| NULL |
+-------------+SELECT some_function() OR log_error();SELECT INTERVAL(22, 24, 26, 28);+--------------------------+
| INTERVAL(22, 24, 26, 28) |
+--------------------------+
| 0 |
+--------------------------+SELECT INTERVAL(22, 22, 22, 22, 23);+------------------------------+
| INTERVAL(22, 22, 22, 22, 23) |
+------------------------------+
| 3 |
+------------------------------+SELECT INTERVAL(25, 24, 26, 28);+--------------------------+
| interval(25, 24, 26, 28) |
+--------------------------+
| 1 |
+--------------------------+SELECT INTERVAL(27, 24, 26, 28);+--------------------------+
| interval(27, 24, 26, 28) |
+--------------------------+
| 2 |
+--------------------------+SELECT INTERVAL(27, 25, 26, 27);+--------------------------+
| interval(27, 25, 26, 27) |
+--------------------------+
| 3 |
+--------------------------+SELECT INTERVAL(23, 1, 15, 17, 30, 44, 200);+--------------------------------------+
| INTERVAL(23, 1, 15, 17, 30, 44, 200) |
+--------------------------------------+
| 3 |
+--------------------------------------+SELECT INTERVAL(10, 1, 10, 100, 1000);+--------------------------------+
| INTERVAL(10, 1, 10, 100, 1000) |
+--------------------------------+
| 2 |
+--------------------------------+SELECT INTERVAL(22, 23, 30, 44, 200);+-------------------------------+
| INTERVAL(22, 23, 30, 44, 200) |
+-------------------------------+
| 0 |
+-------------------------------+SELECT INTERVAL(10, 2, NULL);+-----------------------+
| INTERVAL(10, 2, NULL) |
+-----------------------+
| 2 |
+-----------------------+Firebase Studio template for MariaDB Vector - visit link to vote for suggestion
LangGraph - Agentic workflow, Python
MindSQL - Text-to-SQL RAG Library simplifying database interactions, Python
Open WebUI - AI Interface, Python & Javascript
Vanna AI - Vector search and text2sql, Python
00C0..017F
[@][0..4][g..z]
5*20= 100
97
3
Latin-1 Supplement + Latin Extended-A
0370..03FF
[@][5..9][g..z]
5*20= 100
88
12
Greek and Coptic
0400..052F
[@][g..z][0..6]
20*7= 140
137
3
Code Range values are UCS-2.
All of this encoding happens transparently at the filesystem level with one exception.
Find the file name for a table with a non-Latin1 name:
Find the table name for a file name:
This page is licensed: CC BY-SA / Gnu FDL
Spatial operators produce new geometries.
union of A and B
intersection of A and B
symdifference, notintersecting parts of A and B
returns the shape of the area that lies in 'radius' distance from the shape A.
Predicates return a boolean result of the relationship.
if A and B have an intersection
if A and B cross
if A and B are equal
if A lies within B
if B lies within A
if A and B have no intersection
This page is licensed: CC BY-SA / Gnu FDL
Generate next value for a SEQUENCE.
You can greatly speed up NEXT VALUE by creating the sequence with the CACHE option. If not, every NEXT VALUE usage will cause changes in the stored SEQUENCE table.
When using NEXT VALUE the value will be reserved at once and will not be reused, except if the SEQUENCE was created with CYCLE. This means that when you are using SEQUENCEs you have to expect gaps in the generated sequence numbers.
If one updates the SEQUENCE with or , NEXT VALUE FOR will notice this and start from the next requested value.
will close the sequence and the next sequence number generated will be according to what's stored in the SEQUENCE object. In effect, this will discard the cached values.
A server restart (or closing the current connection) also causes a drop of all cached values. The cached sequence numbers are reserved only for the current connection.
NEXT VALUE requires the INSERT .
You can also use NEXT VALUE FOR sequence for column DEFAULT.
Once the sequence is complete, unless the sequence has been created with the CYCLE attribute (not the default), calling the function will result in Error 4084: Sequence has run out.
. Set next value for the sequence.
This page is licensed: CC BY-SA / Gnu FDL
NULLThe function is useful when substituting a default value for null values when displaying data.
See also NULL Values in MariaDB.
When two arguments are given, COALESCE() is the same as IFNULL():
Hex type confusion:
The reason for the differing results above is that when 0x31 is inserted directly to the column, it's treated as a number (see Hexadecimal Literals), while when 0x31 is passed to COALESCE(), it's treated as a string, because:
HEX values have a string data type by default.
COALESCE() has the same data type as the argument.
Substituting zero for NULL (in this case when the aggregate function returns NULL after finding no rows):
This page is licensed: GPLv2, originally from fill_help_tables.sql
Dividing by zero returns NULL. If the default ERROR_ON_DIVISION_BY_ZERO SQL_MODE is used, a division by zero also produces a warning.
Changing div_precision_increment for the session from the default of four to six:
This page is licensed: GPLv2, originally from fill_help_tables.sql
Databases, tables, indexes, columns, aliases, views, stored routines, triggers, events, variables, partitions, tablespaces, savepoints, labels, users, roles, are collectively known as identifiers, and have certain rules for naming.
Identifiers may be quoted using the backtick character (`). Quoting is optional for identifiers that don't contain special characters, or for identifiers that are not reserved words. If the ANSI_QUOTES SQL_MODE flag is set, double quotes (") can also be used to quote identifiers. If the flag is set, square brackets ([ and ]) can be used for quoting.
Even when using reserved words as names, fully qualified names do not need to be quoted. For example, test.select has only one possible meaning, so it is correctly parsed even without quotes.
The following characters are valid, and allow identifiers to be unquoted:
ASCII: [0-9,a-z,A-Z$_] (numerals 0-9, basic Latin letters, both lowercase and uppercase, dollar sign, underscore)
Extended: U+0080 .. U+FFFF
The following characters are valid, but identifiers using them must be quoted:
ASCII: U+0001 .. U+007F (full Unicode Basic Multilingual Plane (BMP) except for U+0000)
Extended: U+0080 .. U+FFFF
Identifier quotes can themselves be used as part of an identifier, as long as they are quoted.
There are a number of other rules for identifiers:
Identifiers are stored as Unicode (UTF-8)
Identifiers may or may not be case-sensitive. See .
Database, table and column names can't end with space characters
Identifier names may begin with a numeral, but can't only contain numerals unless quoted.
The regular quote character is the backtick character - ```, but if the ANSI_QUOTES option is specified, a regular double quote - " may be used as well.
The backtick character can be used as part of an identifier. In that case the identifier needs to be quoted. The quote character can be the backtick, but in that case, the backtick in the name must be escaped with another backtick.
Databases, tables, columns, indexes, constraints, stored routines, triggers, events, views, tablespaces, servers and log file groups have a maximum length of 64 characters.
Compound statement have a maximum length of 16 characters.
Aliases have a maximum length of 256 characters, except for column aliases in statements, which are checked against the maximum column length of 64 characters (not the maximum alias length of 256 characters).
Users have a maximum length of 80 characters.
MariaDB allows the column name to be used on its own if the reference will be unambiguous, or the table name to be used with the column name, or all three of the database, table and column names. A period is used to separate the identifiers, and the period can be surrounded by spaces.
Using the period to separate identifiers:
The period can be separated by spaces:
Resolving ambiguity:
Creating a table with characters that require quoting:
Using double quotes as a quoting character:
Using an identifier quote as part of an identifier name:
Creating the table named * (Unicode number: U+002A) requires quoting.
Floating point ambiguity:
This page is licensed: CC BY-SA / Gnu FDL
The HandlerSocket plugin has the following options.
See also the Full list of MariaDB options, system and status variables.
Add the options to the [mysqld] section of your my.cnf file.
handlersocket_accept_balanceDescription: When set to a value other than zero ('0'), handlersocket will try to balance accepted connections among threads. Default is 0 , but if you use persistent connections (for example if you use client-side connection pooling), a non-zero value is recommended.
Command line: --handlersocket-accept-balance="value"
Scope: Global
Dynamic: No
Type: number
Range: 0 to 10000
Default Value: 0
handlersocket_addressDescription: Specify the IP address to bind to.
Command line: --handlersocket-address="value"
Scope: Global
Dynamic: No
handlersocket_backlogDescription: Specify the listen backlog length.
Command line: --handlersocket-backlog="value"
Scope: Global
Dynamic: No
handlersocket_epollDescription: Specify whether to use epoll for I/O multiplexing.
Command line: --handlersocket-epoll="value"
Scope: Global
Dynamic: No
handlersocket_plain_secretDescription: When set, enables plain-text authentication for the listener for read requests, with the value of the option specifying the secret authentication key.
Command line: --handlersocket-plain-secret="value"
Dynamic: No
Type: string
handlersocket_plain_secret_wrDescription: When set, enables plain-text authentication for the listener for write requests, with the value of the option specifying the secret authentication key.
Command line: --handlersocket-plain-secret-wr="value"
Dynamic: No
Type: string
handlersocket_portDescription: Specify the port to bind to for reads. An empty value disables the listener.
Command line: --handlersocket-port="value"
Scope: Global
Dynamic: No
handlersocket_port_wrDescription: Specify the port to bind to for writes. An empty value disables the listener.
Command line: --handlersocket-port-wr="value"
Scope: Global
Dynamic: No
handlersocket_rcvbufDescription: Specify the maximum socket receive buffer (in bytes). If '0' then the system default is used.
Command line: --handlersocket-rcvbuf="value"
Scope: Global
Dynamic: No
handlersocket_readsizeDescription: Specify the minimum length of the request buffer. Larger values consume available memory but can make handlersocket faster for large requests.
Command line: --handlersocket-readsize="value"
Scope: Global
Dynamic: No
handlersocket_sndbufDescription: Specify the maximum socket send buffer (in bytes). If '0' then the system default is used.
Command line: --handlersocket-sndbuf="value"
Scope: Global
Dynamic: No
handlersocket_threadsDescription: Specify the number of worker threads for reads. Recommended value = number of CPU cores * 2.
Command line: --handlersocket-threads="value"
Scope: Global
Dynamic: No
handlersocket_threads_wrDescription: Specify the number of worker threads for writes. Recommended value = 1.
Command line: --handlersocket-threads-wr="value"
Scope: Global
Dynamic: No
handlersocket_timeoutDescription: Specify the socket timeout in seconds.
Command line: --handlersocket-timeout="value"
Scope: Global
Dynamic: No
handlersocket_verboseDescription: Specify the logging verbosity.
Command line: --handlersocket-verbose="value"
Scope: Global
Dynamic: No
handlersocket_wrlock_timeoutDescription: The write lock timeout in seconds. When acting on write requests, handlersocket locks an advisory lock named 'handlersocket_wr' and this option sets the timeout for it.
Command line: --handlersocket-wrlock-timeout="value"
Scope: Global
Dynamic: No
This page is licensed: CC BY-SA / Gnu FDL
Strings are sequences of characters and enclosed with quotes.
The syntax is:
For example:
Strings can either be enclosed in single quotes or in double quotes (the same character must be used to both open and close the string).
The ANSI SQL-standard does not permit double quotes for enclosing strings, and although MariaDB does by default, if the MariaDB server has enabled the ANSI_QUOTES_SQL SQL_MODE, double quotes will be treated as being used for identifiers instead of strings.
Strings that are next to each other are automatically concatenated. The following are equivalent:
The \ (backslash character) is used to escape characters (unless the SQL_MODE hasn't been set to NO_BACKSLASH_ESCAPES):
That is not a valid string because of the single quote in the middle of the string, which is treated as if it closes the string, but is actually meant as part of the string, an apostrophe. The backslash character helps in situations like this:
That is now a valid string, and if displayed, will appear without the backslash.
Another way to escape the quoting character is repeating it twice:
There are other escape sequences:
Escaping the % and _ characters can be necessary when using the operator, which treats them as special characters.
The ASCII 26 character (\Z) needs to be escaped when included in a batch file which needs to be executed in Windows. The reason is that ASCII 26, in Windows, is the end of file (EOF).
Backslash (\), if not used as an escape character, must always be escaped. When followed by a character that is not in the above table, backslashes will simply be ignored.
This page is licensed: CC BY-SA / Gnu FDL
This page documents system variables related to Vectors.
See Server System Variables for instructions on setting them.
Also see the Full list of MariaDB options, system and status variables.
mhnsw_default_distanceDescription: Specifies the default distance metric for MHNSW vector indexing. This is used when the DISTANCE option is not explicitly defined during index creation.
Command line: --mhnsw-default-distance=val
Scope: Global, Session
Dynamic: Yes
Data Type: enum
Default Value: euclidean
Valid Values:
euclidean Calculates straight-line distance between vectors. Best for spatial data, images, etc, when absolute magnitude matters.
cosine Measures directional similarity between vectors. Ideal for text embeddings, semantic search, and when vector magnitude is less important.
Introduced: MariaDB 11.7.1
mhnsw_default_mDescription: Defines the default value for the M parameter in MHNSW vector indexing. The M parameter controls the number of connections per layer in the graph structure, influencing the balance between search performance and index size.
Larger M → Better search accuracy, but larger index size and slower updates and searches.
Smaller M → Faster updates and searches, smaller index, but potentially less accurate search.
mhnsw_ef_searchDescription: Defines the minimal number of result candidates to look for in the vector index for ORDER BY ... LIMIT N queries. The search will never search for less rows than that, even if LIMIT is smaller. This notably improves the search quality at low LIMIT values, at the expense of search time. Higher values may increase search quality but will also impact query performance.
Command line: --mhnsw-ef-search=#
Scope: Global, Session
mhnsw_max_cache_sizeDescription: Upper limit for one MHNSW vector index cache. This limits the amount of memory that can be used for caching the index, ensuring efficient memory utilization.
Command line: --mhnsw-max-cache-size=#
Scope: Global
Dynamic: Yes
This page is licensed: CC BY-SA / Gnu FDL
Create new roles to simplify privilege management. Learn how to define a role that can be assigned to multiple users or other roles.
The CREATE ROLE statement creates one or more MariaDB . To use it, you must have the global privilege or the privilege for the mysql database. For each account, CREATE ROLE creates a new row in the table that has no privileges, and with the corresponding is_role field set to Y. It also creates a record in the table.
If any of the specified roles already exist, ERROR 1396 (HY000) results. If an error occurs, CREATE ROLE will still create the roles that do not result in an error. The maximum length for a role is 128 characters. Role names can be quoted, as explained in the page. Only one error is produced for all roles which have not been created:
Failed CREATE or DROP operations, for both users and roles, produce the same error code.
PUBLIC and NONE are reserved, and cannot be used as role names. NONE is used to and PUBLIC has a special use in other systems, such as Oracle, so is reserved for compatibility purposes.
For valid identifiers to use as role names, see .
The optional WITH ADMIN clause determines whether the current user, the current role or another user or role has use of the newly created role. If the clause is omitted, WITH ADMIN CURRENT_USER is treated as the default, which means that the current user will be able to this role to users.
If the optional OR REPLACE clause is used, it acts as a shortcut for:
When the IF NOT EXISTS clause is used, MariaDB will return a warning instead of an error if the specified role already exists. Cannot be used together with the OR REPLACE clause.
Granting the role to another user. Only user lorinda@localhost has permission to grant the developer role:
The OR REPLACE and IF NOT EXISTS clauses. The journalist role already exists:
This page is licensed: CC BY-SA / Gnu FDL
If expr is greater than or equal to min and expr is less than or equal to max, BETWEEN returns 1, otherwise it returns 0. This is equivalent to the expression (min <= expr AND expr <= max) if all the arguments are of the same type. Otherwise type conversion takes place according to the rules described at , but applied to all the three arguments.
NULL:
DATE, DATETIME and TIMESTAMP examples. Omitting the time component compares against 00:00, so later times on the same date are not returned:
The following query doesn't show countries whose name starts with 'D':
When using WHERE name BETWEEN 'B' AND 'D', the condition includes all names that start with 'B' because 'B' is the lower bound and is inclusive. However, names starting with 'D' are excluded because the upper bound 'D' is treated as a string, and the comparison stops at the character level. For example, a name like 'D' is included if it matches exactly, but a name like 'Denmark' is not included because 'Denmark' is lexicographically greater than 'D'.
This page is licensed: GPLv2, originally from
CREATE TABLE embeddings (
doc_id BIGINT UNSIGNED PRIMARY KEY,
embedding VECTOR(1536)
);CREATE TABLE embeddings (
doc_id BIGINT UNSIGNED PRIMARY KEY,
embedding VECTOR(1536) NOT NULL,
VECTOR INDEX (embedding)
);CREATE TABLE embeddings (
doc_id BIGINT UNSIGNED PRIMARY KEY,
embedding VECTOR(1536) NOT NULL,
VECTOR INDEX (embedding) M=8 DISTANCE=cosine
);SELECT CAST(CONVERT("this_is_таблица" USING filename) AS BINARY);
+------------------------------------------------------------------+
| CAST(CONVERT("this_is_таблица" USING filename) AS BINARY) |
+------------------------------------------------------------------+
| this_is_@y0@g0@h0@r0@o0@i1@g0 |
+------------------------------------------------------------------+SELECT CONVERT(_filename "this_is_@y0@g0@h0@r0@o0@i1@g0" USING utf8);
+---------------------------------------------------------------+
| CONVERT(_filename "this_is_@y0@g0@h0@r0@o0@i1@g0" USING utf8) |
+---------------------------------------------------------------+
| this_is_таблица |
+---------------------------------------------------------------+NEXT VALUE FOR sequenceNEXTVAL(sequence_name)sequence_name.nextvalCREATE OR REPLACE SEQUENCE s MAXVALUE=2;
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 1 |
+------------+
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 2 |
+------------+
SELECT NEXTVAL(s);
ERROR 4084 (HY000): Sequence 'test.s' has run out
ALTER SEQUENCE s MAXVALUE=2 CYCLE;
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 1 |
+------------+COALESCE(value,...)SELECT COALESCE(NULL,1);
+------------------+
| COALESCE(NULL,1) |
+------------------+
| 1 |
+------------------+SELECT COALESCE(NULL,NULL,NULL);
+--------------------------+
| COALESCE(NULL,NULL,NULL) |
+--------------------------+
| NULL |
+--------------------------+SET @a=NULL, @b=1;
SELECT COALESCE(@a, @b), IFNULL(@a, @b);
+------------------+----------------+
| COALESCE(@a, @b) | IFNULL(@a, @b) |
+------------------+----------------+
| 1 | 1 |
+------------------+----------------+CREATE TABLE t1 (a INT, b VARCHAR(10));
INSERT INTO t1 VALUES (0x31, 0x61),(COALESCE(0x31), COALESCE(0x61));
SELECT * FROM t1;
+------+------+
| a | b |
+------+------+
| 49 | a |
| 1 | a |
+------+------+SELECT SUM(score) FROM student;
+------------+
| SUM(score) |
+------------+
| NULL |
+------------+
SELECT COALESCE(SUM(score),0) FROM student;
+------------------------+
| COALESCE(SUM(score),0) |
+------------------------+
| 0 |
+------------------------+/SELECT 4/5;
+--------+
| 4/5 |
+--------+
| 0.8000 |
+--------+
SELECT 300/(2-2);
+-----------+
| 300/(2-2) |
+-----------+
| NULL |
+-----------+
SELECT 300/7;
+---------+
| 300/7 |
+---------+
| 42.8571 |
+---------+SET div_precision_increment = 6;
SELECT 300/7;
+-----------+
| 300/7 |
+-----------+
| 42.857143 |
+-----------+
SELECT 300/7;
+-----------+
| 300/7 |
+-----------+
| 42.857143 |
+-----------+SELECT 1 || 1;
+--------+
| 1 || 1 |
+--------+
| 1 |
+--------+
SELECT 1 || 0;
+--------+
| 1 || 0 |
+--------+
| 1 |
+--------+
SELECT 0 || 0;
+--------+
| 0 || 0 |
+--------+
| 0 |
+--------+
SELECT 0 || NULL;
+-----------+
| 0 || NULL |
+-----------+
| NULL |
+-----------+
SELECT 1 || NULL;
+-----------+
| 1 || NULL |
+-----------+
| 1 |
+-----------+SELECT 0 || NULL;
+-----------+
| 0 || NULL |
+-----------+
| 0 |
+-----------+[_charset_name]'string' [COLLATE collation_name]'The MariaDB Foundation'
_utf8 'Foundation' COLLATE utf8_unicode_ci;'The ' 'MariaDB ' 'Foundation''The MariaDB Foundation''MariaDB's new features''MariaDB\'s new features'CREATE [OR REPLACE] ROLE [IF NOT EXISTS] role
[WITH ADMIN
{CURRENT_USER | CURRENT_ROLE | user | role}]expr BETWEEN min AND maxCyrillic + Cyrillic Supplement
0530..058F
[@][g..z][7..8]
20*2= 40
38
2
Armenian
2160..217F
[@][g..z][9]
20*1= 20
16
4
Number Forms
0180..02AF
[@][g..z][a..k]
20*11=220
203
17
Latin Extended-B + IPA Extensions
1E00..1EFF
[@][g..z][l..r]
20*7= 140
136
4
Latin Extended Additional
1F00..1FFF
[@][g..z][s..z]
20*8= 160
144
16
Greek Extended
.... ....
[@][a..f][g..z]
6*20= 120
0
120
RESERVED
24B6..24E9
[@][@][a..z]
26
26
0
Enclosed Alphanumerics
FF21..FF5A
[@][a..z][@]
26
26
0
Halfwidth and Fullwidth forms
if A touches B
Type: IP Address
Default Value: Empty, previously 0.0.0.0
Type: number
Range: 5 to 1000000
Default Value: 32768
Type: number
Valid values:
Min: 0
Max: 1
Default Value: 1
Default Value: Empty
Default Value: Empty
Type: number
Default Value: Empty, previously 9998
Type: number
Default Value: Empty, previously 9999
Type: number
Range: 0 to 1677216
Default Value: 0
Type: number
Range: 0 to 1677216
Default Value: 0 (possibly 4096)
Type: number
Range: 0 to 1677216
Default Value: 0
Type: number
Range: 1 to 3000
Default Value: 16
Type: number
Range: 1 to 3000
Default Value: 1
Type: number
Range: 30 to 3600
Default Value: 300
Type: number
Valid values:
Min: 0
Max: 10000
Default Value: 10
Type: number
Range: 0 to 3600
Tab.
\Z
ASCII 26 (Control+Z). See note following the table.
\
Backslash (“\”).
%
“%” character. See note following the table.
_
A “_” character. See note following the table.
\0
ASCII NUL (0x00).
'
Single quote (“'”).
"
Double quote (“"”).
\b
Backspace.
Newline, or linefeed,.
Carriage return.
GEOMETRY
Note: For clarity, only one type is listed per table in the examples below, but a table row can contain multiple types.
This page is licensed: GPLv2, originally from fill_help_tables.sql
SELECT 'MariaDB\'s new features';
+------------------------+
| MariaDB's new features |
+------------------------+
| MariaDB's new features |
+------------------------+SELECT 'I''m here', """Double""";
+----------+----------+
| I'm here | "Double" |
+----------+----------+
| I'm here | "Double" |
+----------+----------+ERROR 1396 (HY000): Operation CREATE ROLE failed for 'a','b','c'DROP ROLE IF EXISTS name;
CREATE ROLE name ...;CREATE ROLE journalist;
CREATE ROLE developer WITH ADMIN lorinda@localhost;SELECT USER();+-------------------+
| USER() |
+-------------------+
| henning@localhost |
+-------------------+
...GRANT developer TO ian@localhost;Access denied for user 'henning'@'localhost'SELECT USER();+-------------------+
| USER() |
+-------------------+
| lorinda@localhost |
+-------------------+GRANT m_role TO ian@localhost;CREATE ROLE journalist;
ERROR 1396 (HY000): Operation CREATE ROLE failed for 'journalist'
CREATE OR REPLACE ROLE journalist;
Query OK, 0 rows affected (0.00 sec)
CREATE ROLE IF NOT EXISTS journalist;
Query OK, 0 rows affected, 1 warning (0.00 sec)SHOW WARNINGS;+-------+------+---------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------+
| Note | 1975 | Can't create role 'journalist'; it already exists |
+-------+------+---------------------------------------------------+SELECT 1 BETWEEN 2 AND 3;
+-------------------+
| 1 BETWEEN 2 AND 3 |
+-------------------+
| 0 |
+-------------------+SELECT 'b' BETWEEN 'a' AND 'c';
+-------------------------+
| 'b' BETWEEN 'a' AND 'c' |
+-------------------------+
| 1 |
+-------------------------+SELECT 2 BETWEEN 2 AND '3';
+---------------------+
| 2 BETWEEN 2 AND '3' |
+---------------------+
| 1 |
+---------------------+SELECT 2 BETWEEN 2 AND 'x-3';
+-----------------------+
| 2 BETWEEN 2 AND 'x-3' |
+-----------------------+
| 0 |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
Warning (Code 1292): Truncated incorrect DOUBLE value: 'x-3'SELECT 1 BETWEEN 1 AND NULL;
+----------------------+
| 1 BETWEEN 1 AND NULL |
+----------------------+
| NULL |
+----------------------+CREATE TABLE `x` (
a date ,
b datetime,
c timestamp
)
INSERT INTO x VALUES
('2018-11-11', '2018-11-11 05:15', '2018-11-11 05:15'),
('2018-11-12', '2018-11-12 05:15', '2018-11-12 05:15');
SELECT * FROM x WHERE a BETWEEN '2018-11-11' AND '2018-11-12';
+------------+---------------------+---------------------+
| a | b | c |
+------------+---------------------+---------------------+
| 2018-11-11 | 2018-11-11 05:15:00 | 2018-11-11 05:15:00 |
| 2018-11-12 | 2018-11-12 05:15:00 | 2018-11-12 05:15:00 |
+------------+---------------------+---------------------+
SELECT * FROM x WHERE b BETWEEN '2018-11-11' AND '2018-11-12';
+------------+---------------------+---------------------+
| a | b | c |
+------------+---------------------+---------------------+
| 2018-11-11 | 2018-11-11 05:15:00 | 2018-11-11 05:15:00 |
+------------+---------------------+---------------------+
SELECT * FROM x WHERE c BETWEEN '2018-11-11' AND '2018-11-12';
+------------+---------------------+---------------------+
| a | b | c |
+------------+---------------------+---------------------+
| 2018-11-11 | 2018-11-11 05:15:00 | 2018-11-11 05:15:00 |
+------------+---------------------+---------------------+SELECT name
FROM countries
WHERE name BETWEEN "B" AND "D"
ORDER BY name ASC;
+--------------------------------+
| name |
+--------------------------------+
| Bahamas |
| Bahrain |
| Bangladesh |
...
| Cuba |
| Cyprus |
| Czech Republic |
+--------------------------------+
41 rows in set (0.001 sec)CREATE TABLE object (shapeA POLYGON, shapeB LINESTRING);INSERT INTO geometry_example VALUES
(Point(0, 0)),
(ST_PolygonFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')),
(ST_LineFromText('LINESTRING(0 0, 1 1, 2 2)')),
(ST_MultiLineStringFromText(
'MULTILINESTRING((0 1, 0 2, 0 3),
(1 0, 2 0, 3 0))')),
(ST_MultiPointFromText('MULTIPOINT(0 0, 1 1, 0 1, 1 0)')),
(ST_MultiPolygonFromText(
'MULTIPOLYGON(((0 40, 0 20, 6 30, 12 20, 12 40, 0 40),
(15 40, 15 20, 25 20, 30 25, 30 35, 25 40, 15 40)))'));SELECT ST_AsWKT(g) FROM geometry_example;
+-----------------------------------------------------------------------------------------------+
| ST_AsWKT(g) |
+-----------------------------------------------------------------------------------------------+
| POINT(0 0) |
| POLYGON((0 0,0 1,1 1,1 0,0 0)) |
| LINESTRING(0 0,1 1,2 2) |
| MULTILINESTRING((0 1,0 2,0 3),(1 0,2 0,3 0)) |
| MULTIPOINT(0 0,1 1,0 1,1 0) |
| MULTIPOLYGON(((0 40,0 20,6 30,12 20,12 40,0 40),(15 40,15 20,25 20,30 25,30 35,25 40,15 40))) |
+-----------------------------------------------------------------------------------------------+CREATE TABLE gis_point (g POINT);
SHOW FIELDS FROM gis_point;
INSERT INTO gis_point VALUES
(PointFromText('POINT(10 10)')),
(PointFromText('POINT(20 10)')),
(PointFromText('POINT(20 20)')),
(PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));
<</sql>>
=== [[linestring|LINESTRING]]
<<code lang=sql inline=false wrap=true>>
CREATE TABLE gis_line (g LINESTRING);
SHOW FIELDS FROM gis_line;
INSERT INTO gis_line VALUES
(LineFromText('LINESTRING(0 0,0 10,10 0)')),
(LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),
(LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));CREATE TABLE gis_polygon (g POLYGON);
SHOW FIELDS FROM gis_polygon;
INSERT INTO gis_polygon VALUES
(PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),
(PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))')),
(PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0))))));CREATE TABLE gis_multi_point (g MULTIPOINT);
SHOW FIELDS FROM gis_multi_point;
INSERT INTO gis_multi_point VALUES
(MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),
(MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),
(MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));CREATE TABLE gis_multi_line (g MULTILINESTRING);
SHOW FIELDS FROM gis_multi_line;
INSERT INTO gis_multi_line VALUES
(MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))')),
(MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),
(MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));CREATE TABLE gis_multi_polygon (g MULTIPOLYGON);
SHOW FIELDS FROM gis_multi_polygon;
INSERT INTO gis_multi_polygon VALUES
(MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
(MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
(MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));CREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);
SHOW FIELDS FROM gis_geometrycollection;
INSERT INTO gis_geometrycollection VALUES
(GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')),
(GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))),
(GeomFromText('GeometryCollection()')),
(GeomFromText('GeometryCollection EMPTY'));CREATE TABLE gis_geometry (g GEOMETRY);
SHOW FIELDS FROM gis_geometry;
INSERT INTO gis_geometry SELECT * FROM gis_point;
INSERT INTO gis_geometry SELECT * FROM gis_line;
INSERT INTO gis_geometry SELECT * FROM gis_polygon;
INSERT INTO gis_geometry SELECT * FROM gis_multi_point;
INSERT INTO gis_geometry SELECT * FROM gis_multi_line;
INSERT INTO gis_geometry SELECT * FROM gis_multi_polygon;
INSERT INTO gis_geometry SELECT * FROM gis_geometrycollection;An identifier starting with a numeral, followed by an 'e', may be parsed as a floating point number, and needs to be quoted.
Identifiers are not permitted to contain the ASCII NUL character (U+0000) and supplementary characters (U+10000 and higher).
Names such as 5e6, 9e are not prohibited, but it's strongly recommended not to use them, as they could lead to ambiguity in certain contexts, being treated as a number or expression.
User variables cannot be used as part of an identifier, or as an identifier in an SQL statement.
Roles have a maximum length of 128 characters.
Multi-byte characters do not count extra towards the character limit.
Command line: --mhnsw-default-m=#
Scope: Global, Session
Dynamic: Yes
Data Type: int unsigned
Default Value: 6
Range: 3 to 200
Introduced: MariaDB 11.7.1
Data Type: int unsigned
Default Value: 20
Range: 1 to 10000
Introduced: MariaDB 11.7.1
Data Type: bigint unsigned
Default Value: 16777216 (16 MB)
Range: 1048576 to 18446744073709551615
Introduced: MariaDB 11.7.1
Gets the most recent value in the current connection generated from a sequence.
If the sequence has not yet been used by the connection, PREVIOUS VALUE FOR returns NULL (the same thing applies with a new connection which doesn't see a last value for an existing sequence).
If a SEQUENCE has been dropped and re-created then it's treated as a new SEQUENCE and PREVIOUS VALUE FOR will return NULL.
Returns NULL if the sequence is complete.
has no effect on PREVIOUS VALUE FOR.
Previous values for all used sequences are stored per connection until connection ends.
PREVIOUS VALUE FOR requires the .
Now try to start the new connection and check that the last value is still NULL, before updating the value in the new connection after the output of the new connection gets current value (110 in the example below). Note that first connection cannot see this change and the result of last value still remains the same (100 in the example above).
Returns NULL if the sequence has run out:
. Set next value for the sequence.
This page is licensed: CC BY-SA / Gnu FDL
ALTER SEQUENCE changes the parameters of an existing sequence generator. Any parameters not specifically set in the ALTER SEQUENCE command retain their prior settings.
ALTER SEQUENCE requires the ALTER privilege.
INCREMENT
1
Increment to use for values. May be negative.
MINVALUE
1 if INCREMENT > 0 and -9223372036854775807 if INCREMENT < 0
Minimum value for the sequence.
MAXVALUE
9223372036854775806 if INCREMENT > 0 and -1 if INCREMENT < 0
Max value for sequence.
START
MINVALUE if INCREMENT > 0 and MAX_VALUE if INCREMENT< 0
The optional clause RESTART [ WITH restart ] sets the next value for the sequence. This is equivalent to calling the SETVAL() function with the is_used argument as 0. The specified value will be returned by the next call of nextval. Using RESTART with no restart value is equivalent to supplying the start value that was recorded by CREATE SEQUENCE or last set by ALTER SEQUENCE START WITH.
ALTER SEQUENCE does not allow to change the sequence so that it's inconsistent:
To allow SEQUENCE objects to be backed up by old tools, like mariadb-dump, one can use SELECT to read the current state of a SEQUENCE object and use an INSERT to update the SEQUENCE object. INSERT is only allowed if all fields are specified:
ALTER SEQUENCE will instantly affect all future SEQUENCE operations. This is in contrast to some other databases where the changes requested by ALTER SEQUENCE will not be seen until the sequence cache has run out.
ALTER SEQUENCE will take a full table lock of the sequence object during its (brief) operation. This ensures that ALTER SEQUENCE is replicated correctly. If you only want to set the next sequence value to a higher value than current, then you should use SETVAL() instead, as this is not blocking.
If you want to change the storage engine or sequence comment, or rename the sequence, you can use ALTER TABLE for this.
. Set next value for the sequence.
This page is licensed: CC BY-SA / Gnu FDL
round argument.If the is_used argument is not given or is 1 or true, then the next used value will one after the given value. If is_used is 0 or false then the next generated value will be the given value.
If round is used then it will set the round value (or the internal cycle count, starting at zero) for the sequence. If round is not used, it's assumed to be 0.
next_value must be an integer literal.
For SEQUENCE tables defined with CYCLE (see CREATE SEQUENCE) one should use both next_value and round to define the next value. In this case the current sequence value is defined to be round, next_value.
The result returned by SETVAL() is next_value or NULL if the given next_value and round is smaller than the current value.
SETVAL() will not set the SEQUENCE value to a something that is less than its current value. This is needed to ensure that SETVAL() is replication-safe. If you want to set the SEQUENCE to a smaller number, use ALTER SEQUENCE.
If CYCLE is used, first round and then next_value are compared to see if the value is bigger than the current value.
Internally, in the MariaDB server, SETVAL() is used to inform replicas that a SEQUENCE has changed value. The replica may getSETVAL() statements out of order, but this is ok as only the biggest one will have an effect.
SETVAL requires the INSERT privilege.
SETVAL setting higher and lower values on a sequence with an increment of 10:
Example demonstrating round:
The following statement returns NULL, as the given next_value and round is smaller than the current value:
Increasing the round from zero to 1 allows next_value to be returned:
This page is licensed: CC BY-SA / Gnu FDL
The HANDLER statement provides direct access to table storage engine interfaces for key lookups and key or table scans. It is available for at least Aria, , and tables (and should work with most 'normal' storage engines, but not with system tables, or ).
HANDLER ... OPEN opens a table, allowing it to be accessible to subsequent HANDLER ... READ statements. The table can either be opened using an alias, or a table name. If opened with an alias, references to this table by further HANDLER statements must use this alias, and not the table name. If opened with a table name qualified by database name, further references to this table must use the unqualified table name. For example, if a table is opened with db1.t1, further references must use t1.
The table object is only closed when HANDLER ... CLOSE is called by the session, or the session closes, and is not shared by other sessions.
work with HANDLER READ, which gives a much higher performance (50% speedup) as there is no parsing and all data is transformed in binary (without conversions to text, as with the normal protocol).
The HANDLER command does not work with .
A key lookup is started with:
The values stands for the value of each of the key columns. For most key types, except for HASH keys in MEMORY storage engine, you can use a prefix subset of its columns.
If you are using LIMIT, then in case of >= or > then there is an implicit NEXT implied, while if you are using <= or < then there is an implicit PREV implied.
After the initial read, you can use the following to scan rows in key order:
Note that the row order is not defined for keys with duplicated values, and will vary from engine to engine.
You can scan a table in key order by doing this:
Alternatively, if the handler supports backwards key scans (which most do), you can use this:
You can scan a table in row order by doing this:
As this is a direct interface to the storage engine, some limitations may apply for what you can do and what happens if the table changes. Here are some of the common limitations.
HANDLER READ is not transaction-safe, consistent or atomic. It's okay for the storage engine to return rows that existed when you started the scan, but that were later deleted. This can happen as the storage engine may cache rows as part of the scan from a previous read.
You may also find rows committed since the scan originally started.
HANDLER ... READ also reads the data of .
HANDLER ... READ reads everything from , and so includes row_start and row_end fields, as well as all rows that have since been deleted or changed, including when history partitions are used.
If you do an , all your HANDLERs for that table are automatically closed.
If you do an ALTER TABLE for a table that is used by some other connection with HANDLER, the ALTER TABLE query waits for the HANDLER to be closed.
(ER_ILLEGAL_HA) Table storage engine for 't1' doesn't have this option
If you get this for HANDLER OPEN it means the storage engine doesn't support HANDLER calls.
If you get this for HANDLER READ , it means you are trying to use an incomplete
In the previous example, the HANDLER was opened with the t1 table name. Since HANDLERs use unqualified table names, trying to access another table with this same name, even though it's in another database, will result in ambiguity. An alias needs to be used to avoid the ambiguity, resulting in :
This page is licensed: GPLv2, originally from
MariaDB Vector is a feature that allows MariaDB Server to perform as a relational vector database. Vectors generated by an AI model can be stored and searched in MariaDB.
The initial implementation uses the modified HNSW algorithm for searching in the vector index (to solve the so-called Approximate Nearest Neighbor problem), and defaults to Euclidean distance. Concurrent reads/writes and all are supported.
MariaDB uses int16 for indexes, which gives 15 bits to store the value, rather than 10 bits for float16.
Vectors can be defined using VECTOR INDEX
CREATE TABLE t1 (i int);
INSERT INTO t1(i) VALUES (10);
SELECT i FROM t1;
+------+
| i |
+------+
| 10 |
+------+
SELECT t1.i FROM t1;
+------+
| i |
+------+
| 10 |
+------+
SELECT test.t1.i FROM t1;
+------+
| i |
+------+
| 10 |
+------+SELECT test . t1 . i FROM t1;
+------+
| i |
+------+
| 10 |
+------+CREATE TABLE t2 (i int);
SELECT i FROM t1 LEFT JOIN t2 ON t1.i=t2.i;
ERROR 1052 (23000): Column 'i' in field list is ambiguous
SELECT t1.i FROM t1 LEFT JOIN t2 ON t1.i=t2.i;
+------+
| i |
+------+
| 10 |
+------+CREATE TABLE 123% (i int);
ERROR 1064 (42000): You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for the right syntax
to use near '123% (i int)' at line 1
CREATE TABLE `123%` (i int);
Query OK, 0 rows affected (0.85 sec)
CREATE TABLE `TABLE` (i int);
Query OK, 0 rows affected (0.36 sec)CREATE TABLE "SELECT" (i int);
ERROR 1064 (42000): You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for the right syntax
to use near '"SELECT" (i int)' at line 1
SET sql_mode='ANSI_QUOTES';
Query OK, 0 rows affected (0.03 sec)
CREATE TABLE "SELECT" (i int);
Query OK, 0 rows affected (0.46 sec)SHOW VARIABLES LIKE 'sql_mode';
+---------------+-------------+
| Variable_name | Value |
+---------------+-------------+
| sql_mode | ANSI_QUOTES |
+---------------+-------------+
CREATE TABLE "fg`d" (i int);
Query OK, 0 rows affected (0.34 sec)CREATE TABLE `*` (a INT);CREATE TABLE 8984444cce5d (x INT);
Query OK, 0 rows affected (0.38 sec)
CREATE TABLE 8981e56cce5d (x INT);
ERROR 1064 (42000): You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for the right syntax
to use near '8981e56cce5d (x INT)' at line 1
CREATE TABLE `8981e56cce5d` (x INT);
Query OK, 0 rows affected (0.39 sec)PREVIOUS VALUE FOR sequence_nameLASTVAL(sequence_name)sequence_name.currvalCREATE SEQUENCE s START WITH 100 INCREMENT BY 10;
SELECT PREVIOUS VALUE FOR s;
+----------------------+
| PREVIOUS VALUE FOR s |
+----------------------+
| NULL |
+----------------------+
# The function works for sequences only, if the table is used an error is generated
SELECT PREVIOUS VALUE FOR t;
ERROR 4089 (42S02): 'test.t' is not a SEQUENCE
# Call the NEXT VALUE FOR s:
SELECT NEXT VALUE FOR s;
+------------------+
| NEXT VALUE FOR s |
+------------------+
| 100 |
+------------------+
SELECT PREVIOUS VALUE FOR s;
+----------------------+
| PREVIOUS VALUE FOR s |
+----------------------+
| 100 |
+----------------------+$ .mysql -uroot test -e"SELECT PREVIOUS VALUE FOR s; SELECT NEXT VALUE FOR s; SELECT PREVIOUS VALUE FOR s;"
+----------------------+
| PREVIOUS VALUE FOR s |
+----------------------+
| NULL |
+----------------------+
+------------------+
| NEXT VALUE FOR s |
+------------------+
| 110 |
+------------------+
+----------------------+
| PREVIOUS VALUE FOR s |
+----------------------+
| 110 |
+----------------------+CREATE OR REPLACE SEQUENCE s MAXVALUE=2;
SELECT NEXTVAL(s), LASTVAL(s);
+------------+------------+
| NEXTVAL(s) | LASTVAL(s) |
+------------+------------+
| 1 | 1 |
+------------+------------+
SELECT NEXTVAL(s), LASTVAL(s);
+------------+------------+
| NEXTVAL(s) | LASTVAL(s) |
+------------+------------+
| 2 | 2 |
+------------+------------+
SELECT NEXTVAL(s), LASTVAL(s);
ERROR 4084 (HY000): Sequence 'test.s' has run out
SELECT LASTVAL(s);
+------------+
| LASTVAL(s) |
+------------+
| NULL |
+------------+ALTER SEQUENCE [IF EXISTS] sequence_name
[ INCREMENT [ BY | = ] number ]
[ MINVALUE [=] number | NO MINVALUE | NOMINVALUE ]
[ MAXVALUE [=] number | NO MAXVALUE | NOMAXVALUE ]
[ START [ WITH | = ] number ] [ CACHE [=] number ] [ [ NO ] CYCLE ]
[ RESTART [[WITH | =] number]CREATE SEQUENCE s1;
ALTER SEQUENCE s1 MINVALUE 10;
ERROR 4061 (HY000): Sequence 'test.t1' values are conflicting
ALTER SEQUENCE s1 MINVALUE 10 RESTART 10;
ERROR 4061 (HY000): Sequence 'test.t1' values are conflicting
ALTER SEQUENCE s1 MINVALUE 10 START 10 RESTART 10;CREATE SEQUENCE s1;
INSERT INTO s1 VALUES(1000,10,2000,1005,1,1000,0,0);
SELECT * FROM s1;
+------------+-----------+-----------+-------+-----------+-------+-------+-------+
| next_value | min_value | max_value | start | increment | cache | cycle | round |
+------------+-----------+-----------+-------+-----------+-------+-------+-------+
| 1000 | 10 | 2000 | 1005 | 1 | 1000 | 0 | 0 |
+------------+-----------+-----------+-------+-----------+-------+-------+-------+
SHOW CREATE SEQUENCE s1;
+-------+--------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+--------------------------------------------------------------------------------------------------------------+
| s1 | CREATE SEQUENCE `s1` start with 1005 minvalue 10 maxvalue 2000 increment by 1 cache 1000 nocycle ENGINE=Aria |
+-------+--------------------------------------------------------------------------------------------------------------+SETVAL(sequence_name, next_value, [is_used, [round]])SELECT setval(foo, 42); -- Next nextval will return 43
SELECT setval(foo, 42, TRUE); -- Same as above
SELECT setval(foo, 42, FALSE); -- Next nextval will return 42SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 50 |
+------------+
SELECT SETVAL(s, 100);
+----------------+
| SETVAL(s, 100) |
+----------------+
| 100 |
+----------------+
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 110 |
+------------+
SELECT SETVAL(s, 50);
+---------------+
| SETVAL(s, 50) |
+---------------+
| NULL |
+---------------+
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 120 |
+------------+CREATE OR REPLACE SEQUENCE s1
START WITH 1
MINVALUE 1
MAXVALUE 99
INCREMENT BY 1
CACHE 20
CYCLE;
SELECT SETVAL(s1, 99, 1, 0);
+----------------------+
| SETVAL(s1, 99, 1, 0) |
+----------------------+
| 99 |
+----------------------+
SELECT NEXTVAL(s1);
+-------------+
| NEXTVAL(s1) |
+-------------+
| 1 |
+-------------+SELECT SETVAL(s1, 99, 1, 0);
+----------------------+
| SETVAL(s1, 99, 1, 0) |
+----------------------+
| NULL |
+----------------------+
SELECT NEXTVAL(s1);
+-------------+
| NEXTVAL(s1) |
+-------------+
| 2 |
+-------------+SELECT SETVAL(s1, 99, 1, 1);
+----------------------+
| SETVAL(s1, 99, 1, 1) |
+----------------------+
| 99 |
+----------------------+
SELECT NEXTVAL(s1);
+-------------+
| NEXTVAL(s1) |
+-------------+
| 1 |
+-------------+HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | >= | <= | < } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSEFirst value that the sequence will generate.
CACHE
1000
Number of values that should be cached. 0 if no CACHE. The underlying table will be updated first time a new sequence number is generated and each time the cache runs out.
CYCLE
0 (= NO CYCLE)
1 if the sequence should start again from MINVALUE
HASH keys, you must use all key parts when searching for a row.For HASH keys, you can't do a key scan of all values. You can only find all rows with the same key value.
While each HANDLER READ command is atomic, if you do a scan in many steps, some engines may give you error 1020 if the table changed between the commands. Please refer to the specific engine handler page if this happens.
HASHError 1020 (ER_CHECKREAD) Record has changed since last read in table '...'
This means that the table changed between two reads, and the handler can't handle this case for the given scan.
HANDLER tbl_name READ index_name { = | >= | <= | < } (value,value) [LIMIT...]HANDLER tbl_name READ index_name NEXT [ LIMIT ... ]
or
HANDLER tbl_name READ index_name PREV [ LIMIT ... ]HANDLER tbl_name READ index_name FIRST [ LIMIT ... ]
HANDLER tbl_name READ index_name NEXT [ LIMIT ... ]HANDLER tbl_name READ index_name LAST [ LIMIT ... ]
HANDLER tbl_name READ index_name PREV [ LIMIT ... ]HANDLER tbl_name READ FIRST [ LIMIT ... ]
HANDLER tbl_name READ NEXT [ LIMIT ... ]CREATE TABLE t1 (f1 INT);
INSERT INTO t1 VALUES (1),(2),(3);
HANDLER t1 OPEN;
HANDLER t1 READ NEXT;
+------+
| f1 |
+------+
| 1 |
+------+
HANDLER t1 READ NEXT;
+------+
| f1 |
+------+
| 2 |
+------+CREATE DATABASE db_new;
CREATE TABLE db_new.t1 (id INT);
INSERT INTO db_new.t1 VALUES (4),(5),(6);
HANDLER db_new.t1 OPEN;
ERROR 1066 (42000): Not unique table/alias: 't1'
HANDLER db_new.t1 OPEN AS db_new_t1;
HANDLER db_new_t1 READ NEXT LIMIT 3;
+------+
| id |
+------+
| 4 |
| 5 |
| 6 |
+------+The distance function used to build the vector index can be euclidean (the default) or cosine. An additional option, M, can be used to configure the vector index. Larger values mean slower SELECT and INSERT statements, larger index size and higher memory consumption but more accurate results. The valid range is from 3 to 200.
Vector columns store 32-bit IEEE 754 floating point numbers.
Alternatively, you can use VEC_FromText() function:
For vector indexes built with the euclidean function, VEC_DISTANCE_EUCLIDEAN can be used. It calculates a Euclidean (L2) distance between two points:
Most commonly, this kind of query is done with a limit, for example to return vectors that are closest to a given vector, such as from a user search query, image or a song fragment:
For vector indexes built with the cosine function, VEC_DISTANCE_COSINE can be used. It calculates a Cosine distance between two vectors:
The VEC_DISTANCE function is a generic function that behaves either as VEC_DISTANCE_EUCLIDEAN or VEC_DISTANCE_COSINE, depending on the underlying index type:
There are a number of system variables used for vectors. See Vector System Variables.
MariaDB Vector is integrated in several frameworks, see Vector Framework Integrations.
This page is licensed: CC BY-SA / Gnu FDL
CREATE TABLE v (
id INT PRIMARY KEY,
v VECTOR(5) NOT NULL,
VECTOR INDEX (v)
);CREATE TABLE embeddings (
doc_id BIGINT UNSIGNED PRIMARY KEY,
embedding VECTOR(1536) NOT NULL,
VECTOR INDEX (embedding) M=8 DISTANCE=cosine
);INSERT INTO v VALUES
(1, x'e360d63ebe554f3fcdbc523f4522193f5236083d'),
(2, x'f511303f72224a3fdd05fe3eb22a133ffae86a3f'),
(3,x'f09baa3ea172763f123def3e0c7fe53e288bf33e'),
(4,x'b97a523f2a193e3eb4f62e3f2d23583e9dd60d3f'),
(5,x'f7c5df3e984b2b3e65e59d3d7376db3eac63773e'),
(6,x'de01453ffa486d3f10aa4d3fdd66813c71cb163f'),
(7,x'76edfc3e4b57243f10f8423fb158713f020bda3e'),
(8,x'56926c3fdf098d3e2c8c5e3d1ad4953daa9d0b3e'),
(9,x'7b713f3e5258323f80d1113d673b2b3f66e3583f'),
(10,x'6ca1d43e9df91b3fe580da3e1c247d3f147cf33e');INSERT INTO v VALUES
(1,Vec_FromText('[0.418708,0.809902,0.823193,0.598179,0.0332549]')),
(2,Vec_FromText('[0.687774,0.789588,0.496138,0.57487,0.917617]')),
(3,Vec_FromText('[0.333221,0.962687,0.467263,0.448235,0.475671]')),
(4,Vec_FromText('[0.822185,0.185643,0.683452,0.211072,0.554056]')),
(5,Vec_FromText('[0.437057,0.167281,0.0770977,0.428638,0.241591]')),
(6,Vec_FromText('[0.76956,0.926895,0.803376,0.0157961,0.589042]')),
(7,Vec_FromText('[0.493999,0.641957,0.761598,0.94276,0.425865]')),
(8,Vec_FromText('[0.924108,0.275466,0.0543329,0.0731585,0.136344]')),
(9,Vec_FromText('[0.186956,0.69666,0.0356002,0.668875,0.84722]')),
(10,Vec_FromText('[0.415294,0.609278,0.426765,0.988832,0.475556]'));SELECT id FROM v ORDER BY
VEC_DISTANCE_EUCLIDEAN(v, x'6ca1d43e9df91b3fe580da3e1c247d3f147cf33e');
+----+
| id |
+----+
| 10 |
| 7 |
| 3 |
| 9 |
| 2 |
| 1 |
| 5 |
| 4 |
| 6 |
| 8 |
+----+SELECT id FROM v
ORDER BY VEC_DISTANCE_EUCLIDEAN(v, x'6ca1d43e9df91b3fe580da3e1c247d3f147cf33e')
LIMIT 2;
+----+
| id |
+----+
| 10 |
| 7 |
+----+SELECT VEC_DISTANCE_COSINE(VEC_FROMTEXT('[1,2,3]'), VEC_FROMTEXT('[3,5,7]'));SELECT id FROM v
ORDER BY VEC_DISTANCE(v, x'6ca1d43e9df91b3fe580da3e1c247d3f147cf33e');
+----+
| id |
+----+
| 10 |
| 7 |
| 3 |
| 9 |
| 2 |
| 1 |
| 5 |
| 4 |
| 6 |
| 8 |
+----+This page is about sequence objects. For details about the storage engine, see Sequence Storage Engine.
A sequence is an object that generates a sequence of numeric values, as specified by the CREATE SEQUENCE statement.
CREATE SEQUENCE creates a sequence that generates new values when called with NEXT VALUE FOR sequence_name. It's an alternative to AUTO INCREMENT when one wants to have more control of how the numbers are generated. As the SEQUENCE caches values (up to the CACHE value in the statement, by default 1000) it can in some cases be much faster than AUTO INCREMENT. Another benefit is that one can access the last value generated by all used sequences, which solves one of the limitations with .
Sequences should not be used with statement-based logging; see .
The statement is used to create a sequence. Here is an example of a sequence starting at 100, incrementing by 10 each time:
The CREATE SEQUENCE statement, along with defaults, can be viewd with the , for example:
To get the , use
or
or in Oracle mode ()
For used by the current connection from a sequence use:
or
or in Oracle mode ()
For example:
Sequences can be used in DEFAULT:
The statement is used for changing sequences. For example, to restart the sequence at another value:
The can also be used to set the next value to be returned for a SEQUENCE, for example:
SETVAL can only be used to increase the sequence value. Attempting to set a lower value will fail, returning NULL:
The statement is used to drop a sequence, for example:
If you want to use Sequences in a master-master setup or with Galera, you should use INCREMENT=0. This tells the Sequence to use and to generate unique values for each server.
Using SELECT NEXT VALUE causes an error for statement-based logging:
This happens because SELECT modifies objects.
MariaDB supports both ANSI SQL and Oracle syntax for sequences.
However as SEQUENCE is implemented as a special kind of table, it uses the same namespace as tables. The benefits are that sequences show up in , and one can also create a sequence with and drop it with . One can from it as from any other table. This ensures that all old tools that work with tables should work with sequences.
Since sequence objects act as regular tables in many contexts, they will be affected by . This is not the case in other DBMS, such as Oracle, where LOCK TABLE does not affect sequences.
One of the goals with the Sequence implementation is that all old tools, such as (previously mysqldump), should work unchanged, while still keeping the normal usage of sequence standard compatibly.
To make this possible, sequence is currently implemented as a table with a few exclusive properties.
The special properties for sequence tables are:
A sequence table has always one row.
When one creates a sequence, either with or , one row will be inserted.
If one tries to insert into a sequence table, the single row will be updated. This allows to work but also gives the additional benefit that one can change all properties of a sequence with a single insert. New applications should of course also use ALTER SEQUENCE.
. This shows the table structure that is behind the SEQUENCE including the field names that can be used with or even .
Internally, sequence tables are created as a normal table without rollback (the , and engines support this), wrapped by a sequence engine object. This allowed us to create sequences with almost no performance impact for normal tables. (The cost is one 'if' per insert if the is enabled).
The following example shows the table structure of sequences and how it can be used as a table. (Output of results are slightly edited to make them easier to read.)
The cycle_count column is incremented every time the sequence wraps around.
Thanks to Jianwe Zhao from Aliyun for his work on SEQUENCE in AliSQL, which gave ideas and inspiration for this work.
Thanks to Peter Gulutzan, who helped test and gave useful comments about the implementation.
This page is licensed: CC BY-SA / Gnu FDL
Create a sequence generator. This statement initializes a sequence object that produces a series of unique numeric values on demand.
The options for CREATE SEQUENCE can be given in any order, optionally followed by table_options.
table_options can be any of the normal table options in CREATE TABLE — the most used ones are ENGINE=... and COMMENT=.
NOMAXVALUE and NOMINVALUE are there to allow one to create SEQUENCEs using the Oracle syntax.
CREATE SEQUENCE creates a sequence that generates new values when called with NEXT VALUE FOR sequence_name. It's an alternative to if you want to have more control of how the numbers are generated. As the SEQUENCE caches values (up to CACHE), it can in some cases be much faster than . Another benefit is that you can access the last value generated by all used sequences, which solves one of the limitations with .
CREATE SEQUENCE requires the .
can be used to drop a sequence, and to change it.
INT type, that is, one of , , , , , . Can be signed or unsigned. Maximum value is based on the data type. The use of BIGINT UNSIGNED with this option extends the possible maximum value from 9223372036854775806 to 18446744073709551614. Default is BIGINT.
The AS option is not available.
Increment to use for values. May be negative. Setting an increment of 0 causes the sequence to use the value of the system variable at the time of creation, which is always a positive number. (see ). Default 1.
Minimum value for the sequence. From , the parser permits much smaller numbers, such as -9999999999999999999999999999, but converts to the minimum permitted for the INT type, with a note. Default 1 if INCREMENT > 0 , and -9223372036854775807 (or based on int type) if INCREMENT < 0.
Maximum value for sequence. From , the parser permits much larger numbers, such as 9999999999999999999999999999 used in Oracle examples, but converts to the maximum permitted for the INT type, with a note. Default 9223372036854775806 (or based on int type) if INCREMENT > 0 , and -1 if INCREMENT < 0.
First value the sequence will generate. Default MINVALUE if INCREMENT > 0, and MAX_VALUE if INCREMENT< 0.
Number of values that should be cached. 0 if no CACHE. The underlying table will be updated first time a new sequence number is generated and each time the cache runs out. Default 1000. , shutting down the server, etc. will discard the cached values, and the next sequence number generated will be according to what's stored in the Sequence object. In effect, this will discard the cached values.
Note that setting the cache to 1 from 1000 can make inserts to tables using sequences for default values 2x slower and increase the binary log sizes up to 7x.
If CYCLE is used, then the sequence should start again from MINVALUE after it has run out of values. Default value is NOCYCLE.
To be able to create a legal sequence, the following must hold:
MAXVALUE >= start
MAXVALUE > MINVALUE
START >= MINVALUE
Note that sequences can't generate the maximum/minimum 64 bit number because of the constraint ofMINVALUE and MAXVALUE.
MariaDB supports and CREATE SEQUENCE is atomic.
MariaDB does not support and CREATE SEQUENCE is atomic.
The following statement fails, as the increment conflicts with the defaults:
The sequence can be created by specifying workable minimum and maximum values:
From :
Parser accepting larger or smaller values:
Flushing the cache:
You can use sequences instead of AUTO_INCREMENT to generate values for a table:
This page is licensed: CC BY-SA / Gnu FDL
Dynamic columns allow one to store different sets of columns for each row in a table. It works by storing a set of columns in a blob and having a small set of functions to manipulate it.
Dynamic columns should be used when it is not possible to use regular columns.
A typical use case is when one needs to store items that may have many different attributes (like size, color, weight, etc), and the set of possible attributes is very large and/or unknown in advance. In that case, attributes can be put into dynamic columns.
CREATE [OR REPLACE] [TEMPORARY] SEQUENCE [IF NOT EXISTS] sequence_name
[AS { TINYINT | SMALLINT | |MEDIUMINT | INT | INTEGER | BIGINT } [SIGNED | UNSIGNED]]
[ INCREMENT [ BY | = ] number ]
[ MINVALUE [=] number | NO MINVALUE | NOMINVALUE ]
[ MAXVALUE [=] number | NO MAXVALUE | NOMAXVALUE ]
[ START [ WITH | = ] number ]
[ CACHE [=] number | NOCACHE ] [ CYCLE | NOCYCLE]
[table_options](../sql-statements/data-definition/create/create-table.md#table-options)Doing a select on the sequence shows the current state of the sequence, except the values that are reserved in the cache. The next_value column shows the next value not reserved by the cache.
FLUSH TABLES will close the sequence and the next sequence number generated will be according to what's stored in the Sequence object. In effect, this will discard the cached values.
A number of normal table operations work on Sequence tables. See next section.
DROP TABLE sequence_name. This is allowed mainly to get old tools like mariadb-dump to work with sequence tables.
SETVAL(). Set next value for the sequence.
d, with values ranging from 2017 to 2019, where only the lower value falls within the portion to be deleted, has been shrunk to 2018 to 2019.
d, with values ranging from 2017 to 2019, where only the lower value falls within the portion to be updated, has been shrunk to 2018 to 2019.
Original rows affected by the update have "_original" appended to the name.
CREATE SEQUENCE s START WITH 100 INCREMENT BY 10;SHOW CREATE SEQUENCE s\G
*************************** 1. row ***************************
Table: s
Create Table: CREATE SEQUENCE `s` start with 100 minvalue 1 maxvalue 9223372036854775806
increment by 10 cache 1000 nocycle ENGINE=InnoDBNEXT VALUE FOR sequence_nameNEXTVAL(sequence_name)sequence_name.nextvalPREVIOUS VALUE FOR sequence_nameLASTVAL(sequence_name)sequence_name.currvalSELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 100 |
+------------+
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 110 |
+------------+
SELECT LASTVAL(s);
+------------+
| LASTVAL(s) |
+------------+
| 110 |
+------------+CREATE SEQUENCE s1;
CREATE TABLE t1 (a INT PRIMARY KEY DEFAULT (NEXT VALUE FOR s1), b INT);
INSERT INTO t1 (b) VALUES (1),(2);
SELECT * FROM t1;
+---+------+
| a | b |
+---+------+
| 1 | 1 |
| 2 | 2 |
+---+------+ALTER SEQUENCE s RESTART 50;
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 50 |
+------------+SELECT SETVAL(s, 100);
+----------------+
| SETVAL(s, 100) |
+----------------+
| 100 |
+----------------+SELECT SETVAL(s, 50);
+---------------+
| SETVAL(s, 50) |
+---------------+
| NULL |
+---------------+DROP SEQUENCE s;ERROR 1665 (HY000): Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging.CREATE SEQUENCE t1;
SHOW CREATE SEQUENCE t1\G
*************************** 1. row ***************************
CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806
increment by 1 cache 1000 nocycle ENGINE=InnoDB
SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
Create Table: CREATE TABLE `t1` (
`next_not_cached_value` bigint(21) NOT NULL,
`minimum_value` bigint(21) NOT NULL,
`maximum_value` bigint(21) NOT NULL,
`start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache_size` bigint(21) unsigned NOT NULL,
`cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed',
`cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done'
) ENGINE=InnoDB SEQUENCE=1
SELECT * FROM t1\G
next_not_cached_value: 1
minimum_value: 1
maximum_value: 9223372036854775806
start_value: 1
increment: 1
cache_size: 1000
cycle_option: 0
cycle_count: 0CREATE TABLE t1(
name VARCHAR(50),
date_1 DATE,
date_2 DATE,
PERIOD FOR date_period(date_1, date_2));CREATE OR REPLACE TABLE rooms (
room_number INT,
guest_name VARCHAR(255),
checkin DATE,
checkout DATE
);
ALTER TABLE rooms ADD PERIOD FOR p(checkin,checkout);ALTER TABLE rooms DROP PERIOD FOR p;ALTER TABLE rooms ADD PERIOD IF NOT EXISTS FOR p(checkin,checkout);
ALTER TABLE rooms DROP PERIOD IF EXISTS FOR p;CREATE TABLE t1(
name VARCHAR(50),
date_1 DATE,
date_2 DATE,
PERIOD FOR date_period(date_1, date_2));
INSERT INTO t1 (name, date_1, date_2) VALUES
('a', '1999-01-01', '2000-01-01'),
('b', '1999-01-01', '2018-12-12'),
('c', '1999-01-01', '2017-01-01'),
('d', '2017-01-01', '2019-01-01');
SELECT * FROM t1;
+------+------------+------------+
| name | date_1 | date_2 |
+------+------------+------------+
| a | 1999-01-01 | 2000-01-01 |
| b | 1999-01-01 | 2018-12-12 |
| c | 1999-01-01 | 2017-01-01 |
| d | 2017-01-01 | 2019-01-01 |
+------+------------+------------+DELETE FROM t1
FOR PORTION OF date_period
FROM '2001-01-01' TO '2018-01-01';
Query OK, 3 rows affected (0.028 sec)
SELECT * FROM t1 ORDER BY name;
+------+------------+------------+
| name | date_1 | date_2 |
+------+------------+------------+
| a | 1999-01-01 | 2000-01-01 |
| b | 1999-01-01 | 2001-01-01 |
| b | 2018-01-01 | 2018-12-12 |
| c | 1999-01-01 | 2001-01-01 |
| d | 2018-01-01 | 2019-01-01 |
+------+------------+------------+TRUNCATE t1;
INSERT INTO t1 (name, date_1, date_2) VALUES
('a', '1999-01-01', '2000-01-01'),
('b', '1999-01-01', '2018-12-12'),
('c', '1999-01-01', '2017-01-01'),
('d', '2017-01-01', '2019-01-01');
SELECT * FROM t1;
+------+------------+------------+
| name | date_1 | date_2 |
+------+------------+------------+
| a | 1999-01-01 | 2000-01-01 |
| b | 1999-01-01 | 2018-12-12 |
| c | 1999-01-01 | 2017-01-01 |
| d | 2017-01-01 | 2019-01-01 |
+------+------------+------------+UPDATE t1 FOR PORTION OF date_period
FROM '2000-01-01' TO '2018-01-01'
SET name = CONCAT(name,'_original');
SELECT * FROM t1 ORDER BY name;
+------------+------------+------------+
| name | date_1 | date_2 |
+------------+------------+------------+
| a | 1999-01-01 | 2000-01-01 |
| b | 1999-01-01 | 2000-01-01 |
| b | 2018-01-01 | 2018-12-12 |
| b_original | 2000-01-01 | 2018-01-01 |
| c | 1999-01-01 | 2000-01-01 |
| c_original | 2000-01-01 | 2017-01-01 |
| d | 2018-01-01 | 2019-01-01 |
| d_original | 2017-01-01 | 2018-01-01 |
+------------+------------+------------+CREATE OR REPLACE TABLE rooms (
room_number INT,
guest_name VARCHAR(255),
checkin DATE,
checkout DATE,
PERIOD FOR p(checkin,checkout)
);
INSERT INTO rooms VALUES
(1, 'Regina', '2020-10-01', '2020-10-03'),
(2, 'Cochise', '2020-10-02', '2020-10-05'),
(1, 'Nowell', '2020-10-03', '2020-10-07'),
(2, 'Eusebius', '2020-10-04', '2020-10-06');CREATE OR REPLACE TABLE rooms (
room_number INT,
guest_name VARCHAR(255),
checkin DATE,
checkout DATE,
PERIOD FOR p(checkin,checkout),
UNIQUE (room_number, p WITHOUT OVERLAPS)
);
INSERT INTO rooms VALUES
(1, 'Regina', '2020-10-01', '2020-10-03'),
(2, 'Cochise', '2020-10-02', '2020-10-05'),
(1, 'Nowell', '2020-10-03', '2020-10-07'),
(2, 'Eusebius', '2020-10-04', '2020-10-06');
ERROR 1062 (23000): Duplicate entry '2-2020-10-06-2020-10-04' for key 'room_number'CREATE TABLE `t2` (
`id` int(11) DEFAULT NULL,
`d1` datetime DEFAULT NULL,
`d2` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE t2 ADD PERIOD FOR p(d1,d2);
SHOW CREATE TABLE t2\G
*************************** 1. row ***************************
Table: t2
Create Table: CREATE TABLE `t2` (
* //a// is *unchanged*, as the range falls entirely out of the specified portion to be updated.
* For //b//, with years ranging from 1999 to 2018, two extra rows are *inserted*, with ranges 1999-01 to 2000-01 and 2018-01 to 2018-12. The original row's period has been *shrunk* to years 2000 and 2018, and the _name_ field has got "_original" appended.
* //c//, with values ranging from 1999 to 2017, where only the upper value falls within the portion to be updated, has been *shrunk* to 1999 to 2001.
* //d//, with values ranging from 2017 to 2019, where only the lower value falls within the portion to be updated, has been *shrunk* to 2018 to 2019.
* Original rows affected by the update have "_original" appended to the ##name## field.
`id` int(11) DEFAULT NULL,
`d1` datetime NOT NULL,
`d2` datetime NOT NULL,
PERIOD FOR `p` (`d1`, `d2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1CREATE OR REPLACE TABLE `t2` (
`id` int(11) DEFAULT NULL,
`d1` datetime DEFAULT NULL,
`d2` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO t2(id) VALUES(1);
ALTER TABLE t2 ADD PERIOD FOR p(d1,d2);
ERROR 1265 (01000): Data truncated for column 'd1' at row 1MAXVALUE <= 9223372036854775806 (LONGLONG_MAX-1). From , the parser accepts values beyond this, and converts based on the int type.
MINVALUE >= -9223372036854775807 (LONGLONG_MIN+1). From , the parser accepts values beyond this, and converts based on the int type.
SETVAL(). Set next value for the sequence.
The table should have a blob column which will be used as storage for dynamic columns:
Once created, you can access dynamic columns via dynamic column functions.
Insert a row with two dynamic columns: color=blue, size=XL:
Insert another row with dynamic columns: color=black, price=500:
Select the dynamic column 'color' for all items:
It is possible to add and remove dynamic columns from a row:
You can also list all columns, or get them together with their values in JSON format:
This is a complete reference of dynamic columns in MariaDB.
Column can be referred to by name (column_name in the following code blocks). This is the preferred method. If you need support for old (< 10.0) MariaDB versions, you have to refer to columns by number. In that case, replace column_name with column_nr. This method is not recommended.
Returns a dynamic columns blob that stores the specified columns with values. The return value is suitable for
storing in a table,
further modification with other dynamic columns functions.
The as type part allows one to specify the value type. In most cases, this is redundant because MariaDB will be able to deduce the type of the value. Explicit type specification may be needed when the type of the value is not apparent. For example, a literal '2012-12-01' has a CHAR type by default, one will need to specify '2012-12-01' AS DATE to have it stored as a date. See the Datatypes section for further details. Note also MDEV-597.
Typical usage:
Adds or updates dynamic columns.
dyncol_blob must be either a valid dynamic columns blob (for example, COLUMN_CREATE returns such blob), or an empty string.
column_name specifies the name of the column to be added. If dyncol_blob already has a column with this name, it will be overwritten.
value specifies the new value for the column. Passing a NULL value will cause the column to be deleted.
as type is optional. See the section for a discussion about types.
The return value is a dynamic column blob after the modifications.
Typical usage:
Note: COLUMN_ADD() is a regular function (just like CONCAT()), hence, in order to update the value in the table you have to use the UPDATE ... SET dynamic_col=COLUMN_ADD(dynamic_col, ....) pattern.
Retrieves the value of a dynamic column by its name. If no column with the given name exists, NULL is returned.
column_name as type requires that one specify the datatype of the dynamic column they are reading.
This may seem counter-intuitive: Why would you need to specify which datatype they're retrieving? Can't the dynamic columns system figure the datatype from the data being stored?
The answer is: SQL is a statically typed language. The SQL interpreter needs to know the datatypes of all expressions before the query is run (for example, when one is using prepared statements and runs"select COLUMN_GET(...)", the prepared statement API requires the server to inform the client about the datatype of the column being read before the query is executed and the server can see what datatype the column actually has).
See the Datatypes section for more information about datatypes.
Deletes a dynamic column with the specified name. Multiple names can be given.
The return value is a dynamic column blob after the modification.
Checks if a column with name column_name exists in dyncol_blob. If yes, return 1, otherwise return 0.
Returns a comma-separated list of column names. The names are quoted with backticks.
Checks if dyncol_blob is a valid packed dynamic columns blob. A return value of 1 means the blob is valid, a return value of 0 means it is not.
Rationale:
Normally, you work with valid dynamic column blobs. Functions likeCOLUMN_CREATE, COLUMN_ADD, COLUMN_DELETE always return valid dynamic column blobs. However, if a dynamic column blob is accidentally truncated, or transcoded from one character set to another, it is corrupted. This function can be used to check if a value in a blob field is a valid dynamic column blob.
It is possible that a truncation cuts a Dynamic Column "clearly" so that COLUMN_CHECK does not notice the corruption, but, in any case of truncation, a warning is issued during value storing.
Returns a JSON representation of data in dyncol_blob :
Limitation: COLUMN_JSON decodes nested dynamic columns at a nesting level of not more than 10 levels deep. Dynamic columns that are nested deeper than 10 levels are shown as a BINARY string, without encoding.
It is possible to use nested dynamic columns by putting one dynamic column blob inside another. The COLUMN_JSON function will display nested columns.
If you are trying to get a nested dynamic column as a string, use AS BINARY as the last argument of COLUMN_GET . Otherwise, problems with character set conversion and illegal symbols are possible:
In SQL, one needs to define the type of each column in a table. Dynamic columns do not provide any way to declare a type in advance ("whenever there is a column 'weight', it should be integer" is not possible). However, each particular dynamic column value is stored together with its datatype.
The set of possible datatypes is mostly the same as that used by the CAST and CONVERT functions. However, note that there are currently some differences - see MDEV-597.
BINARY[(N)]
DYN_COL_STRING
(variable length string with binary charset)
CHAR[(N)]
DYN_COL_STRING
(variable length string with charset)
DATE
DYN_COL_DATE
(date - 3 bytes)
DATETIME[(D)]
DYN_COL_DATETIME
If you're running queries without specifying a maximum length (i.e. using #as CHAR#, not as CHAR(n)), MariaDB reports the maximum length of the result set column to be53,6870,911 (bytes or characters?). This may cause excessive memory usage in some client libraries, because they try to pre-allocate a buffer of maximum result set width. If you suspect you're hitting this problem, use CHAR(n)
whenever you're using COLUMN_GET in the select list.
It is also possible to create or parse dynamic columns blobs on the client side. libmysql client library now includes an API for writing/reading dynamic column blobs. See dynamic-columns-api for details.
Max number of columns
65535
Maximum total length of packed dynamic column
(1G)
This page is licensed: CC BY-SA / Gnu FDL
CREATE SEQUENCE s START WITH 100 INCREMENT BY 10;
CREATE SEQUENCE s2 START WITH -100 INCREMENT BY -10;CREATE SEQUENCE s3 START WITH -100 INCREMENT BY 10;
ERROR 4082 (HY000): Sequence 'test.s3' values are conflictingCREATE SEQUENCE s3 START WITH -100 INCREMENT BY 10 MINVALUE=-100 MAXVALUE=1000;CREATE SEQUENCE s3 AS BIGINT UNSIGNED START WITH 10;CREATE OR REPLACE SEQUENCE s AS TINYINT SIGNED
MINVALUE=-999999999999999999999999999999999
MAXVALUE=999999999999999999999999999999999
START WITH 100 INCREMENT BY 10;
Query OK, 0 rows affected, 2 warnings (0.037 sec)
SHOW WARNINGS;
+-------+------+-----------------------------------------------+
| Level | Code | Message |
+-------+------+-----------------------------------------------+
| Note | 1292 | Truncated incorrect INTEGER value: 'MINVALUE' |
| Note | 1292 | Truncated incorrect INTEGER value: 'MAXVALUE' |
+-------+------+-----------------------------------------------+
SELECT * FROM INFORMATION_SCHEMA.SEQUENCES\G
*************************** 1. row ***************************
SEQUENCE_CATALOG: def
SEQUENCE_SCHEMA: test
SEQUENCE_NAME: s
DATA_TYPE: tinyint
NUMERIC_PRECISION: 8
NUMERIC_PRECISION_RADIX: 2
NUMERIC_SCALE: 0
START_VALUE: 100
MINIMUM_VALUE: -127
MAXIMUM_VALUE: 126
INCREMENT: 10
CYCLE_OPTION: 0CREATE OR REPLACE SEQUENCE s START WITH 1 INCREMENT BY 1 MAXVALUE=10 CACHE=5;
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 1 |
+------------+
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 2 |
+------------+
FLUSH TABLES s;
SELECT NEXTVAL(s);
+------------+
| NEXTVAL(s) |
+------------+
| 6 |
+------------+
FLUSH TABLES s;
SELECT NEXTVAL(s);
ERROR 4084 (HY000): Sequence 'test.s' has run outCREATE SEQUENCE s1;
CREATE TABLE t1 (a INT PRIMARY KEY DEFAULT nextval(s1), b INT);
INSERT INTO t1 (b) VALUES(1);
SELINT * FROM t1;
+---+------+
| a | b |
+---+------+
| 1 | 1 |
+---+------+main
CREATE TABLE assets (
item_name VARCHAR(32) PRIMARY KEY, -- A common attribute for all items
dynamic_cols BLOB -- Dynamic columns will be stored here
);INSERT INTO assets VALUES
('MariaDB T-shirt', COLUMN_CREATE('color', 'blue', 'size', 'XL'));INSERT INTO assets VALUES
('Thinkpad Laptop', COLUMN_CREATE('color', 'black', 'price', 500));SELECT item_name, COLUMN_GET(dynamic_cols, 'color' as char)
AS color FROM assets;
+-----------------+-------+
| item_name | color |
+-----------------+-------+
| MariaDB T-shirt | blue |
| Thinkpad Laptop | black |
+-----------------+-------+-- Remove a column:
UPDATE assets SET dynamic_cols=COLUMN_DELETE(dynamic_cols, "price")
WHERE COLUMN_GET(dynamic_cols, 'color' AS CHAR)='black';
-- Add a column:
UPDATE assets SET dynamic_cols=COLUMN_ADD(dynamic_cols, 'warranty', '3 years')
WHERE item_name='Thinkpad Laptop';SELECT item_name, column_list(dynamic_cols) FROM assets;
+-----------------+---------------------------+
| item_name | column_list(dynamic_cols) |
+-----------------+---------------------------+
| MariaDB T-shirt | `size`,`color` |
| Thinkpad Laptop | `color`,`warranty` |
+-----------------+---------------------------+
SELECT item_name, COLUMN_JSON(dynamic_cols) FROM assets;
+-----------------+----------------------------------------+
| item_name | COLUMN_JSON(dynamic_cols) |
+-----------------+----------------------------------------+
| MariaDB T-shirt | {"size":"XL","color":"blue"} |
| Thinkpad Laptop | {"color":"black","warranty":"3 years"} |
+-----------------+----------------------------------------+COLUMN_CREATE(column_name, value [as type], [column_name, value
[as type]]...);INSERT INTO tbl SET dyncol_blob=COLUMN_CREATE("column_name", "value");COLUMN_ADD(dyncol_blob, column_name, value [as type],
[column_name, value [as type]]...);UPDATE t1 SET dyncol_blob=COLUMN_ADD(dyncol_blob, "column_name", "value")
WHERE id=1;COLUMN_GET(dyncol_blob, column_name as type);COLUMN_DELETE(dyncol_blob, column_name, column_name...);COLUMN_EXISTS(dyncol_blob, column_name);COLUMN_LIST(dyncol_blob);SELECT column_list(column_create('col1','val1','col2','val2'));
+---------------------------------------------------------+
| column_list(column_create('col1','val1','col2','val2')) |
+---------------------------------------------------------+
| `col1`,`col2` |
+---------------------------------------------------------+COLUMN_CHECK(dyncol_blob);COLUMN_JSON(dyncol_blob);SELECT item_name, COLUMN_JSON(dynamic_cols) FROM assets;
+-----------------+----------------------------------------+
| item_name | COLUMN_JSON(dynamic_cols) |
+-----------------+----------------------------------------+
| MariaDB T-shirt | {"size":"XL","color":"blue"} |
| Thinkpad Laptop | {"color":"black","warranty":"3 years"} |
+-----------------+----------------------------------------+SET @tmp= column_create('parent_column',
column_create('child_column', 12345));
Query OK, 0 rows affected (0.00 sec)
SELECT column_json(@tmp);
+------------------------------------------+
| column_json(@tmp) |
+------------------------------------------+
| {"parent_column":{"child_column":12345}} |
+------------------------------------------+
SELECT column_get(column_get(@tmp, 'parent_column' AS char),
'child_column' AS int);
+------------------------------------------------------------------------------+
| column_get(column_get(@tmp, 'parent_column' as char), 'child_column' as int) |
+------------------------------------------------------------------------------+
| 12345 |
+------------------------------------------------------------------------------+SELECT column_json( column_get(
column_create('test1',
column_create('key1','value1','key2','value2','key3','value3')),
'test1' AS BINARY));SELECT COLUMN_GET(blob, 'colname' as CHAR) ...(date and time (with microseconds) - 9 bytes)
DECIMAL[(M[,D])]
DYN_COL_DECIMAL
(variable length binary decimal representation with MariaDB limitation)
DOUBLE[(M,D)]
DYN_COL_DOUBLE
(64 bit double-precision floating point)
INTEGER
DYN_COL_INT
(variable length, up to 64-bit signed integer)
SIGNED [INTEGER]
DYN_COL_INT
(variable length, up to 64-bit signed integer)
TIME[(D)]
DYN_COL_TIME
(time (with microseconds, may be negative) - 6 bytes)
UNSIGNED [INTEGER]
DYN_COL_UINT
(variable length, up to 64bit unsigned integer)
If any of the specified user accounts do not yet exist, an error results. If an error occurs, ALTER USER will still modify the accounts that do not result in an error. Only one error is produced for all users which have not been modified.
For renaming an existing account (user name and/or host), see RENAME USER.
When the IF EXISTS clause is used, MariaDB will return a warning instead of an error for each specified user that does not exist.
For ALTER USER statements, account names are specified as the username argument in the same way as they are for CREATE USER statements. See account names from the CREATE USER page for details on how account names are specified.
CURRENT_USER or CURRENT_USER() can also be used to alter the account logged into the current session. For example, to change the current user's password to mariadb:
From MariaDB 10.4, it is possible to use more than one authentication plugin for each user account. For example, this can be useful to slowly migrate users to the more secure ed25519 authentication plugin over time, while allowing the old mysql_native_password authentication plugin as an alternative for the transitional period. See Authentication from MariaDB 10.4 for more.
When running ALTER USER, not specifying an authentication option in the IDENTIFIED VIA clause will remove that authentication method. (However this was not the case before , see MDEV-21928)
For example, a user is created with the ability to authenticate via both a password and unix_socket:
If the user's password is updated, but unix_socket authentication is not specified in the IDENTIFIED VIA clause, unix_socket authentication will no longer be permitted.
The optional IDENTIFIED BY clause can be used to provide an account with a password. The password should be specified in plain text. It will be hashed by the PASSWORD function prior to being stored in the mysql.user view.
For example, if our password is mariadb, then we can set the account's password with:
If you do not specify a password with the IDENTIFIED BY clause, the user
will be able to connect without a password. A blank password is not a wildcard
to match any password. The user must connect without providing a password if no
password is set.
The only authentication plugins that this clause supports are mysql_native_password and mysql_old_password.
The optional IDENTIFIED BY PASSWORD clause can be used to provide an account with a password that has already been hashed. The password should be specified as a hash that was provided by the PASSWORD#function. It will be stored in the mysql.user view as-is.
For example, if our password is mariadb, then we can find the hash with:
And then we can set an account's password with the hash:
If you do not specify a password with the IDENTIFIED BY clause, the user
will be able to connect without a password. A blank password is not a wildcard
to match any password. The user must connect without providing a password if no password is set.
The only authentication plugins that this clause supports are mysql_native_password and mysql_old_password.
The optional IDENTIFIED VIA authentication_plugin allows you to specify that the account should be authenticated by a specific authentication plugin. The plugin name must be an active authentication plugin as per SHOW PLUGINS. If it doesn't show up in that output, then you will need to install it with INSTALL PLUGIN or INSTALL SONAME.
For example, this could be used with the PAM authentication plugin:
Some authentication plugins allow additional arguments to be specified after a USING or AS keyword. For example, the PAM authentication plugin accepts a service name:
The exact meaning of the additional argument would depend on the specific authentication plugin.
The USING or AS keyword can also be used to provide a plain-text password to a plugin if it's provided as an argument to the PASSWORD() function. This is only valid for authentication plugins that have implemented a hook for the PASSWORD() function. For example, the ed25519 authentication plugin supports this:
The USING or AS keyword cannot be used to provide a plain-text password to a plugin if it's provided as an argument to the PASSWORD() function.
By default, MariaDB transmits data between the server and clients without encrypting it. This is generally acceptable when the server and client run on the same host or in networks where security is guaranteed through other means. However, in cases where the server and client exist on separate networks or they are in a high-risk network, the lack of encryption does introduce security concerns as a malicious actor could potentially eavesdrop on the traffic as it is sent over the network between them.
To mitigate this concern, MariaDB allows you to encrypt data in transit between the server and clients using the Transport Layer Security (TLS) protocol. TLS was formerly known as Secure Socket Layer (SSL), but strictly speaking the SSL protocol is a predecessor to TLS and, that version of the protocol is now considered insecure. The documentation still uses the term SSL often and for compatibility reasons TLS-related server system and status variables still use the prefix ssl_, but internally, MariaDB only supports its secure successors.
See Secure Connections Overview for more information about how to determine whether your MariaDB server has TLS support.
You can set certain TLS-related restrictions for specific user accounts. For instance, you might use this with user accounts that require access to sensitive data while sending it across networks that you do not control. These restrictions can be enabled for a user account with the CREATE USER, ALTER USER, or GRANT statements. The following options are available:
REQUIRE NONE
TLS is not required for this account, but can still be used.
REQUIRE SSL
The account must use TLS, but no valid X509 certificate is required. This option cannot be combined with other TLS options.
REQUIRE X509
The account must use TLS and must have a valid X509 certificate. This option implies REQUIRE SSL. This option cannot be combined with other TLS options.
REQUIRE ISSUER 'issuer'
The account must use TLS and must have a valid X509 certificate. Also, the Certificate Authority must be the one specified via the string issuer. This option implies REQUIRE X509. This option can be combined with the SUBJECT, and CIPHER options in any order.
REQUIRE SUBJECT 'subject'
The account must use TLS and must have a valid X509 certificate. Also, the certificate's Subject must be the one specified via the string subject. This option implies REQUIRE X509. This option can be combined with the ISSUER, and CIPHER options in any order.
REQUIRE CIPHER 'cipher'
The account must use TLS, but no valid X509 certificate is required. Also, the encryption used for the connection must use a specific cipher method specified in the string cipher. This option implies REQUIRE SSL. This option can be combined with the ISSUER, and SUBJECT options in any order.
The REQUIRE keyword must be used only once for all specified options, and the AND keyword can be used to separate individual options, but it is not required.
For example, you can alter a user account to require these TLS options with the following:
If any of these options are set for a specific user account, then any client who tries to connect with that user account will have to be configured to connect with TLS.
See Securing Connections for Client and Server for information on how to enable TLS on the client and server.
It is possible to set per-account limits for certain server resources. The following table shows the values that can be set per account:
MAX_QUERIES_PER_HOUR
Number of statements that the account can issue per hour (including updates)
MAX_UPDATES_PER_HOUR
Number of updates (not queries) that the account can issue per hour
MAX_CONNECTIONS_PER_HOUR
Number of connections that the account can start per hour
MAX_USER_CONNECTIONS
Number of simultaneous connections that can be accepted from the same account; if it is 0, max_connections will be used instead; if max_connections is 0, there is no limit for this account's simultaneous connections.
MAX_STATEMENT_TIME
Timeout, in seconds, for statements executed by the user. See also .
If any of these limits are set to 0, then there is no limit for that resource for that user.
Here is an example showing how to set an account's resource limits:
The resources are tracked per account, which means 'user'@'server'; not per user name or per connection.
The count can be reset for all users using FLUSH USER_RESOURCES, FLUSH PRIVILEGES or mysqladmin reload.
Per account resource limits are stored in the user table, in the mysql database. Columns used for resources limits are named max_questions, max_updates, max_connections (for MAX_CONNECTIONS_PER_HOUR), and max_user_connections (for MAX_USER_CONNECTIONS).
Besides automatic password expiry, as determined by default_password_lifetime, password expiry times can be set on an individual user basis, overriding the global setting, for example:
See User Password Expiry for more details.
Account locking permits privileged administrators to lock/unlock user accounts. No new client connections will be permitted if an account is locked (existing connections are not affected). For example:
See Account Locking for more details.
The lock_option and password_option clauses can occur in either order.
The lock_option must be placed before the password_option.
- permits the setting of basic criteria for passwords
- allow various authentication methods to be used, and new ones to be developed.
This page is licensed: CC BY-SA / Gnu FDL

WEBINAR
The Next Generation of MariaDB: Powered by Vector Search
Hybrid search combines the keyword precision of full-text search with the conceptual understanding of vector search to produce a single, superior set of results.
Full-text search is the traditional keyword-based search, excelling at finding documents that contain the exact words from your query. Behind the scenes, it relies on a data structure called an inverted index—a dictionary that maps each word to a list of documents it appears in, allowing for very fast lookups. For instance, a search for 'apple pie recipe' will instantly find all documents indexed under those three words: ‘apple‘, ‘pie‘ & ‘recipe‘.
ALTER USER safe@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret');ALTER USER [IF EXISTS]
user_specification [,user_specification] ...
[REQUIRE {NONE | tls_option [[AND] tls_option] ...}]
[WITH resource_option [resource_option] ...]
[lock_option] [password_option]
user_specification:
username [authentication_option]
authentication_option:
IDENTIFIED BY 'password'
| IDENTIFIED BY PASSWORD 'password_hash'
| IDENTIFIED {VIA|WITH} authentication_rule [OR authentication_rule] ...
authentication_rule:
authentication_plugin
| authentication_plugin {USING|AS} 'authentication_string'
| authentication_plugin {USING|AS} PASSWORD('password')
tls_option
SSL
| X509
| CIPHER 'cipher'
| ISSUER 'issuer'
| SUBJECT 'subject'
resource_option
MAX_QUERIES_PER_HOUR COUNT
| MAX_UPDATES_PER_HOUR COUNT
| MAX_CONNECTIONS_PER_HOUR COUNT
| MAX_USER_CONNECTIONS COUNT
| MAX_STATEMENT_TIME TIME
password_option:
PASSWORD EXPIRE
| PASSWORD EXPIRE DEFAULT
| PASSWORD EXPIRE NEVER
| PASSWORD EXPIRE INTERVAL N DAY
lock_option:
ACCOUNT LOCK
| ACCOUNT UNLOCK
}ALTER USER CURRENT_USER() IDENTIFIED BY 'mariadb';CREATE USER 'bob'@'localhost'
IDENTIFIED VIA mysql_native_password USING PASSWORD('pwd')
OR unix_socket;
SHOW CREATE USER 'bob'@'localhost'\G*************************** 1. row ***************************
CREATE USER for bob@localhost: CREATE USER `bob`@`localhost`
IDENTIFIED VIA mysql_native_password
USING '*975B2CD4FF9AE554FE8AD33168FBFC326D2021DD'
OR unix_socketALTER USER 'bob'@'localhost' IDENTIFIED VIA mysql_native_password
USING PASSWORD('pwd2');
SHOW CREATE USER 'bob'@'localhost'\G*************************** 1. row ***************************
CREATE USER for bob@localhost: CREATE USER `bob`@`localhost`
IDENTIFIED BY PASSWORD '*38366FDA01695B6A5A9DD4E428D9FB8F7EB75512'ALTER USER foo2@test IDENTIFIED BY 'mariadb';SELECT PASSWORD('mariadb');+-------------------------------------------+
| PASSWORD('mariadb') |
+-------------------------------------------+
| *54958E764CE10E50764C2EECBB71D01F08549980 |
+-------------------------------------------+ALTER USER foo2@test
IDENTIFIED BY PASSWORD '*54958E764CE10E50764C2EECBB71D01F08549980';ALTER USER foo2@test IDENTIFIED VIA pam;ALTER USER foo2@test IDENTIFIED VIA pam USING 'mariadb';ALTER USER 'alice'@'%'
REQUIRE SUBJECT '/CN=alice/O=My Dom, Inc./C=US/ST=Oregon/L=Portland' AND
ISSUER '/C=FI/ST=Somewhere/L=City/ O=Some Company/CN=Peter Parker/emailAddress=p.parker@marvel.com'
AND CIPHER 'SHA-DES-CBC3-EDH-RSA';ALTER USER 'someone'@'localhost' WITH
MAX_USER_CONNECTIONS 10
MAX_QUERIES_PER_HOUR 200;ALTER USER 'monty'@'localhost' PASSWORD EXPIRE INTERVAL 120 DAY;
ALTER USER 'monty'@'localhost' PASSWORD EXPIRE NEVER;
ALTER USER 'monty'@'localhost' PASSWORD EXPIRE DEFAULT;ALTER USER 'marijn'@'localhost' ACCOUNT LOCK;Vector search is a modern search method based on meaning. It finds documents that are conceptually similar to your query, even if they don't share any keywords. It works by converting both the query and the documents into numerical representations called "vector embeddings." These vectors exist as points in a high-dimensional conceptual space. A search then finds the "nearest neighbors"—the document points that are closest to the query point. For instance, a vector search for "apple pie recipe" might also return a document titled "how to bake a Granny Smith tart," because the model understands that "tart" is similar to "pie" and "Granny Smith" is a type of "apple."
Full-text search offers precise keyword matching, while vector search provides nuanced understanding of concepts. Together, they handle ambiguity and ensure critical queries aren't missed, resulting in a robust, intelligent search experience.
When a user searches for "sustainable coffee pods," the two search systems return the following ranked lists.
Full-Text Search Results
1
1
'Eco Coffee Pods - 100 Count'
2
3
'Recyclable Coffee Capsules'
3
4
'Morning Roast Coffee Beans'
Vector Search Results
1
2
'Compostable Espresso Pods'
2
3
'Recyclable Coffee Capsules'
3
6
'Bamboo Reusable Coffee Filter'
When two search systems produce distinct lists of titles, a traditional merging approach would prioritize titles that appear in both lists, similar to an INNER JOIN operation.
An INNER JOIN only returns results found by both search systems, discarding valuable items that appear in only one list.
If we were to INNER JOIN the two lists from our "sustainable coffee pods" search, the result would be:
3
'Recyclable Coffee Capsules'
This result is severely incomplete. It correctly finds the one common item but completely discards the #1 ranked result from both searches ('Eco Coffee Pods' and 'Compostable Espresso Pods') simply because they were specialists found by only one system.
To solve the problem of discarded results, we use Reciprocal Rank Fusion (RRF). The power of RRF lies in its simplicity: it operates on the rank of an item (1st, 2nd, 3rd) in a list, not its raw, non-comparable score. This makes it highly effective for merging lists from different systems without needing to normalize their scores.
A helpful way to think of this is to imagine your different search systems as a "panel of expert advisors"; RRF intelligently combines their opinions using the formula:
Where rank is the position of a document in a list, and k is a tuning constant that moderates the influence of that rank.
A key advantage of RRF is that it ignores the raw scores from the search systems and uses only the rank. The table below shows the partial RRF score for the top items in our "sustainable coffee pods" search, calculated with k=60.
To build the model, our query uses the following Common Table Expressions (CTEs).
vector_limit_search
Runs the initial vector search to retrieve the top N conceptually similar items.
fulltext_limit_search
Runs the initial full-text search to retrieve the top N keyword matches.
vector_score
Calculates a partial_rrf score for each item from the vector search based on its rank.
fulltext_score
Calculates a partial_rrf score for each item from the full-text search based on its rank.
full_outer_join_output
Merges the two score lists and sums the partial scores into a total_rrf.
The annotated SQL query uses the CTEs to perform the hybrid search:
With k=60, the final CTE merges and sums the partial scores. The consensus item, found in both lists, rises to the top.
3
Recyclable Coffee Capsules
0.01613
0.01613
0.03226
1
1
Eco Coffee Pods
0.01639
As introduced earlier, the k parameter can be fine-tuned for specific situations. Here are three common scenarios to consider.
Combining Diverse, Specialist Systems
For merging results from different methods like keyword and vector search, a higher k (such as 60) is ideal to balance their contributions. Our main "sustainable coffee pods" search is a perfect illustration of this, where the consensus item wins but the high-quality specialists are ranked immediately after.
1
3
Recyclable Coffee Capsules
0.03226
Consensus Winner
2
1
Eco Coffee Pods
0.01639
Specialist
Handling Mixed-Quality or "Noisy" Systems
If you are fusing results from reliable systems and one experimental, less predictable system, a higher k (60 or more) is the safest choice to prevent an outlier from disproportionately influencing the final rank.
Consider our search with a third, "noisy" system that incorrectly ranks 'Eco-Friendly Car Wax' (ID 8) at #1. A high k value minimizes the impact of this error.
Recyclable Coffee Capsules
2
2
-
1/62 + 1/62 = 0.03226
Eco-Friendly Car Wax
-
-
1
1/61 = 0.01639
The high k value correctly ensures that the consensus result from the two reliable systems easily beats the single, erroneous result from the noisy system.
Fusing High-Quality, Similar Systems
If you are combining lists from two very similar, high-performing algorithms, you can experiment with a slightly lower k (30-50) to give more weight to a top-ranked document.
Consider a case where we fuse two similar vector models (Vector_A, Vector_B) that both rank 'Compostable Espresso Pods' as #1 and 'Recyclable Coffee Capsules' as #2. A lower k makes the winner more decisive.
Compostable Pods
1, 1
1/31 + 1/31 = 0.0645
1/61 + 1/61 = 0.0328
Recyclable Capsules
2, 2
1/32 + 1/32 = 0.0625
1/62 + 1/62 = 0.0322
Score Difference
0.0020
With k=30, the score separation between the #1 and #2 results is more than three times larger, showing higher confidence in the top result, which is desirable when you trust both systems.
A formal, 3-step process can be used to scientifically determine the best k value for your data through offline evaluation. To illustrate this process, which requires a pre-judged "ground truth" set with graded relevance, we will use a separate, self-contained case study.
Gather Prerequisites
You need: Multiple Ranked Lists, a "Ground Truth" Set, and an Evaluation Metric (like NDCG). With a query like "healthy breakfast", your ground truth might look like this:
A
'Oatmeal with Berries'
3 (High)
B
'Green Smoothie'
3 (High)
C
'Avocado Toast'
2 (Medium)
D
'Bacon and Eggs'
1 (Low)
And your raw ranked lists might be:
Full-Text Results: [D, A, E]
Vector Results: [B, C, A]
Run the Experiment
You iterate through k values, applying the RRF formula to the raw lists to generate a final ranking for each k.
Final Ranked List (k=10):
1
B
'Green Smoothie'
2
D
'Bacon and Eggs'
3
A
'Oatmeal with Berries'
4
C
'Avocado Toast'
Final Ranked List (k=60):
1
A
'Oatmeal with Berries'
2
B
'Green Smoothie'
3
C
'Avocado Toast'
4
D
'Bacon and Eggs'
Analyze and Select
You use your metric to "grade" each list against the Ground Truth and choose the k with the highest score. The k=60 list is clearly better as it placed the two "Highly Relevant" documents (A and B) at the top.
10
0.85
60
0.92
In this experiment, k=60 is the winner. A key advantage of RRF is that its performance is "not critically sensitive to the choice of k, making it a robust and reliable method" for improving search relevance.

WEBINAR
The Next Generation of MariaDB: Powered by Vector Search
This page describes the client-side API for reading and writing blobs.
Normally, you should use which are run inside the MariaDB server and allow one to access Dynamic Columns content without any client-side libraries.
If you need to read/write dynamic column blobs on the client for some reason, this API enables that.
The API is a part of libmysql C client library. In order to use it, you need to include this header file and link against libmysql
-- Set the parameters for our query.
SET @k = 60; -- The RRF smoothing constant.
SET @search_term = "sustainable coffee pods";
-- The vector for the search term would be set here.
-- SET @search_term_vector = VEC_FromText("...");
-- Use CTEs to break the logic into sequential steps.
WITH
-- STEP 1: Get top results from each search method.
vector_limit_search AS (
SELECT id, title, VEC_DISTANCE_EUCLIDEAN(embedding, @search_term_vector) AS dist
FROM products ORDER BY dist ASC LIMIT 10
),
fulltext_limit_search AS (
SELECT id, title, MATCH(title) AGAINST (@search_term) AS match_score
FROM products WHERE MATCH(title) AGAINST (@search_term)
ORDER BY match_score DESC LIMIT 10
),
-- STEP 2: Calculate partial RRF scores for each list.
vector_score AS (
SELECT id, title, 1 / (@k + RANK() OVER (ORDER BY dist ASC)) AS partial_rrf
FROM vector_limit_search
),
fulltext_score AS (
SELECT id, title, 1 / (@k + RANK() OVER (ORDER BY match_score DESC)) AS partial_rrf
FROM fulltext_limit_search
),
-- STEP 3: Merge the two lists and sum the scores.
full_outer_join_output AS (
SELECT v.id, v.title, (v.partial_rrf + IFNULL(f.partial_rrf, 0)) AS total_rrf
FROM vector_score v LEFT JOIN fulltext_score f USING (id)
UNION
SELECT f.id, f.title, (IFNULL(v.partial_rrf, 0) + f.partial_rrf) AS total_rrf
FROM fulltext_score f LEFT JOIN vector_score v USING (id)
)
-- STEP 4: Select the final, unified list.
SELECT id, title, total_rrf FROM full_outer_join_output
ORDER BY total_rrf DESC
LIMIT 10;ACCESSIBLE
ADD
ALL
ALTER
ANALYZE
AND
AS
ASC
ASENSITIVE
BEFORE
BETWEEN
BIGINT
BINARY
Some keywords are exceptions for historical reasons, and are permitted as unquoted identifiers. These include:
ACTION
NO
In , there are a number of extra reserved words:
BODY
ELSIF
GOTO
HISTORY
MINUS (> 10.6.0)
OTHERS
PACKAGE
PERIOD
RAISE
ROWNUM
ROWTYPE
If the IGNORE_SPACE SQL_MODE flag is set, function names become reserved words.
This page is licensed: CC BY-SA / Gnu FDL
DYNAMIC_COLUMN represents a packed dynamic column blob. It is essentially a string-with-length and is defined as follows:
Dynamic columns blobs store {name, value} pairs. The DYNAMIC_COLUMN_VALUE structure is used to represent the value in accessible form.
Every value has a type, which is determined by the type member.
DYN_COL_NULL
-
DYN_COL_INT
value.x.long_value
DYN_COL_UINT
value.x.ulong_value
DYN_COL_DOUBLE
value.x.double_value
DYN_COL_STRING
value.x.string.value, value.x.string.charset
DYN_COL_DECIMAL
value.x.decimal.value
Values with type DYN_COL_NULL do not ever occur in dynamic columns blobs.
Type DYN_COL_DYNCOL means that the value is a packed dynamic blob. This is how nested dynamic columns are done.
Before storing a value to value.x.decimal.value, you must call mariadb_dyncol_prepare_decimal() to initialize the space for storage.
enum enum_dyncol_func_result is used as return value.
0
ER_DYNCOL_OK
OK
0
ER_DYNCOL_NO
(the same as ER_DYNCOL_OK but for functions which return a YES/NO)
1
ER_DYNCOL_YES
YES response or success
2
ER_DYNCOL_TRUNCATED
Operation succeeded but the data was truncated
Result codes that are less than zero represent error conditions.
Functions come in pairs:
xxx_num() operates on the old (pre-MariaDB-10.0.1) dynamic column blob format, where columns were identified by numbers.
xxx_named() can operate on both old or new data format. If it modifies the blob, it converts it to the new data format.
You should use xxx_named() functions, unless you need to keep the data compatible with MariaDB versions before 10.0.1.
First, define mariadb_dyncol_init(A) memset((A), 0, sizeof(*(A))). It is the correct initialization for an empty packed dynamic blob.
Copy where str is IN. Packed dynamic blob which memory should be freed.
Create a packed dynamic blob from arrays of values and names.
Here are the names and values:
str
OUT
Packed dynamic blob will be put here
column_count
IN
Number of columns
column_numbers
IN
Column numbers array (old format)
column_keys
IN
Column names array (new format)
Add or update columns in a dynamic columns blob. To delete a column, update its value to a "non-value" of type DYN_COL_NULL :
str
IN/OUT
Dynamic columns blob to be modified
column_count
IN
Number of columns in following arrays
column_numbers
IN
Column numbers array (old format)
column_keys
IN
Column names array (new format)
Check if column with given names exist in the blob:
str
IN
Packed dynamic columns string
column_number
IN
Column number (old format)
column_key
IN
Column name (new format)
The function returns YES, or NO or Error code.
Get the number of columns in a dynamic column blob:
str
IN
Packed dynamic columns string
column_count
OUT
Number of not NULL columns in the dynamic columns string
List columns in a dynamic column blob:
str
IN
Packed dynamic columns string
column_count
OUT
Number of columns in following arrays
column_numbers
OUT
Column numbers array (old format). Caller should free this array
column_keys
OUT
Column names array (new format). Caller should free this array
Get a value of one column:
str
IN
Packed dynamic columns string
column_number
IN
Column numbers array (old format)
column_key
IN
Column names array (new format)
value
OUT
Value of the column
If the column is not found, NULL is returned as the value of the column.
Get the value of all columns:
str
IN
Packed dynamic columns string to unpack
column_count
OUT
Number of columns in following arrays
column_keys
OUT
Column names array (should be free by caller)
values
OUT
Values of the columns array (should be free by caller)
Check whether the dynamic columns blob uses the new data format (the one where columns are identified by names):
str
IN
Packed dynamic columns string
Check whether the dynamic column blob has the correct data format:
str
IN
Packed dynamic columns string
Get contents of a dynamic columns blob in a JSON form:
str
IN
Packed dynamic columns string
json
OUT
JSON representation
Get the dynamic column value as one of the base types:
str or ll or dbl
OUT
value of the column
val
IN
Value
Initialize DYNAMIC_COLUMN_VALUE before setting the value of value.x.decimal.value:
value
OUT
Value of the column
This function links value.x.decimal.value to value.x.decimal.buffer.
Initialize a DYNAMIC_COLUMN_VALUE structure to a safe default:
Compare two column names (column names are compared with memcmp()):
This page is licensed: CC BY-SA / Gnu FDL
0
0.01639
2
2
Compostable Espresso Pods
0
0.01639
0.01639
2
2
2
Compostable Espresso Pods
0.01639
Specialist
0.0006
E
'Cinnamon Roll'
0 (None)
5
E
'Cinnamon Roll'
5
E
'Cinnamon Roll'
MariaDB supports temporal data tables in the form of system-versioning tables (allowing you to query and operate on historic data, discussed below), (allow you to query and operate on a temporal range of data), and (which combine both system-versioning and ).
System-versioned tables store the history of all changes, not only data which is currently applicable. This allows data analysis for any point in time, auditing of changes and comparison of data from different points in time. Typical uses cases are:
#include <mysql/ma_dyncol.h>/* A generic-purpose arbitrary-length string defined in MySQL Client API */
typedef struct st_dynamic_string
{
char *str;
size_t length,max_length,alloc_increment;
} DYNAMIC_STRING;
...
typedef DYNAMIC_STRING DYNAMIC_COLUMN;struct st_dynamic_column_value
{
DYNAMIC_COLUMN_TYPE type;
union
{
long long long_value;
unsigned long long ulong_value;
double double_value;
struct {
MYSQL_LEX_STRING value;
CHARSET_INFO *charset;
} string;
struct {
decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
decimal_t value;
} decimal;
MYSQL_TIME time_value;
} x;
};
typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE;void mariadb_dyncol_free(DYNAMIC_COLUMN *str);enum enum_dyncol_func_result
mariadb_dyncol_create_many(DYNAMIC_COLUMN *str,
uint column_count,
uint *column_numbers,
DYNAMIC_COLUMN_VALUE *values,
my_bool new_string);
enum enum_dyncol_func_result
mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str,
uint column_count,
MYSQL_LEX_STRING *column_keys,
DYNAMIC_COLUMN_VALUE *values,
my_bool new_string);enum enum_dyncol_func_result
mariadb_dyncol_update_many(DYNAMIC_COLUMN *str,
uint column_count,
uint *column_numbers,
DYNAMIC_COLUMN_VALUE *values);
enum enum_dyncol_func_result
mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str,
uint column_count,
MYSQL_LEX_STRING *column_keys,
DYNAMIC_COLUMN_VALUE *values);enum enum_dyncol_func_result
mariadb_dyncol_exists(DYNAMIC_COLUMN *str, uint column_number);
enum enum_dyncol_func_result
mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *column_key);enum enum_dyncol_func_result
mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count);enum enum_dyncol_func_result
mariadb_dyncol_list(DYNAMIC_COLUMN *str, uint *column_count, uint **column_numbers);
enum enum_dyncol_func_result
mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *column_count,
MYSQL_LEX_STRING **column_keys);enum enum_dyncol_func_result
mariadb_dyncol_get(DYNAMIC_COLUMN *org, uint column_number,
DYNAMIC_COLUMN_VALUE *value);
enum enum_dyncol_func_result
mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *column_key,
DYNAMIC_COLUMN_VALUE *value);enum enum_dyncol_func_result
mariadb_dyncol_unpack(DYNAMIC_COLUMN *str,
uint *column_count,
MYSQL_LEX_STRING **column_keys,
DYNAMIC_COLUMN_VALUE **values);my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str);enum enum_dyncol_func_result
mariadb_dyncol_check(DYNAMIC_COLUMN *str);enum enum_dyncol_func_result
mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json);enum enum_dyncol_func_result
mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
CHARSET_INFO *cs, my_bool quote);
enum enum_dyncol_func_result
mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val);
enum enum_dyncol_func_result
mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val);void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value);#define mariadb_dyncol_value_init(V) (V)->type= DYN_COL_NULLint mariadb_dyncol_column_cmp_named(const MYSQL_LEX_STRING *s1,
const MYSQL_LEX_STRING *s2);DYN_COL_DATETIME
value.x.time_value
DYN_COL_DATE
value.x.time_value
DYN_COL_TIME
value.x.time_value
DYN_COL_DYNCOL
value.x.string.value
-1
ER_DYNCOL_FORMAT
Wrong format of the encoded string
-2
ER_DYNCOL_LIMIT
A limit of implementation reached
-3
ER_DYNCOL_RESOURCE
Out of resources
-4
ER_DYNCOL_DATA
Incorrect input data
-5
ER_DYNCOL_UNKNOWN_CHARSET
Unknown character set
values
IN
Column values array
new_string
IN
If TRUE then the str will be reinitialized (not freed) before usage
values
IN
Column values array
Data analytics (retrospective, trends etc.), e.g. to get your staff information as of one year ago.
Point-in-time recovery - recover a table state as of particular point in time.
System-versioned tables were first introduced in the SQL:2011 standard.
The CREATE TABLE syntax has been extended to permit creating a system-versioned table. To be system-versioned, according to SQL:2011, a table must have two generated columns, a period, and a special table option clause:
In MariaDB, you can use a simplified syntax:
In the latter case, no extra columns will be created, and they won't clutter the output of, say, SELECT * FROM t. The versioning information will still be stored, and it can be accessed via the pseudo-columns ROW_START and ROW_END:
An existing table can be altered to enable system versioning for it.
Similarly, system versioning can be removed from a table:
You can also add system versioning with all columns created explicitly:
MariaDB starting with
It is possible to convert a versioned table from implicit to explicit row_start/row_end columns. Note that, in order to do any ALTER on a system versioned table, system_versioning_alter_history must be set to KEEP.
It is not possible to convert a versioned table from implicit to explicit row_start/row_end columns. Doing so results in a duplicate row error:
When data is inserted into a system-versioned table, it is given a row_start value of the current timestamp, and a row_end value of FROM_UNIXTIME (2147483647.999999). The current timestamp can be adjusted by setting the timestamp system variable:
To query the historical data one uses the clause FOR SYSTEM_TIME directly after the table name (before the table alias, if any). SQL:2011 provides three syntactic extensions:
AS OF is used to see the table as it was at a specific point in time in the past:
BETWEEN start AND end will show all rows that were visible at any point between two specified points in time. It works inclusively, a row visible exactly at start or exactly at end will be shown too.
FROM start TO end will also show all rows that were visible at any point between two specified points in time, including start, but excluding end.
Additionally, MariaDB implements a non-standard extension.
ALL will show all rows, historical and current.
If the FOR SYSTEM_TIME clause is not used, the table shows the current data. This is usually the same as if you had specified FOR SYSTEM_TIME AS OF CURRENT_TIMESTAMP, unless you've adjusted the row_start value:
If the FOR SYSTEM_TIME clause is not used, the table shows the current data. This is usually the same as if you had specified FOR SYSTEM_TIME AS OF CURRENT_TIMESTAMP, unless you've adjusted the row_start value (only possible by setting the secure_timestamp variable):
When a system-versioned table is used in a view or in a subquery in the from clause, FOR SYSTEM_TIME can be used directly in the view or subquery body, or (non-standard) applied to the whole view when it's being used in a SELECT:
Or:
Tables that use system-versioning implicitly add the row_end column to the Primary Key. While this is generally not an issue for most use cases, it can lead to problems when re-applying write statements from the binary log or in replication environments, where a primary retries an SQL statement on the replica.
Specifically, these writes include a value on the row_end column containing the timestamp from when the write was initially made. The re-occurrence of the Primary Key with the old system-versioning columns raises an error due to the duplication.
To mitigate this with MariaDB Replication, set the secure_timestamp system variable to YES on the replica. When set, the replica uses its own system clock when applying to the row log, meaning that the primary can retry as many times as needed without causing a conflict. The retries generate new historical rows with new values for the row_start and row_end columns.
A point in time when a row was inserted or deleted does not necessarily mean that a change became visible at the same moment. With transactional tables, a row might have been inserted in a long transaction, and became visible hours after it was inserted.
For some applications — for example, when doing data analytics on one-year-old data — this distinction does not matter much. For others — forensic analysis — it might be crucial.
MariaDB supports transaction-precise history (only for the InnoDB storage engine) that allows seeing the data exactly as it would've been seen by a new connection doing a SELECT at the specified point in time — rows inserted before that point, but committed after will not be shown.
To use transaction-precise history, InnoDB needs to remember not timestamps, but transaction identifier per row. This is done by creating generated columns as BIGINT UNSIGNED, not TIMESTAMP(6):
These columns must be specified explicitly, but they can be made INVISIBLE to avoid cluttering SELECT * output.
Note that if you are using an engine that does not support system versioning with transaction ids, you will get an error like "start_trxid must be of type TIMESTAMP(6) for system-versioned table t".
When one uses transaction-precise history, one can optionally use transaction identifiers in the FOR SYSTEM_TIME clause:
This shows the data, exactly as it was seen by the transaction with the identifier 12345.
Data for this feature is stored in the mysql.transaction_registry table.
When the history is stored together with the current data, it increases the size of the table, so current data queries — table scans and index searches — will take more time, because they will need to skip over historical data. If most queries on that table use only current data, it might make sense to store the history separately, to reduce the overhead from versioning.
This is done by partitioning the table by SYSTEM_TIME. Because of the partition pruning optimization, all current data queries will only access one partition, the one that stores current data.
This example shows how to create such a partitioned table:
In this example, all history will be stored in the partition p_hist while all current data will be in the partition p_cur. The table must have exactly one current partition and at least one historical partition.
Partitioning by SYSTEM_TIME also supports automatic partition rotation. You can rotate historical partitions by time or by size. This example shows how to rotate partitions by size:
MariaDB starts writing history rows into partition p0, and at the end of the statement that wrote the 100000th row, MariaDB will switch to partition p1. There are only two historical partitions, so when p1 overflows, MariaDB will issue a warning, but will continue writing into it.
Similarly, one can rotate partitions by time:
This means that the history for the first week after the table was created will be stored in p0. The history for the second week — in p1, and all later history will go into p2. One can see the exact rotation time for each partition in the INFORMATION_SCHEMA.PARTITIONS table.
It is possible to combine partitioning by SYSTEM_TIME and subpartitions:
Since partitioning by current and historical data is such a typical use case, it is possible to use a simplified statement to do so. Instead of the following statement:
You can use:
You can also specify the number of partitions, which is useful if you want to rotate history by time, for example:
Specifying the number of partitions without specifying a rotation condition results in a warning:
While specifying only one partition results in an error:
The AUTO keyword can be used to automatically create history partitions:
Or with explicit partitions:
To disable or enable auto-creation, one can use ALTER TABLE by adding or removing AUTO from the partitioning specification:
If the rest of the partitioning specification is identical to CREATE TABLE, no repartitioning will be done (for details see MDEV-27328).
Because it stores all the history, a system-versioned table might grow very large over time. There are many options to trim down the space and remove the old history.
One can completely drop the versioning from the table and add it back again, this deletes all the history:
It might be a rather time-consuming operation, though, as the table needs to be rebuilt, possibly twice (depending on the storage engine).
Another option would be to use partitioning and drop some of historical partitions:
You cannot drop a current partition or the only historical partition.
As a third option; you can use a variant of the DELETE statement to prune the history:
Or only old history up to a specific point in time:
Or to a specific transaction (with BEFORE SYSTEM_TIME TRANSACTION xxx).
To protect the integrity of the history, this statement requires a special DELETE HISTORY privilege.
Currently, using the DELETE HISTORY statement with a BEFORE SYSTEM_TIME greater than the ROW_END of the active records (as a TIMESTAMP, this has a maximum value of '2038-01-19 03:14:07' UTC) results in the historical records being dropped, and the active records being deleted and moved to history. See MDEV-25468.
The TRUNCATE TABLE statement drops all historical records from a system-versioned table.
Historic data is protected from TRUNCATE statements, as per the SQL standard, and an Error 4137 is instead raised:
Another MariaDB extension allows one to version only a subset of columns in a table. This is useful, for example, if you have a table with user information that should be versioned, but one column is, let's say, a login counter that is incremented often and is not interesting to version. Such a column can be excluded from versioning by declaring it WITHOUT VERSIONING
A column can also be declared WITH VERSIONING, that will automatically make the table versioned. The statement below is equivalent to the one above:
A number of system variables are related to system-versioned tables:
Description: SQL:2011 does not allow ALTER TABLE on system-versioned tables. When this variable is set to ERROR, an attempt to alter a system-versioned table will result in an error. When this variable is set to KEEP, ALTER TABLE will be allowed, but the history will become incorrect — querying historical data will show the new table structure. This mode is still useful, for example, when adding new columns to a table. Note that if historical data contains or would contain nulls, attempting to ALTER these columns to be NOT NULL will return an error (or warning if strict_mode is not set).
Command line: --system-versioning-alter-history=value
Scope: Global, Session
Dynamic: Yes
Type: Enum
Default Value: ERROR
Valid Values: ERROR, KEEP
Description: If set to a specific timestamp value, an implicit FOR SYSTEM_TIME AS OF clause will be applied to all queries. This is useful if one wants to do many queries for history at the specific point in time. Set it to 'DEFAULT' to restore the default behavior. Has no effect on DML, so queries such as INSERT .. SELECT and REPLACE .. SELECT need to state AS OF explicitly.
Note: You need to use quotes around the name 'DEFAULT' when setting the session value, unquoted literal DEFAULT will restore the current global value instead.
Command line: None
Scope: Global, Session
Dynamic: Yes
Type: Varchar
Default Value: DEFAULT
Description: Never fully implemented and removed in the following release.
Command line: --system-versioning-innodb-algorithm-simple[={0|1}]
Scope: Global, Session
Dynamic: Yes
Type: Boolean
Default Value: ON
Introduced: MariaDB 10.3.4
Removed: MariaDB 10.3.5
Description: Allows direct inserts into ROW_START and ROW_END columns if secure_timestamp allows changing timestamp.
Command line: --system-versioning-insert-history[={0|1}]
Scope: Global, Session
Dynamic: Yes
Type: Boolean
Default Value: OFF
Introduced: MariaDB 10.11.0
Versioning clauses cannot be applied to generated (virtual and persistent) columns.
mariadb-dump did not read historical rows from versioned tables, and so historical data would not be backed up. Also, a restore of the timestamps would not be possible as they cannot be defined by an insert/a user. From , use the -H or --dump-history options to include the history.
MariaDB Temporal Tables (video)
This page is licensed: CC BY-SA / Gnu FDL
For each account, CREATE USER creates a new row in the mysql.user view (and the underlying mysql.global_priv table) that has no privileges.
For each account, CREATE USER creates a new row in mysql.user table that has no privileges.
If any of the specified accounts, or any permissions for the specified accounts, already exist, then the server returns ERROR 1396 (HY000). If an error occurs, CREATE USER will still create the accounts that do not result in an error. Only one error is produced for all users which have not been created:
CREATE USER, DROP USER, CREATE ROLE, and DROP ROLE all produce the same error code when they fail.
See Account Names below for details on how account names are specified.
One can also create users with GRANT if SQL_MODE does not have NO_AUTO_CREATE_USER set. NO_AUTO_CREATE_USER is set by default.
If the optional OR REPLACE clause is used, it is basically a shortcut for:
For example:
When the IF NOT EXISTS clause is used, MariaDB will return a warning instead of an error if the specified user already exists.
For example:
If more than one authentication mechanism is declared using the OR keyword, the mechanisms are attempted in the order they are declared in the CREATE USER statement. As soon as one of the authentication mechanisms is successful, authentication is complete. If none of them is successful, the authentication has failed.
The optional IDENTIFIED BY clause can be used to provide an account with a password. The password should be specified in plain text. It will be hashed by the PASSWORD function prior to being stored in the mysql.user/mysql.global_priv_table table.
For example, if our password is mariadb, then we can create the user with:
If you do not specify a password with the IDENTIFIED BY clause, the user
will be able to connect without a password. A blank password is not a wildcard
to match any password. The user must connect without providing a password if no
password is set.
The only authentication plugins that this clause supports are mysql_native_password and mysql_old_password.
The optional IDENTIFIED BY PASSWORD clause can be used to provide an account with a password that has already been hashed. The password should be specified as a hash that was provided by the PASSWORD function. It will be stored in the mysql.user/mysql.global_priv_table table as-is.
For example, if our password is mariadb, then we can find the hash with:
And then we can create a user with the hash:
If you do not specify a password with the IDENTIFIED BY clause, the user will be able to connect without a password. A blank password is not a wildcard to match any password. The user must connect without providing a password if no password is set.
The only authentication plugins that this clause supports are mysql_native_password and mysql_old_password.
The optional IDENTIFIED VIA authentication_plugin allows you to specify that the account should be authenticated by a specific authentication plugin. The plugin name must be an active authentication plugin as per SHOW PLUGINS. If it doesn't show up in that output, then you will need to install it with INSTALL PLUGIN or INSTALL SONAME.
VIA and WITH are synonyms.
For example, this could be used with the PAM authentication plugin:
Some authentication plugins allow additional arguments to be specified after a USING or AS keyword. For example, the PAM authentication plugin accepts a service name:
The exact meaning of the additional argument would depend on the specific authentication plugin.
The USING or AS keyword can also be used to provide a plain-text password to a plugin if it's provided as an argument to the PASSWORD() function. This is only valid for authentication plugins that have implemented a hook for the PASSWORD() function. For example, the ed25519 authentication plugin supports this:
One can specify many authentication plugins, they all work as alternatives ways of authenticating a user:
By default, when you create a user without specifying an authentication plugin, MariaDB uses the mysql_native_password plugin.
MariaDB allows you to encrypt data in transit between the server and clients using the Transport Layer Security (TLS) protocol. TLS was formerly known as Secure Socket Layer (SSL), but strictly speaking the SSL protocol is a predecessor to TLS and, that version of the protocol is now considered insecure. The documentation still uses the term SSL often and for compatibility reasons TLS-related server system and status variables still use the prefix ssl_, but internally, MariaDB only supports its secure successors.
By default, MariaDB transmits data between the server and clients without encrypting it. This is generally acceptable when the server and client run on the same host or in networks where security is guaranteed through other means. However, in cases where the server and client exist on separate networks or they are in a high-risk network, the lack of encryption does introduce security concerns as a malicious actor could potentially eavesdrop on the traffic as it is sent over the network between them.
To mitigate this concern, MariaDB allows you to encrypt data in transit between the server and clients using the Transport Layer Security (TLS) protocol. TLS was formerly known as Secure Socket Layer (SSL), but strictly speaking the SSL protocol is a predecessor to TLS and, that version of the protocol is now considered insecure. The documentation still uses the term SSL often and for compatibility reasons TLS-related server system and status variables still use the prefix ssl_, but internally, MariaDB only supports its secure successors.
See Secure Connections Overview for more information about how to determine whether your MariaDB server has TLS support.
You can set certain TLS-related restrictions for specific user accounts. For instance, you might use this with user accounts that require access to sensitive data while sending it across networks that you do not control. These restrictions can be enabled for a user account with the CREATE USER, ALTER USER, or GRANT statements. The following options are available:
REQUIRE NONE
TLS is not required for this account, but can still be used.
REQUIRE SSL
The account must use TLS, but no valid X509 certificate is required. This option cannot be combined with other TLS options.
REQUIRE X509
The account must use TLS and must have a valid X509 certificate. This option implies REQUIRE SSL. This option cannot be combined with other TLS options.
REQUIRE ISSUER 'issuer'
The account must use TLS and must have a valid X509 certificate. Also, the Certificate Authority must be the one specified via the string issuer. This option implies REQUIRE X509. This option can be combined with the SUBJECT, and CIPHER options in any order.
REQUIRE SUBJECT 'subject'
The account must use TLS and must have a valid X509 certificate. Also, the certificate's Subject must be the one specified via the string subject. This option implies REQUIRE X509. This option can be combined with the ISSUER, and CIPHER options in any order.
REQUIRE CIPHER 'cipher'
The account must use TLS, but no valid X509 certificate is required. Also, the encryption used for the connection must use a specific cipher method specified in the string cipher. This option implies REQUIRE SSL. This option can be combined with the ISSUER, and SUBJECT options in any order.
The REQUIRE keyword must be used only once for all specified options, and the AND keyword can be used to separate individual options, but it is not required.
For example, you can create a user account that requires these TLS options with the following:
If any of these options are set for a specific user account, then any client who tries to connect with that user account will have to be configured to connect with TLS.
See Securing Connections for Client and Server for information on how to enable TLS on the client and server.
It is possible to set per-account limits for certain server resources. The following table shows the values that can be set per account:
MAX_QUERIES_PER_HOUR
Number of statements that the account can issue per hour (including updates)
MAX_UPDATES_PER_HOUR
Number of updates (not queries) that the account can issue per hour
MAX_CONNECTIONS_PER_HOUR
Number of connections that the account can start per hour
MAX_USER_CONNECTIONS
Number of simultaneous connections that can be accepted from the same account; if it is 0, max_connections will be used instead; if max_connections is 0, there is no limit for this account's simultaneous connections.
MAX_STATEMENT_TIME
Timeout, in seconds, for statements executed by the user. See also .
If any of these limits are set to 0, then there is no limit for that resource for that user.
Here is an example showing how to create a user with resource limits:
The resources are tracked per account, which means 'user'@'server'; not per user name or per connection.
The count can be reset for all users using FLUSH USER_RESOURCES, FLUSH PRIVILEGES or mariadb-admin reload.
Per account resource limits are stored in the user table, in the mysql database. Columns used for resources limits are named max_questions, max_updates, max_connections (for MAX_CONNECTIONS_PER_HOUR), and max_user_connections (for MAX_USER_CONNECTIONS).
Account names have both a user name component and a host name component, and are specified as 'user_name'@'host_name'.
The user name and host name may be unquoted, quoted as strings using double quotes (") or
single quotes ('), or quoted as identifiers using backticks (```). You must use quotes
when using special characters (such as a hyphen) or wildcard characters. If you quote, you
must quote the user name and host name separately (for example 'user_name'@'host_name').
If the host name is not provided, it is assumed to be '%'.
Host names may contain the wildcard characters % and _. They are matched as if by
the LIKE clause. If you need to use a wildcard character literally (for example, to
match a domain name with an underscore), prefix the character with a backslash. See LIKE
for more information on escaping wildcard characters.
Host name matches are case-insensitive. Host names can match either domain names or IP
addresses. Use 'localhost' as the host name to allow only local client connections. On Linux, the loopback interface (127.0.0.1) will not match 'localhost' as it is not considered a local connection: this means that only connections via UNIX-domain sockets will match 'localhost'.
You can use a netmask to match a range of IP addresses using 'base_ip/netmask' as the
host name. A user with an IP address ip_addr will be allowed to connect if the following
condition is true:
For example, given a user:
the IP addresses satisfying this condition range from 247.150.130.0 to 247.150.130.255.
Using 255.255.255.255 is equivalent to not using a netmask at all. Netmasks cannot be used for IPv6 addresses.
Note that the credentials added when creating a user with the '%' wildcard host will not grant access in all cases. For example, some systems come with an anonymous localhost user, and when connecting from localhost this will take precedence.
Before MariaDB 10.6, the host name component could be up to 60 characters in length. Starting from MariaDB 10.6, it can be up to 255 characters.
User names must match exactly, including case. A user name that is empty is known as an anonymous account and is allowed to match a login attempt with any user name component. These are described more in the next section.
For valid identifiers to use as user names, see Identifier Names.
It is possible for more than one account to match when a user connects. MariaDB selects the first matching account after sorting according to the following criteria:
Accounts with an exact host name are sorted before accounts using a wildcard in the host name. Host names using a netmask are considered to be exact for sorting.
Accounts with a wildcard in the host name are sorted according to the position of the first wildcard character. Those with a wildcard character later in the host name sort before those with a wildcard character earlier in the host name.
Accounts with a non-empty user name sort before accounts with an empty user name.
Accounts with an empty user name are sorted last. As mentioned previously, these are known as anonymous accounts. These are described more in the next section.
The following table shows a list of example account as sorted by these criteria:
Once connected, you only have the privileges granted to the account that matched, not all accounts that could have matched. For example, consider the following commands:
If you connect as joffrey from 192.168.0.3, you will have the SELECT
privilege on the table test.t1, but not on the table test.t2. If you connect as joffrey from any other IP address, you will have the SELECT privilege on the table test.t2, but not
on the table test.t1.
Usernames can be up to 80 characters long before 10.6 and starting from 10.6 it can be 128 characters long.
Anonymous accounts are accounts where the user name portion of the account name is empty. These accounts act as special catch-all accounts. If a user attempts to log into the system from a host, and an anonymous account exists with a host name portion that matches the user's host, then the user will log in as the anonymous account if there is no more specific account match for the user name that the user entered.
For example, here are some anonymous accounts:
On some systems, the mysql.db table has some entries for the ''@'%' anonymous account by default. Unfortunately, there is no matching entry in the mysql.user/mysql.global_priv_table table, which means that this anonymous account doesn't exactly exist, but it does have privileges--usually on the default test database created by mariadb-install-db. These account-less privileges are a legacy that is leftover from a time when MySQL's privilege system was less advanced.
This situation means that you will run into errors if you try to create a ''@'%' account. For example:
The fix is to DELETE the row in the mysql.db table and then execute FLUSH PRIVILEGES:
Note that FLUSH PRIVILEGES is only needed if one modifies the mysql tables directly. It is not needed when using CREATE USER, DROP USER, GRANT etc.
And then the account can be created:
See MDEV-13486 for more information.
Besides automatic password expiry, as determined by default_password_lifetime, password expiry times can be set on an individual user basis, overriding the global setting, for example:
See User Password Expiry for more details.
Account locking permits privileged administrators to lock/unlock user accounts. No new client connections will be permitted if an account is locked (existing connections are not affected). For example:
See Account Locking for more details.
The lock_option and password_option clauses can occur in either order.
Prior to MariaDB 10.4.7 and MariaDB 10.5.8, the lock_option must be placed before the password_option.
From and , the lock_option and password_option clauses can occur in either order.
- permits the setting of basic criteria for passwords
- allow various authentication methods to be used, and new ones to be developed.
This page is licensed: GPLv2, originally from fill_help_tables.sql
BLOB
BOTH
BY
CALL
CASCADE
CASE
CHANGE
CHAR
CHARACTER
CHECK
COLLATE
COLUMN
CONDITION
CONSTRAINT
CONTINUE
CONVERT
CREATE
CROSS
CURRENT_DATE
CURRENT_ROLE
CURRENT_TIME
CURRENT_TIMESTAMP
CURRENT_USER
CURSOR
DATABASE
DATABASES
DAY_HOUR
DAY_MICROSECOND
DAY_MINUTE
DAY_SECOND
DEC
DECIMAL
DECLARE
DEFAULT
DELAYED
DELETE
DELETE_DOMAIN_ID
DESC
DESCRIBE
DETERMINISTIC
DISTINCT
DISTINCTROW
DIV
DO_DOMAIN_IDS
DOUBLE
DROP
DUAL
EACH
ELSE
ELSEIF
ENCLOSED
ESCAPED
EXCEPT
EXISTS
EXIT
EXPLAIN
FALSE
FETCH
FLOAT
FLOAT4
FLOAT8
FOR
FORCE
FOREIGN
FROM
FULLTEXT
GENERAL
GRANT
GROUP
HAVING
HIGH_PRIORITY
HOUR_MICROSECOND
HOUR_MINUTE
HOUR_SECOND
IF
IGNORE
IGNORE_DOMAIN_IDS
IGNORE_SERVER_IDS
IN
INDEX
INFILE
INNER
INOUT
INSENSITIVE
INSERT
INT
INT1
INT2
INT3
INT4
INT8
INTEGER
INTERSECT
INTERVAL
INTO
IS
ITERATE
JOIN
KEY
KEYS
KILL
LEADING
LEAVE
LEFT
LIKE
LIMIT
LINEAR
LINES
LOAD
LOCALTIME
LOCALTIMESTAMP
LOCK
LONG
LONGBLOB
LONGTEXT
LOOP
LOW_PRIORITY
MASTER_HEARTBEAT_PERIOD
MASTER_SSL_VERIFY_SERVER_CERT
MATCH
MAXVALUE
MEDIUMBLOB
MEDIUMINT
MEDIUMTEXT
MIDDLEINT
MINUTE_MICROSECOND
MINUTE_SECOND
MOD
MODIFIES
NATURAL
NOT
NO_WRITE_TO_BINLOG
NULL
NUMERIC
OFFSET (> 10.6)
ON
OPTIMIZE
OPTION
OPTIONALLY
OR
ORDER
OUT
OUTER
OUTFILE
OVER
PAGE_CHECKSUM
PARSE_VCOL_EXPR
PARTITION
PRECISION
PRIMARY
PROCEDURE
PURGE
RANGE
READ
READS
READ_WRITE
REAL
RECURSIVE
REF_SYSTEM_ID
REFERENCES
REGEXP
RELEASE
RENAME
REPEAT
REPLACE
REQUIRE
RESIGNAL
RESTRICT
RETURN
RETURNING
REVOKE
RIGHT
RLIKE
ROW_NUMBER (> 10.7)
ROWS
SCHEMA
SCHEMAS
SECOND_MICROSECOND
SELECT
SENSITIVE
SEPARATOR
SET
SHOW
SIGNAL
SLOW
SMALLINT
SPATIAL
SPECIFIC
SQL
SQLEXCEPTION
SQLSTATE
SQLWARNING
SQL_BIG_RESULT
SQL_CALC_FOUND_ROWS
SQL_SMALL_RESULT
SSL
STARTING
STATS_AUTO_RECALC
STATS_PERSISTENT
STATS_SAMPLE_PAGES
STRAIGHT_JOIN
TABLE
TERMINATED
THEN
TINYBLOB
TINYINT
TINYTEXT
TO
TRAILING
TRIGGER
TRUE
UNDO
UNION
UNIQUE
UNLOCK
UNSIGNED
UPDATE
USAGE
USE
USING
UTC_DATE
UTC_TIME
UTC_TIMESTAMP
VALUES
VARBINARY
VARCHAR
VARCHARACTER
VARYING
VECTOR (> 11.6)
WHEN
WHERE
WHILE
WINDOW
WITH
WRITE
XOR
YEAR_MONTH
ZEROFILL
SYSDATE
SYSTEM
SYSTEM_TIME
VERSIONING
WITHOUT

WEBINAR
The Next Generation of MariaDB: Powered by Vector Search

WEBINAR
The Next Generation of MariaDB: Powered by Vector Search
CREATE OR REPLACE TABLE t1 (x INT) WITH SYSTEM VERSIONING;
SET system_versioning_alter_history = keep;
ALTER TABLE t1 ADD COLUMN rs TIMESTAMP(6) AS ROW START,
ADD COLUMN re TIMESTAMP(6) AS ROW END, ADD PERIOD FOR SYSTEM_TIME (rs,re)CREATE OR REPLACE TABLE t1 (x INT) WITH SYSTEM VERSIONING;
SET system_versioning_alter_history = keep;
ALTER TABLE t1 ADD COLUMN rs TIMESTAMP(6) AS ROW START,
ADD COLUMN re TIMESTAMP(6) AS ROW END, ADD PERIOD FOR SYSTEM_TIME (rs,re);
ERROR 4134 (HY000): Duplicate ROW START column `rs`CREATE OR REPLACE TABLE t (a int) WITH SYSTEM VERSIONING;
SELECT NOW();
+---------------------+
| NOW() |
+---------------------+
| 2022-10-24 23:43:37 |
+---------------------+
INSERT INTO t VALUES (1);
SET @@timestamp = UNIX_TIMESTAMP('2033-03-03');
INSERT INTO t VALUES (2);
DELETE FROM t;
SET @@timestamp = default;
SELECT a, row_start, row_end FROM t FOR SYSTEM_TIME ALL;
+------+----------------------------+----------------------------+
| a | row_start | row_end |
+------+----------------------------+----------------------------+
| 1 | 2022-10-24 23:43:37.192725 | 2033-03-03 00:00:00.000000 |
| 2 | 2033-03-03 00:00:00.000000 | 2033-03-03 00:00:00.000000 |
+------+----------------------------+----------------------------+
2 rows in set (0.000 sec)
SELECT a, row_start, row_end FROM t FOR SYSTEM_TIME AS OF CURRENT_TIMESTAMP;
+------+----------------------------+----------------------------+
| a | row_start | row_end |
+------+----------------------------+----------------------------+
| 1 | 2022-10-24 23:43:37.192725 | 2033-03-03 00:00:00.000000 |
+------+----------------------------+----------------------------+
1 row in set (0.000 sec)
SELECT a, row_start, row_end FROM t;
Empty set (0.001 sec)CREATE OR REPLACE TABLE t (a int) WITH SYSTEM VERSIONING;
SELECT NOW();
+---------------------+
| NOW() |
+---------------------+
| 2022-10-24 23:43:37 |
+---------------------+
INSERT INTO t VALUES (1);
SET @@timestamp = UNIX_TIMESTAMP('2033-03-03');
INSERT INTO t VALUES (2);
DELETE FROM t;
SET @@timestamp = default;
SELECT a, row_start, row_end FROM t FOR SYSTEM_TIME ALL;
+------+----------------------------+----------------------------+
| a | row_start | row_end |
+------+----------------------------+----------------------------+
| 1 | 2022-10-24 23:43:37.192725 | 2033-03-03 00:00:00.000000 |
| 2 | 2033-03-03 00:00:00.000000 | 2033-03-03 00:00:00.000000 |
+------+----------------------------+----------------------------+
2 rows in set (0.000 sec)
SELECT a, row_start, row_end FROM t FOR SYSTEM_TIME AS OF CURRENT_TIMESTAMP;
+------+----------------------------+----------------------------+
| a | row_start | row_end |
+------+----------------------------+----------------------------+
| 1 | 2022-10-24 23:43:37.192725 | 2033-03-03 00:00:00.000000 |
+------+----------------------------+----------------------------+
1 row in set (0.000 sec)
SELECT a, row_start, row_end FROM t;
Empty set (0.001 sec)CREATE TABLE t(
x INT,
start_timestamp TIMESTAMP(6) GENERATED ALWAYS AS ROW START,
end_timestamp TIMESTAMP(6) GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME(start_timestamp, end_timestamp)
) WITH SYSTEM VERSIONING;CREATE TABLE t (
x INT
) WITH SYSTEM VERSIONING;SELECT x, ROW_START, ROW_END FROM t;CREATE TABLE t(
x INT
);ALTER TABLE t ADD SYSTEM VERSIONING;SHOW CREATE TABLE t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`x` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONINGALTER TABLE t DROP SYSTEM VERSIONING;SHOW CREATE TABLE t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`x` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1ALTER TABLE t ADD COLUMN ts TIMESTAMP(6) GENERATED ALWAYS AS ROW START,
ADD COLUMN te TIMESTAMP(6) GENERATED ALWAYS AS ROW END,
ADD PERIOD FOR SYSTEM_TIME(ts, te),
ADD SYSTEM VERSIONING;SHOW CREATE TABLE t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`x` int(11) DEFAULT NULL,
`ts` timestamp(6) GENERATED ALWAYS AS ROW START,
`te` timestamp(6) GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (`ts`, `te`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONINGSELECT NOW();
+---------------------+
| NOW() |
+---------------------+
| 2022-10-24 23:09:38 |
+---------------------+
INSERT INTO t VALUES(1);
SET @@timestamp = UNIX_TIMESTAMP('2033-10-24');
INSERT INTO t VALUES(2);
SET @@timestamp = default;
INSERT INTO t VALUES(3);
SELECT a,row_start,row_end FROM t;
+------+----------------------------+----------------------------+
| a | row_start | row_end |
+------+----------------------------+----------------------------+
| 1 | 2022-10-24 23:09:38.951347 | 2038-01-19 05:14:07.999999 |
| 2 | 2033-10-24 00:00:00.000000 | 2038-01-19 05:14:07.999999 |
| 3 | 2022-10-24 23:09:38.961857 | 2038-01-19 05:14:07.999999 |
+------+----------------------------+----------------------------+SELECT * FROM t FOR SYSTEM_TIME AS OF TIMESTAMP'2016-10-09 08:07:06';SELECT * FROM t FOR SYSTEM_TIME BETWEEN (NOW() - INTERVAL 1 YEAR) AND NOW();SELECT * FROM t FOR SYSTEM_TIME FROM '2016-01-01 00:00:00' TO '2017-01-01 00:00:00';SELECT * FROM t FOR SYSTEM_TIME ALL;CREATE VIEW v1 AS SELECT * FROM t FOR SYSTEM_TIME AS OF TIMESTAMP'2016-10-09 08:07:06';CREATE VIEW v1 AS SELECT * FROM t;
SELECT * FROM v1 FOR SYSTEM_TIME AS OF TIMESTAMP'2016-10-09 08:07:06';CREATE TABLE t(
x INT,
start_trxid BIGINT UNSIGNED GENERATED ALWAYS AS ROW START,
end_trxid BIGINT UNSIGNED GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME(start_trxid, end_trxid)
) WITH SYSTEM VERSIONING;SELECT * FROM t FOR SYSTEM_TIME AS OF TRANSACTION 12345;CREATE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME (
PARTITION p_hist HISTORY,
PARTITION p_cur CURRENT
);CREATE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME LIMIT 100000 (
PARTITION p0 HISTORY,
PARTITION p1 HISTORY,
PARTITION pcur CURRENT
);CREATE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME INTERVAL 1 WEEK (
PARTITION p0 HISTORY,
PARTITION p1 HISTORY,
PARTITION p2 HISTORY,
PARTITION pcur CURRENT
);CREATE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME
SUBPARTITION BY KEY (x)
SUBPARTITIONS 4 (
PARTITION ph HISTORY,
PARTITION pc CURRENT
);CREATE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME (
PARTITION p0 HISTORY,
PARTITION pn CURRENT
);CREATE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME;CREATE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME
INTERVAL 1 MONTH
PARTITIONS 12;CREATE OR REPLACE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME PARTITIONS 12;
Query OK, 0 rows affected, 1 warning (0.518 sec)
Warning (Code 4115): Maybe missing parameters: no rotation condition for multiple HISTORY partitions.CREATE OR REPLACE TABLE t (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME PARTITIONS 1;
ERROR 4128 (HY000): Wrong partitions for `t`: must have at least one HISTORY and exactly one last CURRENTCREATE TABLE t1 (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO;
CREATE TABLE t1 (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME INTERVAL 1 MONTH
STARTS '2021-01-01 00:00:00' AUTO PARTITIONS 12;
CREATE TABLE t1 (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME LIMIT 1000 AUTO;CREATE TABLE t1 (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO
(PARTITION p0 HISTORY, PARTITION pn CURRENT);CREATE TABLE t1 (x INT) WITH SYSTEM VERSIONING
PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO;
# Disables auto-creation:
ALTER TABLE t1 PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR;
# Enables auto-creation:
ALTER TABLE t1 PARTITION BY SYSTEM_TIME INTERVAL 1 HOUR AUTO;ALTER TABLE t DROP SYSTEM VERSIONING;
ALTER TABLE t ADD SYSTEM VERSIONING;ALTER TABLE t DROP PARTITION p0;DELETE HISTORY FROM t;DELETE HISTORY FROM t BEFORE SYSTEM_TIME '2016-10-09 08:07:06';TRUNCATE t;
ERROR 4137 (HY000): System-versioned tables do not support TRUNCATE TABLECREATE TABLE t (
x INT,
y INT WITHOUT SYSTEM VERSIONING
) WITH SYSTEM VERSIONING;CREATE TABLE t (
x INT WITH SYSTEM VERSIONING,
y INT
);CREATE [OR REPLACE] USER [IF NOT EXISTS]
user_specification [,user_specification ...]
[REQUIRE {NONE | tls_option [[AND] tls_option ...] }]
[WITH resource_option [resource_option ...] ]
[lock_option] [password_option]
user_specification:
username [authentication_option]
authentication_option:
IDENTIFIED BY 'password'
| IDENTIFIED BY PASSWORD 'password_hash'
| IDENTIFIED {VIA|WITH} authentication_rule [OR authentication_rule ...]
authentication_rule:
authentication_plugin
| authentication_plugin {USING|AS} 'authentication_string'
| authentication_plugin {USING|AS} PASSWORD('password')
tls_option:
SSL
| X509
| CIPHER 'cipher'
| ISSUER 'issuer'
| SUBJECT 'subject'
resource_option:
MAX_QUERIES_PER_HOUR count
| MAX_UPDATES_PER_HOUR count
| MAX_CONNECTIONS_PER_HOUR count
| MAX_USER_CONNECTIONS count
| MAX_STATEMENT_TIME time
password_option:
PASSWORD EXPIRE
| PASSWORD EXPIRE DEFAULT
| PASSWORD EXPIRE NEVER
| PASSWORD EXPIRE INTERVAL N DAY
lock_option:
ACCOUNT LOCK
| ACCOUNT UNLOCK
}ERROR 1396 (HY000):
Operation CREATE USER failed for 'u1'@'%','u2'@'%'DROP USER IF EXISTS name;
CREATE USER name ...;CREATE USER foo2@test IDENTIFIED BY 'password';
ERROR 1396 (HY000): Operation CREATE USER failed for 'foo2'@'test'
CREATE OR REPLACE USER foo2@test IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.00 sec)CREATE USER foo2@test IDENTIFIED BY 'password';
ERROR 1396 (HY000): Operation CREATE USER failed for 'foo2'@'test'
CREATE USER IF NOT EXISTS foo2@test IDENTIFIED BY 'password';
Query OK, 0 rows affected, 1 warning (0.00 sec)
SHOW WARNINGS;
+-------+------+----------------------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------------------+
| Note | 1973 | Can't create user 'foo2'@'test'; it already exists |
+-------+------+----------------------------------------------------+CREATE USER foo2@test IDENTIFIED BY 'mariadb';SELECT PASSWORD('mariadb');
+-------------------------------------------+
| PASSWORD('mariadb') |
+-------------------------------------------+
| *54958E764CE10E50764C2EECBB71D01F08549980 |
+-------------------------------------------+
1 row in set (0.00 sec)CREATE USER foo2@test IDENTIFIED BY PASSWORD '*54958E764CE10E50764C2EECBB71D01F08549980';CREATE USER foo2@test IDENTIFIED VIA pam;CREATE USER foo2@test IDENTIFIED VIA pam USING 'mariadb';CREATE USER safe@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret');CREATE USER safe@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret') OR unix_socket;CREATE USER 'alice'@'%'
REQUIRE SUBJECT '/CN=alice/O=My Dom, Inc./C=US/ST=Oregon/L=Portland'
AND ISSUER '/C=FI/ST=Somewhere/L=City/ O=Some Company/CN=Peter Parker/emailAddress=p.parker@marvel.com'
AND CIPHER 'SHA-DES-CBC3-EDH-RSA';CREATE USER 'someone'@'localhost' WITH
MAX_USER_CONNECTIONS 10
MAX_QUERIES_PER_HOUR 200;ip_addr & netmask = base_ipCREATE USER 'maria'@'247.150.130.0/255.255.255.0';+---------+-------------+
| User | Host |
+---------+-------------+
| joffrey | 192.168.0.3 |
| | 192.168.0.% |
| joffrey | 192.168.% |
| | 192.168.% |
+---------+-------------+CREATE USER 'joffrey'@'192.168.0.3';
CREATE USER 'joffrey'@'%';
GRANT SELECT ON test.t1 TO 'joffrey'@'192.168.0.3';
GRANT SELECT ON test.t2 TO 'joffrey'@'%';CREATE USER ''@'localhost';
CREATE USER ''@'192.168.0.3';CREATE USER ''@'%';
ERROR 1396 (HY000): Operation CREATE USER failed for ''@'%'DELETE FROM mysql.db WHERE User='' AND Host='%';
FLUSH PRIVILEGES;CREATE USER ''@'%';
Query OK, 0 rows affected (0.01 sec)CREATE USER 'monty'@'localhost' PASSWORD EXPIRE INTERVAL 120 DAY;CREATE USER 'marijn'@'localhost' ACCOUNT LOCK;