1.9. MySQL Standards Compliance
This section describes how MySQL relates to the ANSI/ISO SQL standards. MySQL Server has many extensions to the SQL standard, and here you can find out what they are and how to use them. You can also find information about functionality missing from MySQL Server, and how to work around some of the differences.
The SQL standard has been evolving since 1986 and several versions exist. In this manual, "SQL-92" refers to the standard released in 1992, "SQL:1999" refers to the standard released in 1999, and "SQL:2003" refers to the current version of the standard. We use the phrase "the SQL standard" or "standard SQL" to mean the current version of the SQL standard at any time.
One of our main goals with the product is to continue to work toward compliance with the SQL standard, but without sacrificing speed or reliability. We are not afraid to add extensions to SQL or support for non-SQL features if this greatly increases the usability of MySQL Server for a large segment of our user base. The HANDLER interface is an example of this strategy.
We continue to support transactional and non-transactional databases to satisfy both mission-critical 24/7 usage and heavy Web or logging usage.
MySQL Server was originally designed to work with medium-sized databases (10100 million rows, or about 100MB per table) on small computer systems. Today MySQL Server handles terabyte-sized databases, but the code can also be compiled in a reduced version suitable for hand-held and embedded devices. The compact design of the MySQL server makes development in both directions possible without any conflicts in the source tree.
Currently, we are not targeting real-time support, although MySQL replication capabilities offer significant functionality.
MySQL supports high-availability database clustering using the NDBCluster storage engine. See Chapter 9, "MySQL Cluster."
XML support is to be implemented in a future version of the database server.
1.9.1. What Standards MySQL Follows
Our aim is to support the full ANSI/ISO SQL standard, but without making concessions to speed and quality of the code.
ODBC levels 0-3.51.
1.9.2. Selecting SQL Modes
The MySQL server can operate in different SQL modes, and can apply these modes differentially for different clients. This capability enables each application to tailor the server's operating mode to its own requirements.
SQL modes control aspects of server operation such as what SQL syntax MySQL should support and what kind of data validation checks it should perform. This makes it easier to use MySQL in different environments and to use MySQL together with other database servers.
You can set the default SQL mode by starting mysqld with the --sql-mode="mode_value" option. Beginning with MySQL 4.1, you can also change the mode at runtime by setting the sql_mode system variable with a SET [SESSION|GLOBAL] sql_mode= 'mode_value' statement.
For more information on setting the SQL mode, see Section 4.2.5, "The Server SQL Mode."
1.9.3. Running MySQL in ANSI Mode
As of MySQL 4.1.1, you can achieve the same effect at runtime by executing these two statements:
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE; SET GLOBAL sql_mode = 'ANSI';
You can see that setting the sql_mode system variable to 'ANSI' enables all SQL mode options that are relevant for ANSI mode as follows:
mysql> SET GLOBAL sql_mode= 'ANSI' ; mysql> SELECT @@global.sql_mode; -> 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI'
Note that running the server in ANSI mode with --ansi is not quite the same as setting the SQL mode to 'ANSI'. The --ansi option affects the SQL mode and also sets the transaction isolation level. Setting the SQL mode to 'ANSI' has no effect on the isolation level.
1.9.4. MySQL Extensions to Standard SQL
MySQL Server supports some extensions that you probably won't find in other SQL DBMSs. Be warned that if you use them, your code won't be portable to other SQL servers. In some cases, you can write code that includes MySQL extensions, but is still portable, by using comments of the following form:
/*! MySQL-specific code */
In this case, MySQL Server parses and executes the code within the comment as it would any other SQL statement, but other SQL servers will ignore the extensions. For example, MySQL Server recognizes the STRAIGHT_JOIN keyword in the following statement, but other servers will not:
SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE ...
If you add a version number after the '!' character, the syntax within the comment is executed only if the MySQL version is greater than or equal to the specified version number. The TEMPORARY keyword in the following comment is executed only by servers from MySQL 3.23.02 or higher:
CREATE /*!32302 TEMPORARY */ TABLE t (a INT);
For a prioritized list indicating when new extensions are added to MySQL Server, you should consult the online MySQL development roadmap at http://dev.mysql.com/doc/mysql/en/roadmap.html.
1.9.5. MySQL Differences from Standard SQL
We try to make MySQL Server follow the ANSI SQL standard and the ODBC SQL standard, but MySQL Server performs operations differently in some cases:
18.104.22.168. Subquery Support
MySQL 4.1 and up supports subqueries and derived tables. A "subquery" is a SELECT statement nested within another statement. A "derived table" (an unnamed view) is a subquery in the FROM clause of another statement.
For MySQL versions older than 4.1, most subqueries can be rewritten using joins or other methods.
22.214.171.124. SELECT INTO TABLE
MySQL Server doesn't support the SELECT ... INTO TABLE Sybase SQL extension. Instead, MySQL Server supports the INSERT INTO ... SELECT standard SQL syntax, which is basically the same thing. For example:
INSERT INTO tbl_temp2 (fld_id) SELECT tbl_temp1.fld_order_id FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;
Alternatively, you can use SELECT ... INTO OUTFILE or CREATE TABLE ... SELECT.
As of MySQL 5.0, you can use SELECT ... INTO with user-defined variables. The same syntax can also be used inside stored routines using cursors and local variables.
126.96.36.199. Transactions and Atomic Operations
MySQL Server (version 3.23-max and all versions 4.0 and above) supports transactions with the InnoDB and BDB transactional storage engines. InnoDB provides full ACID compliance. See Chapter 8, "Storage Engines and Table Types." For information about InnoDB differences from standard SQL with regard to treatment of transaction errors, see Section 8.2.15, "InnoDB Error Handling."
The other non-transactional storage engines in MySQL Server (such as MyISAM) follow a different paradigm for data integrity called "atomic operations." In transactional terms, MyISAM tables effectively always operate in AUTOCOMMIT=1 mode. Atomic operations often offer comparable integrity with higher performance.
Because MySQL Server supports both paradigms, you can decide whether your applications are best served by the speed of atomic operations or the use of transactional features. This choice can be made on a per-table basis.
As noted, the trade-off for transactional versus non-transactional storage engines lies mostly in performance. Transactional tables have significantly higher memory and disk space requirements, and more CPU overhead. On the other hand, transactional storage engines such as InnoDB also offer many significant features. MySQL Server's modular design allows the concurrent use of different storage engines to suit different requirements and deliver optimum performance in all situations.
The transactional paradigm has its benefits and its drawbacks. Many users and application developers depend on the ease with which they can code around problems where an abort appears to be necessary, or is necessary. However, even if you are new to the atomic operations paradigm, or more familiar with transactions, do consider the speed benefit that nontransactional tables can offer on the order of three to five times the speed of the fastest and most optimally tuned transactional tables.
In situations where integrity is of highest importance, MySQL Server offers transaction-level reliability and integrity even for non-transactional tables. If you lock tables with LOCK TABLES, all updates stall until integrity checks are made. If you obtain a READ LOCAL lock (as opposed to a write lock) for a table that allows concurrent inserts at the end of the table, reads are allowed, as are inserts by other clients. The newly inserted records are not be seen by the client that has the read lock until it releases the lock. With INSERT DELAYED, you can write inserts that go into a local queue until the locks are released, without having the client wait for the insert to complete. See Section 6.3.3, "Concurrent Inserts."
"Atomic," in the sense that we mean it, is nothing magical. It only means that you can be sure that while each specific update is running, no other user can interfere with it, and there can never be an automatic rollback (which can happen with transactional tables if you are not very careful). MySQL Server also guarantees that there are no dirty reads.
188.8.131.52. Stored Routines and Triggers
Stored procedures and functions are implemented beginning with MySQL 5.0.
Basic trigger functionality is implemented beginning with MySQL 5.0.2, with further development planned for MySQL 5.1.
184.108.40.206. Foreign Keys
For storage engines other than InnoDB, MySQL Server parses the FOREIGN KEY syntax in CREATE TABLE statements, but does not use or store it. In the future, the implementation will be extended to store this information in the table specification file so that it may be retrieved by mysqldump and ODBC. At a later stage, foreign key constraints will be implemented for MyISAM tables as well.
Foreign key enforcement offers several benefits to database developers:
Do keep in mind that these benefits come at the cost of additional overhead for the database server to perform the necessary checks. Additional checking by the server affects performance, which for some applications may be sufficiently undesirable as to be avoided if possible. (Some major commercial applications have coded the foreign key logic at the application level for this reason.)
MySQL gives database developers the choice of which approach to use. If you don't need foreign keys and want to avoid the overhead associated with enforcing referential integrity, you can choose another storage engine instead, such as MyISAM. (For example, the MyISAM storage engine offers very fast performance for applications that perform only INSERT and SELECT operations. In this case, the table has no holes in the middle and the inserts can be performed concurrently with retrievals. See Section 6.3.3, "Concurrent Inserts.")
If you choose not to take advantage of referential integrity checks, keep the following considerations in mind:
Be aware that the use of foreign keys can sometimes lead to problems:
Note that foreign keys in SQL are used to check and enforce referential integrity, not to join tables. If you want to get results from multiple tables from a SELECT statement, you do this by performing a join between them:
SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id;
Views (including updatable views) are implemented beginning with MySQL Server 5.0.1.
Views are useful for allowing users to access a set of relations (tables) as if it were a single table, and limiting their access to just that. Views can also be used to restrict access to rows (a subset of a particular table). For access control to columns, you can also use the sophisticated privilege system in MySQL Server. See Section 4.8, "The MySQL Access Privilege System."
In designing an implementation of views, our ambitious goal, as much as is possible within the confines of SQL, has been full compliance with "Codd's Rule #6" for relational database systems: "All views that are theoretically updatable, should in practice also be updatable."
220.127.116.11. '--' as the Start of a Comment
Standard SQL uses the C syntax /* this is a comment */ for comments, and MySQL Server supports this syntax as well. MySQL also support extensions to this syntax that allow MySQL-specific SQL to be embedded in the comment, as described in the "MySQL Language Reference."
Standard SQL uses '--' as a start-comment sequence. MySQL Server uses '#' as the start comment character. MySQL Server 3.23.3 and up also supports a variant of the '--' comment style. That is, the '--' start-comment sequence must be followed by a space (or by a control character such as a newline). The space is required to prevent problems with automatically generated SQL queries that use constructs such as the following, where we automatically insert the value of the payment for !payment!:
UPDATE account SET credit=credit-!payment!
Consider about what happens if payment has a negative value such as -1:
UPDATE account SET credit=credit--1
credit--1 is a legal expression in SQL, but '--' is interpreted as the start of a comment, part of the expression is discarded. The result is a statement that has a completely different meaning than intended:
UPDATE account SET credit=credit
The statement produces no change in value at all! This illustrates that allowing comments to start with '--' can have serious consequences.
Using our implementation of requiring a following space for '--' to be recognized as a start-comment sequence in MySQL Server 3.23.3 and up, credit--1 is actually safe.
The following information is relevant only if you are running a MySQL version earlier than 3.23.3:
If you have an SQL script in a text file that contains '--' comments, you should use the replace utility as follows to convert the comments to use '#' characters before executing the script:
shell> replace "--" " #" < text-file-with-funny-comments.sql \ | mysql db_name
That is safer than executing the script in the usual way:
shell> mysql db_name < text-file-with-funny-comments.sql
You can also edit the script file "in place" to change the '--' comments to '#' comments:
shell> replace " --" " #" -- text-file-with-funny-comments.sql
Change them back with this command:
shell> replace " #" " --" -- text-file-with-funny-comments.sql
1.9.6. How MySQL Deals with Constraints
MySQL allows you to work both with transactional tables that allow rollback and with nontransactional tables that do not. Because of this, constraint handling is a bit different in MySQL than in other DBMSs. We must handle the case when you have inserted or updated a lot of rows in a non-transactional table for which changes cannot be rolled back when an error occurs.
The basic philosophy is that MySQL Server tries to produce an error for anything that it can detect while parsing a statement to be executed, and tries to recover from any errors that occur while executing the statement. We do this in most cases, but not yet for all.
The options MySQL has when an error occurs are to stop the statement in the middle or to recover as well as possible from the problem and continue. By default, the server follows the latter course. This means, for example, that the server may coerce illegal values to the closest legal values.
Beginning with MySQL 5.0.2, several SQL mode options are available to provide greater control over handling of bad data values and whether to continue statement execution or abort when errors occur. Using these options, you can configure MySQL Server to act in a more traditional fashion that is like other DBMSs that reject improper input. The SQL mode can be set globally at server startup to affect all clients. Individual clients can set the SQL mode at runtime, which enables each client to select the behavior most appropriate for its requirements. See Section 4.2.5, "The Server SQL Mode."
The following sections describe how MySQL Server handles different types of constraints.
18.104.22.168. PRIMARY KEY and UNIQUE Index Constraints
Normally, an error occurs when you try to INSERT or UPDATE a row that causes a primary key, unique key, or foreign key violation. If you are using a transactional storage engine such as InnoDB, MySQL automatically rolls back the statement. If you are using a non-transactional storage engine, MySQL stops processing the statement at the row for which the error occurred and leaves any remaining rows unprocessed.
If you want to ignore such key violations, MySQL supports an IGNORE keyword for INSERT and UPDATE. In this case, MySQL ignores any key violations and continues processing with the next row.
You can get information about the number of rows actually inserted or updated with the mysql_info() C API function. In MySQL 4.1 and up, you also can use the SHOW WARNINGS statement.
Currently, only InnoDB tables support foreign keys. See Section 22.214.171.124, "FOREIGN KEY Constraints." Foreign key support in MyISAM tables is scheduled for implementation in MySQL 5.2. See Section 1.6, "MySQL Development Roadmap."
126.96.36.199. Constraints on Invalid Data
Before MySQL 5.0.2, MySQL is forgiving of illegal or improper data values and coerces them to legal values for data entry. In MySQL 5.0.2 and up, that remains the default behavior, but you can change the server SQL mode to select more traditional treatment of bad values such that the server rejects them and aborts the statement in which they occur. Section 4.2.5, "The Server SQL Mode."
This section describes the default (forgiving) behavior of MySQL, as well as the newer strict SQL mode and how it differs.
If you are not using strict mode, whenever you insert an "incorrect" value into a column, such as a NULL into a NOT NULL column or a too-large numeric value into a numeric column, MySQL sets the column to the "best possible value" instead of producing an error. The following rules describe in more detail how this works:
The reason for using the preceding rules in non-strict mode is that we can't check these conditions until the statement has begun executing. We can't just roll back if we encounter a problem after updating a few rows, because the storage engine may not support rollback. The option of terminating the statement is not that good; in this case, the update would be "half done," which is probably the worst possible scenario. In this case, it's better to "do the best you can" and then continue as if nothing happened.
In MySQL 5.0.2 and up, you can select stricter treatment of input values by using the STRICT_TRANS_TABLES or STRICT_ALL_TABLES SQL modes:
SET sql_mode = 'STRICT_TRANS_TABLES'; SET sql_mode = 'STRICT_ALL_TABLES';
STRICT_TRANS_TABLES enables strict mode for transactional storage engines, and also to some extent for non-transactional engines. It works like this:
For even stricter checking, enable STRICT_ALL_TABLES. This is the same as STRICT_TRANS_TABLES except that for non-transactional storage engines, errors abort the statement even for bad data in rows following the first row. This means that if an error occurs partway through a multiple-row insert or update for a non-transactional table, a partial update results. Earlier rows are inserted or updated, but those from the point of the error on are not. To avoid this for non-transactional tables, either use single-row statements or else use STRICT_TRANS_TABLES if conversion warnings rather than errors are acceptable. To avoid problems in the first place, do not use MySQL to check column content. It is safest (and often faster) to let the application ensure that it passes only legal values to the database.
With either of the strict mode options, you can cause errors to be treated as warnings by using INSERT IGNORE or UPDATE IGNORE rather than INSERT or UPDATE without IGNORE.
188.8.131.52. ENUM and SET Constraints
ENUM and SET columns provide an efficient way to define columns that can contain only a given set of values. However, before MySQL 5.0.2, ENUM and SET columns do not provide true constraints on entry of invalid data:
As of MySQL 5.0.2, you can configure the server to use strict SQL mode. See Section 4.2.5, "The Server SQL Mode." With strict mode enabled, the definition of a ENUM or SET column does act as a constraint on values entered into the column. An error occurs for values that do not satisfy these conditions:
Errors for invalid values can be suppressed in strict mode if you use INSERT IGNORE or UPDATE IGNORE. In this case, a warning is generated rather than an error. For ENUM, the value is inserted as the error member (0). For SET, the value is inserted as given except that any invalid substrings are deleted. For example, 'a,x,b,y' results in a value of 'a,b'.