Commit 6e91d6a8 authored by peter@mysql.com's avatar peter@mysql.com

Merge mysql.com:/home/pz/mysql/mysql-4.1-root

into mysql.com:/home/pz/mysql/mysql-4.1
parents ba8c05da 40c0fd1c
......@@ -6957,21 +6957,30 @@ Follow the instructions to install it.
@item
After @code{BitKeeper} is installed, first go to the directory you
want to work from, and then use this command if you want to clone
the MySQL 3.23 branch:
want to work from, and then use one of the following commands to clone
the MySQL version branch of your choice:
To clone the 3.23 branch, use this command:
@example
shell> bk clone bk://work.mysql.com:7000 mysql
shell> bk clone bk://work.mysql.com:7000 mysql-3.23
@end example
To clone the 4.0 branch, use this command instead:
To clone the 4.0 branch, use this command:
@example
shell> bk clone bk://work.mysql.com:7001 mysql-4.0
@end example
In the preceding examples the source tree will be set up in the @file{mysql/}
or @file{mysql-4.0/} subdirectory of your current directory.
To clone the 4.1 branch, use this command:
@example
shell> bk clone bk://work.mysql.com:7004 mysql-4.1
@end example
In the preceding examples the source tree will be set up in the
@file{mysql-3.23/}, @file{mysql-4.0/}, or @file{mysql-4.1/}
subdirectory of your current directory.
The initial download of the source tree may take a while, depending on the
speed of your connection; be patient.
......@@ -8400,7 +8409,7 @@ or @code{myisamchk} for @code{MyISAM} tables (@file{.MYI}) and
@item
If you want your @code{mysqldump} files to be compatible between
MySQL Version 3.22 and Version 3.23, you should not use the
@code{--opt} or @code{--full} option to @code{mysqldump}.
@code{--opt} or @code{--all} option to @code{mysqldump}.
@item
Check all your calls to @code{DATE_FORMAT()} to make sure there is a
......@@ -16051,7 +16060,9 @@ Values in the scope fields may be specified as follows:
@itemize @bullet
@item
The wildcard characters @samp{%} and @samp{_} can be used in the @code{Host}
and @code{Db} fields of either table.
and @code{Db} fields of either table. If you wish to use for instance a
@samp{_} character as part of a database name, specify it as @samp{\_} in
the @code{GRANT} command.
@item
A @code{'%'} @code{Host} value in the @code{db} table means ``any host.'' A
......@@ -16676,6 +16687,13 @@ database privileges by using @code{ON db_name.*} syntax. If you specify
that database. (@strong{Warning}: if you specify @code{ON *} and you
@strong{don't} have a current database, you will affect the global privileges!)
@strong{Please note}: the @samp{_} and @samp{%} wildcards are allowed when
specifying database names in @code{GRANT} commands. This means that if you
wish to use for instance a @samp{_} character as part of a database name,
you should specify it as @samp{\_} in the @code{GRANT} command, to prevent
the user from being able to access additional databases matching the
wildcard pattern, e.g., @code{GRANT ... ON `foo\_bar`.* TO ...}.
In order to accommodate granting rights to users from arbitrary hosts,
MySQL supports specifying the @code{user_name} value in the form
@code{user@@host}. If you want to specify a @code{user} string
......@@ -16684,8 +16702,8 @@ containing special characters or wildcard characters (such as @samp{%}), you
can quote the user or host name (for example, @code{'test-user'@@'test-hostname'}).
You can specify wildcards in the hostname. For example,
@code{user@@"%.loc.gov"} applies to @code{user} for any host in the
@code{loc.gov} domain, and @code{user@@"144.155.166.%"} applies to @code{user}
@code{user@@'%.loc.gov'} applies to @code{user} for any host in the
@code{loc.gov} domain, and @code{user@@'144.155.166.%'} applies to @code{user}
for any host in the @code{144.155.166} class C subnet.
The simple form @code{user} is a synonym for @code{user@@"%"}.
......@@ -17703,7 +17721,7 @@ the @code{mysqlhotcopy script}. @xref{mysqldump, , @code{mysqldump}}.
Do a full backup of your databases:
@example
shell> mysqldump --tab=/path/to/some/dir --opt --full
shell> mysqldump --tab=/path/to/some/dir --opt --all
or
......@@ -19931,7 +19949,7 @@ cache.
The value of the @code{--bdb-home} option.
@item @code{bdb_max_lock}
The maximum number of locks (1000 by default) you can have active on a
The maximum number of locks (10,000 by default) you can have active on a
BDB table. You should increase this if you get errors of type @code{bdb:
Lock table is out of available locks} or @code{Got error 12 from ...}
when you have do long transactions or when @code{mysqld} has to examine
......@@ -20030,15 +20048,15 @@ The maximum length of the word to be included in a @code{FULLTEXT} index.
@strong{Note: @code{FULLTEXT} indexes must be rebuilt after changing
this variable.} (This option is new for MySQL 4.0.)
@item @code{ft_max_word_len_sort}
@item @code{ft_max_word_len_for_sort}
The maximum length of the word in a @code{FULLTEXT} index
to be used in fast index recreation method in @code{REPAIR},
@code{CREATE INDEX}, or @code{ALTER TABLE}. Longer words are inserted the
slow way. The rule of the thumb is as follows: with
@code{ft_max_word_len_sort} increasing, @strong{MySQL} will create bigger
@code{ft_max_word_len_for_sort} increasing, @strong{MySQL} will create bigger
temporary files (thus slowing the process down, due to disk I/O), and will put
fewer keys in one sort block (again, decreasing the efficiency). When
@code{ft_max_word_len_sort} is too small, instead, @strong{MySQL} will insert a
@code{ft_max_word_len_for_sort} is too small, instead, @strong{MySQL} will insert a
lot of words into index the slow way, but short words will be inserted very
quickly.
......@@ -23324,7 +23342,7 @@ If you need better performance when you start using MySQL in a production
environment, you can remove the @code{--log} option from @code{mysql.server}
or change it to @code{--log-bin}. @xref{Binary log}.
The entries in this log are written as @code{mysqld} receives the queries.
The entries in this log are written as @code{mysqld} receives the questions.
This may be different from the order in which the statements are executed.
This is in contrast to the update log and the binary log which are written
after the query is executed, but before any locks are released.
......@@ -23337,7 +23355,7 @@ after the query is executed, but before any locks are released.
@cindex files, update log
@strong{Note}: the update log is replaced by the binary
log. @xref{Binary log}. You can do anything with the binary log that you can do
log. @xref{Binary log}. With this you can do anything that you can do
with the update log.
When started with the @code{--log-update[=file_name]} option,
......@@ -23352,7 +23370,7 @@ flush-logs}, execute the @code{FLUSH LOGS} statement, or restart the server.
@strong{Note}: for the above scheme to work, you must not create
your own files with the same filename as the update log + some extensions
that may be regarded as a number in the directory used by the update log!
that may be regarded as a number, in the directory used by the update log!
If you use the @code{--log} or @code{-l} options, @code{mysqld} writes a
general log with a filename of @file{hostname.log}, and restarts and
......@@ -23396,8 +23414,8 @@ and the crash.
@cindex binary log
@cindex files, binary log
The binary log will replace the now deprecated update log, so
we recommend you to switch to this log format as soon as possible.
The intention is that the binary log should replace the update log, so
we recommend you to switch to this log format as soon as possible!
The binary log contains all information that is available in the update
log in a more efficient format. It also contains information about how long
......@@ -23408,10 +23426,10 @@ find a problem query) you should use the general query log. @xref{Query log}.
The binary log is also used when you are replicating a slave from a master.
@xref{Replication}.
When started with the @code{--log-bin[=file_name]} option @code{mysqld}
When started with the @code{--log-bin[=file_name]} option, @code{mysqld}
writes a log file containing all SQL commands that update data. If no
file name is given it defaults to the name of the host machine followed
by @code{-bin}. If a file name is given, but doesn't contain a path, the
file name is given, it defaults to the name of the host machine followed
by @code{-bin}. If file name is given, but it doesn't contain a path, the
file is written in the data directory.
If you supply an extension to @code{--log-bin=filename.extension}, the
......@@ -23431,9 +23449,14 @@ to the binary log:
@multitable @columnfractions .38 .62
@item @strong{Option} @tab @strong{Description}
@item @code{binlog-do-db=database_name} @tab Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned. (Example: @code{binlog-do-db=some_database})
@item @code{binlog-do-db=database_name} @tab
Tells the master it should log updates for the specified database, and
exclude all others not explicitly mentioned.
(Example: @code{binlog-do-db=some_database})
@item @code{binlog-ignore-db=database_name} @tab Tells the master that updates to the given database should not be logged to the binary log (Example: @code{binlog-ignore-db=some_database})
@item @code{binlog-ignore-db=database_name} @tab
Tells the master that updates to the given database should not be logged
to the binary log (Example: @code{binlog-ignore-db=some_database})
@end multitable
To be able to know which different binary log files have been used,
......@@ -23458,10 +23481,10 @@ shell> mysqlbinlog log-file | mysql -h server_name
@end example
You can also use the @code{mysqlbinlog} program to read the binary log
directly from a remote MySQL server.
directly from a remote MySQL server!
@code{mysqlbinlog --help} will give you more information of how to use
this program.
this program!
If you are using @code{BEGIN [WORK]} or @code{SET AUTOCOMMIT=0}, you must
use the MySQL binary log for backups instead of the old update log.
......@@ -23470,13 +23493,14 @@ The binary logging is done immediately after a query completes but before
any locks are released or any commit is done. This ensures that the log
will be logged in the execution order.
Updates to a non-transactional table are stored in the binary log at
once. For transactional tables such as @code{BDB} ! or @code{InnoDB}
tables, all updates are cached until a @code{COMMIT}. Every thread
will, on start, allocate a buffer of @code{binlog_cache_size} to buffer
queries. If a query is bigger than this, the thread will open a
temporary file to handle the bigger cache. The temporary file will be
deleted when the thread ends.
Updates to non-transactional tables are stored in the binary log
immediately after execution. For transactional tables such as @code{BDB}
or @code{InnoDB} tables, all updates (@code{UPDATE}, @code{DELETE}
or @code{INSERT}) that change tables are cached until a @code{COMMIT}.
Every thread will, on start, allocate a buffer of @code{binlog_cache_size}
to buffer queries. If a query is bigger than this, the thread will open
a temporary file to handle the bigger cache. The temporary file will
be deleted when the thread ends.
The @code{max_binlog_cache_size} can be used to restrict the total size used
to cache a multi-query transaction.
......@@ -23499,10 +23523,10 @@ more than @code{long_query_time} to execute. The time to get the initial
table locks are not counted as execution time.
The slow query log is logged after the query is executed and after all
locks have been released. This may be different from the order in which
locks has been released. This may be different from the order in which
the statements are executed.
If no filename is given, it defaults to the name of the host machine
If no file name is given, it defaults to the name of the host machine
suffixed with @code{-slow.log}. If a filename is given, but doesn't
contain a path, the file is written in the data directory.
......@@ -23512,8 +23536,8 @@ can become a difficult task. You can pipe the slow query log through the
@code{mysqldumpslow} command to get a summary of the queries which
appear in the log.
If you use @code{--log-long-format} also, then queries that do not
use indexes are logged as well. @xref{Command-line options}.
You are using @code{--log-long-format} then also queries that are not
using indexes are printed. @xref{Command-line options}.
@node Log file maintenance, , Slow query log, Log Files
......@@ -23523,19 +23547,22 @@ use indexes are logged as well. @xref{Command-line options}.
@cindex maintaining, log files
@cindex log files, maintaining
MySQL has many log files which makes it easy to see what is going on.
@xref{Log Files}. One must, however, occasionally clean up
after @code{MySQL} to ensure that the logs don't take up too much disk
space by either removing or backing up old log files and then telling MySQL
to start logging to new files. @xref{Backup}.
The MySQL Server can create a number of different log files, which make
it easy to see what is going on. @xref{Log Files}. One must however
regularly clean up these files, to ensure that the logs don't take up
too much disk space.
When using MySQL with log files, you will, from time to time,
want to remove/backup old log files and tell MySQL to start
logging on new files. @xref{Backup}.
On a Linux (@code{Redhat}) installation you can use the
On a Linux (@code{Redhat}) installation, you can use the
@code{mysql-log-rotate} script for this. If you installed MySQL
from an RPM distribution the script should have been installed
automatically. @strong{Note}: you should be careful with this if you are
using the logs for replication.
from an RPM distribution, the script should have been installed
automatically. Note that you should be careful with this if you are using
the log for replication!
On other systems you must install a short script yourself that you can
On other systems you must install a short script yourself that you
start from @code{cron} to handle log files.
You can force MySQL to start using new log files by using
......@@ -24203,7 +24230,7 @@ ignore, use the directive multiple times, once for each database.
You should not use this directive if you are using cross table updates
and you don't want these update to be replicated.
The main reason for this behavior is that it's hard from the command
The main reason for this behaviour is that it's hard from the command
alone know if a query should be replicated or not; For example if you
are using multi-table-delete or multi-table-update commands in MySQL 4.x
that goes across multiple databases. It's also very fast to just check
......@@ -24294,10 +24321,16 @@ summary of commands:
@item @strong{Command} @tab @strong{Description}
@item @code{SLAVE START}
@tab Starts the slave thread. (Slave)
@tab Starts the slave thread.
As of MySQL 4.0.2, you can add @code{IO_THREAD} or @code{SQL_THREAD}
options to the statement to start the I/O thread or the SQL thread.
The I/O thread reads queries from the master server and stores them in the
relay log. The SQL thread reads the relay log and executes the queries.
(Slave)
@item @code{SLAVE STOP}
@tab Stops the slave thread. (Slave)
@tab Stops the slave thread. Like @code{SLAVE START}, this statement
may be used with @code{IO_THREAD} and @code{SQL_THREAD} options. (Slave)
@item @code{SET SQL_LOG_BIN=0}
@tab Disables update logging if the user has the @code{SUPER} privilege.
......@@ -28951,7 +28984,7 @@ A few are reserved because MySQL needs them and is
@c START_OF_RESERVED_WORDS
@c Reserved word list updated Tue Jul 23 20:41:20 2002 by monty.
@c Reserved word list updated Tue Oct 8 13:03:34 2002 by arjen.
@c To regenerate, use Support/update-reserved-words.pl.
@multitable @columnfractions .33 .33 .34
......@@ -28973,38 +29006,41 @@ A few are reserved because MySQL needs them and is
@item @code{BINARY}
@tab @code{BLOB}
@tab @code{BOTH}
@item @code{BY}
@item @code{BTREE}
@tab @code{BY}
@tab @code{CASCADE}
@tab @code{CASE}
@item @code{CHANGE}
@item @code{CASE}
@tab @code{CHANGE}
@tab @code{CHAR}
@tab @code{CHARACTER}
@item @code{COLUMN}
@tab @code{COLUMNS}
@item @code{CHARACTER}
@tab @code{COLLATE}
@tab @code{COLUMN}
@item @code{COLUMNS}
@tab @code{CONSTRAINT}
@item @code{CREATE}
@tab @code{CROSS}
@tab @code{CREATE}
@item @code{CROSS}
@tab @code{CURRENT_DATE}
@item @code{CURRENT_TIME}
@tab @code{CURRENT_TIMESTAMP}
@tab @code{CURRENT_TIME}
@item @code{CURRENT_TIMESTAMP}
@tab @code{DATABASE}
@item @code{DATABASES}
@tab @code{DAY_HOUR}
@tab @code{DATABASES}
@item @code{DAY_HOUR}
@tab @code{DAY_MINUTE}
@item @code{DAY_SECOND}
@tab @code{DEC}
@tab @code{DAY_SECOND}
@item @code{DEC}
@tab @code{DECIMAL}
@item @code{DEFAULT}
@tab @code{DELAYED}
@tab @code{DEFAULT}
@item @code{DELAYED}
@tab @code{DELETE}
@item @code{DESC}
@tab @code{DESCRIBE}
@tab @code{DESC}
@item @code{DESCRIBE}
@tab @code{DISTINCT}
@item @code{DISTINCTROW}
@tab @code{DOUBLE}
@tab @code{DISTINCTROW}
@item @code{DOUBLE}
@tab @code{DROP}
@item @code{ELSE}
@tab @code{ENCLOSED}
@tab @code{ELSE}
@item @code{ENCLOSED}
@tab @code{ERRORS}
@tab @code{ESCAPED}
@item @code{EXISTS}
@tab @code{EXPLAIN}
......@@ -29015,83 +29051,86 @@ A few are reserved because MySQL needs them and is
@item @code{FROM}
@tab @code{FULLTEXT}
@tab @code{FUNCTION}
@item @code{GRANT}
@item @code{GEOMETRY}
@tab @code{GRANT}
@tab @code{GROUP}
@item @code{HASH}
@tab @code{HAVING}
@item @code{HIGH_PRIORITY}
@tab @code{HOUR_MINUTE}
@tab @code{HIGH_PRIORITY}
@item @code{HOUR_MINUTE}
@tab @code{HOUR_SECOND}
@item @code{IF}
@tab @code{IGNORE}
@tab @code{IF}
@item @code{IGNORE}
@tab @code{IN}
@item @code{INDEX}
@tab @code{INFILE}
@tab @code{INDEX}
@item @code{INFILE}
@tab @code{INNER}
@item @code{INNODB}
@tab @code{INSERT}
@tab @code{INNODB}
@item @code{INSERT}
@tab @code{INT}
@item @code{INTEGER}
@tab @code{INTERVAL}
@tab @code{INTEGER}
@item @code{INTERVAL}
@tab @code{INTO}
@item @code{IS}
@tab @code{JOIN}
@tab @code{IS}
@item @code{JOIN}
@tab @code{KEY}
@item @code{KEYS}
@tab @code{KILL}
@tab @code{KEYS}
@item @code{KILL}
@tab @code{LEADING}
@item @code{LEFT}
@tab @code{LIKE}
@tab @code{LEFT}
@item @code{LIKE}
@tab @code{LIMIT}
@item @code{LINES}
@tab @code{LOAD}
@tab @code{LINES}
@item @code{LOAD}
@tab @code{LOCK}
@item @code{LONG}
@tab @code{LONGBLOB}
@tab @code{LONG}
@item @code{LONGBLOB}
@tab @code{LONGTEXT}
@item @code{LOW_PRIORITY}
@tab @code{MASTER_SERVER_ID}
@tab @code{LOW_PRIORITY}
@item @code{MASTER_SERVER_ID}
@tab @code{MATCH}
@item @code{MEDIUMBLOB}
@tab @code{MEDIUMINT}
@tab @code{MEDIUMBLOB}
@item @code{MEDIUMINT}
@tab @code{MEDIUMTEXT}
@item @code{MIDDLEINT}
@tab @code{MINUTE_SECOND}
@tab @code{MIDDLEINT}
@item @code{MINUTE_SECOND}
@tab @code{MRG_MYISAM}
@item @code{NATURAL}
@tab @code{NOT}
@tab @code{NATURAL}
@item @code{NOT}
@tab @code{NULL}
@item @code{NUMERIC}
@tab @code{ON}
@tab @code{NUMERIC}
@item @code{ON}
@tab @code{OPTIMIZE}
@item @code{OPTION}
@tab @code{OPTIONALLY}
@tab @code{OPTION}
@item @code{OPTIONALLY}
@tab @code{OR}
@item @code{ORDER}
@tab @code{OUTER}
@tab @code{ORDER}
@item @code{OUTER}
@tab @code{OUTFILE}
@item @code{PARTIAL}
@tab @code{PRECISION}
@tab @code{PRIMARY}
@item @code{PRIVILEGES}
@item @code{PRIMARY}
@tab @code{PRIVILEGES}
@tab @code{PROCEDURE}
@tab @code{PURGE}
@item @code{READ}
@item @code{PURGE}
@tab @code{READ}
@tab @code{REAL}
@tab @code{REFERENCES}
@item @code{REGEXP}
@item @code{REFERENCES}
@tab @code{REGEXP}
@tab @code{RENAME}
@tab @code{REPLACE}
@item @code{REQUIRE}
@item @code{REPLACE}
@tab @code{REQUIRE}
@tab @code{RESTRICT}
@tab @code{RETURNS}
@item @code{REVOKE}
@item @code{RETURNS}
@tab @code{REVOKE}
@tab @code{RIGHT}
@tab @code{RLIKE}
@item @code{SELECT}
@tab @code{SET}
@item @code{RLIKE}
@tab @code{RTREE}
@tab @code{SELECT}
@item @code{SET}
@tab @code{SHOW}
@item @code{SMALLINT}
@tab @code{SONAME}
@tab @code{SMALLINT}
@item @code{SONAME}
@tab @code{SPATIAL}
@tab @code{SQL_BIG_RESULT}
@item @code{SQL_CALC_FOUND_ROWS}
@tab @code{SQL_SMALL_RESULT}
......@@ -29108,26 +29147,29 @@ A few are reserved because MySQL needs them and is
@item @code{TINYTEXT}
@tab @code{TO}
@tab @code{TRAILING}
@item @code{UNION}
@item @code{TYPES}
@tab @code{UNION}
@tab @code{UNIQUE}
@tab @code{UNLOCK}
@item @code{UNSIGNED}
@item @code{UNLOCK}
@tab @code{UNSIGNED}
@tab @code{UPDATE}
@tab @code{USAGE}
@item @code{USE}
@item @code{USAGE}
@tab @code{USE}
@tab @code{USER_RESOURCES}
@tab @code{USING}
@item @code{VALUES}
@item @code{USING}
@tab @code{VALUES}
@tab @code{VARBINARY}
@tab @code{VARCHAR}
@item @code{VARYING}
@tab @code{WHEN}
@item @code{VARCHAR}
@tab @code{VARYING}
@tab @code{WARNINGS}
@item @code{WHEN}
@tab @code{WHERE}
@item @code{WITH}
@tab @code{WRITE}
@tab @code{WITH}
@item @code{WRITE}
@tab @code{XOR}
@item @code{YEAR_MONTH}
@tab @code{ZEROFILL}
@tab @code{YEAR_MONTH}
@item @code{ZEROFILL}
@tab
@tab
@end multitable
......@@ -31225,7 +31267,7 @@ mysql> SELECT IF(STRCMP('test','test1'),'no','yes');
If @code{expr2} or @code{expr3} is explicitely @code{NULL} then the
result type of the @code{IF()} function is the type of the not
@code{NULL} column. (This behavior is new in MySQL 4.0.3).
@code{NULL} column. (This behaviour is new in MySQL 4.0.3).
@code{expr1} is evaluated as an integer value, which means that if you are
testing floating-point or string values, you should do so using a comparison
......@@ -35001,6 +35043,7 @@ DELAYED} when you are really sure you need it!
UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
SET col_name1=expr1 [, col_name2=expr2, ...]
[WHERE where_definition]
[ORDER BY ...]
[LIMIT #]
@end example
......@@ -36226,10 +36269,8 @@ mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
This will create a @code{MyISAM} table with three columns, a, b, and c.
Notice that the columns from the @code{SELECT} statement are appended to
the right side of the table, not overlapped onto it.
Still, the column from the @code{SELECT} will overlap the column from
the @code{CREATE} clause if they both have the same name. Take the following
examples:
the right side of the table, not overlapped onto it. Take the following
example:
@example
mysql> SELECT * FROM foo;
......@@ -36250,18 +36291,6 @@ mysql> SELECT * FROM bar;
| NULL | 1 |
+------+---+
1 row in set (0.00 sec)
mysql> CREATE TABLE foobar (n FLOAT(3,2), m INT) SELECT n FROM foo;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM foobar;
+------+------+
| n | m |
+------+------+
| 1.00 | NULL |
+------+------+
1 row in set (0.00 sec)
@end example
For each row in table @code{foo}, a row is inserted in @code{bar} with
......@@ -36615,7 +36644,7 @@ deleted due to duplication of unique key values.
The @code{FOREIGN KEY}, @code{CHECK}, and @code{REFERENCES} clauses don't
actually do anything, except for InnoDB type tables which support
@code{ADD CONSTRAINT FOREIGN KEY (...) REFERENCES ... (...)}.
Note that InnoDB does not allow a constraint @code{symbol} or @code{index_name}
Note that InnoDB does not allow an @code{index_name}
to be specified. @xref{InnoDB}.
The syntax for other table types is provided only for compatibility,
to make it easier to port code from other SQL servers and to run applications
......@@ -39268,7 +39297,7 @@ constraints to guard the integrity of your data.
The syntax of a foreign key constraint definition in InnoDB:
@example
FOREIGN KEY (index_col_name, ...)
[CONSTRAINT symbol] FOREIGN KEY (index_col_name, ...)
REFERENCES table_name (index_col_name, ...)
[ON DELETE CASCADE | ON DELETE SET NULL]
@end example
......@@ -39327,7 +39356,7 @@ Starting from version 3.23.50 InnoDB allows you to add a new
foreign key constraint to a table through
@example
ALTER TABLE yourtablename
ADD CONSTRAINT FOREIGN KEY (...) REFERENCES anothertablename(...)
ADD [CONSTRAINT symbol] FOREIGN KEY (...) REFERENCES anothertablename(...)
@end example
Remember to create the required indexes first, though.
......@@ -50833,8 +50862,10 @@ each individual 4.0.x release.
@appendixsubsec Changes in release 4.0.5
@itemize
@item
Give error if one has more than 2 ^ 32 rows in a MyISAM MERGE file and one
has not compiled MySQL with @code{-DBIG_TABLES}.
Small fix in @code{mysqld_safe} for some shells.
@item
Give error if a @code{MyISAM} @code{MERGE} table has more than 2 ^ 32 rows and
MySQL was not compiled with with @code{-DBIG_TABLES}.
@item
Fixed some @code{ORDER BY ... DESC} problems with InnoDB.
@item
......@@ -50854,7 +50885,7 @@ Fixed bug where @code{GRANT}/@code{REVOKE} failed if hostname was given in
not matching case.
@item
Don't give warning in @code{LOAD DATA INFILE} when setting a
@code{timestamp} to a string of '0'.
@code{timestamp} to a string value of @code{'0'}.
@item
Fixed bug in @code{myisamchk -R} mode.
@item
......@@ -50927,7 +50958,7 @@ output in @code{SHOW GRANTS}.
Fixed that @code{mysqld --help} reports correct values for @code{--datadir}
and @code{--bind-address}.
@item
Fixed that one can drop UDFs that didn't exist when mysqld was started.
Fixed that one can drop UDFs that didn't exist when @code{mysqld} was started.
@item
Fixed core dump problem with @code{SHOW VARIABLES} on some 64 bit systems
(like Solaris sparc).
......@@ -51009,7 +51040,7 @@ that can be used as data values in queries.
Changed variable @code{DELAY_KEY_WRITE} to an enum to allow one set
@code{DELAY_KEY_WRITE} for all tables without taking down the server.
@item
Changed behavior of @code{IF(condition,column,NULL)} so that it returns
Changed behaviour of @code{IF(condition,column,NULL)} so that it returns
the value of the column type.
@item
Made @code{safe_mysqld} a symlink to @code{mysqld_safe} in binary distribution.
......@@ -51281,6 +51312,9 @@ Fixed bug in truncation operator for boolean full-text search.
Allow value of @code{--user=#} option for @code{mysqld} to be specified
as a numeric user ID.
@item
Fixed a bug where @code{SQL_CALC_ROWS} returned an incorrect value when used
with one table and @code{ORDER BY} and with @code{InnoDB} tables.
@item
Fixed that @code{SELECT 0 LIMIT 0} doesn't hang thread.
@item
Fixed some problems with @code{USE/IGNORE INDEX} when using
......@@ -51667,6 +51701,8 @@ not yet 100% confident in this code.
@appendixsubsec Changes in release 3.23.53
@itemize @bullet
@item
Small fix in @code{safe_mysqld} for some shells.
@item
Fixed that @code{SHOW STATUS} doesn't reset @code{Delayed_insert_threads}.
@item
Fixed core dump bug when using the @code{BINARY} cast on a @code{NULL} value.
......@@ -21,7 +21,8 @@ static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
ulong max_records);
int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
uint reclength, ulong max_records, ulong min_records)
uint reclength, ulong max_records, ulong min_records,
HP_CREATE_INFO *create_info)
{
uint i, j, key_segs, max_length, length;
HP_SHARE *share;
......@@ -120,6 +121,9 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
share->keys= keys;
share->max_key_length= max_length;
share->changed= 0;
share->auto_key= create_info->auto_key;
share->auto_key_type= create_info->auto_key_type;
share->auto_increment= create_info->auto_increment;
if (!(share->name= my_strdup(name,MYF(0))))
{
my_free((gptr) share,MYF(0));
......
......@@ -537,3 +537,51 @@ my_bool hp_if_null_in_key(HP_KEYDEF *keydef, const byte *record)
}
return 0;
}
void heap_update_auto_increment(HP_INFO *info, const byte *record)
{
ulonglong value;
HA_KEYSEG *keyseg= info->s->keydef[info->s->auto_key - 1].seg;
const uchar *key= (uchar*) record + keyseg->start;
switch (info->s->auto_key_type) {
case HA_KEYTYPE_INT8:
case HA_KEYTYPE_BINARY:
value= (ulonglong) *(uchar*) key;
break;
case HA_KEYTYPE_SHORT_INT:
case HA_KEYTYPE_USHORT_INT:
value= (ulonglong) uint2korr(key);
break;
case HA_KEYTYPE_LONG_INT:
case HA_KEYTYPE_ULONG_INT:
value= (ulonglong) uint4korr(key);
break;
case HA_KEYTYPE_INT24:
case HA_KEYTYPE_UINT24:
value= (ulonglong) uint3korr(key);
break;
case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
{
float f_1;
float4get(f_1, key);
value= (ulonglong) f_1;
break;
}
case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
{
double f_1;
float8get(f_1, key);
value= (ulonglong) f_1;
break;
}
case HA_KEYTYPE_LONGLONG:
case HA_KEYTYPE_ULONGLONG:
value= uint8korr(key);
break;
default:
value= 0; /* Error */
break;
}
set_if_bigger(info->s->auto_increment, value);
}
......@@ -55,5 +55,7 @@ int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x,
x->index_length= info->s->index_length;
x->max_records = info->s->max_records;
x->errkey = info->errkey;
if (flag & HA_STATUS_AUTO)
x->auto_increment= info->s->auto_increment + 1;
DBUG_RETURN(0);
} /* heap_info */
......@@ -37,11 +37,14 @@ int main(int argc, char **argv)
const char *filename;
HP_KEYDEF keyinfo[10];
HA_KEYSEG keyseg[4];
HP_CREATE_INFO hp_create_info;
MY_INIT(argv[0]);
filename= "test1";
get_options(argc,argv);
bzero(&hp_create_info, sizeof(hp_create_info));
keyinfo[0].keysegs=1;
keyinfo[0].seg=keyseg;
keyinfo[0].algorithm= HA_KEY_ALG_HASH;
......@@ -55,7 +58,8 @@ int main(int argc, char **argv)
bzero((gptr) flags,sizeof(flags));
printf("- Creating heap-file\n");
if (heap_create(filename,1,keyinfo,30,(ulong) flag*100000l,10l) ||
if (heap_create(filename,1,keyinfo,30,(ulong) flag*100000l,10l,
&hp_create_info) ||
!(file= heap_open(filename, 2)))
goto err;
printf("- Writing records:s\n");
......
......@@ -63,6 +63,7 @@ int main(int argc, char *argv[])
HP_KEYDEF keyinfo[MAX_KEYS];
HA_KEYSEG keyseg[MAX_KEYS*5];
HEAP_PTR position;
HP_CREATE_INFO hp_create_info;
MY_INIT(argv[0]); /* init my_sys library & pthreads */
LINT_INIT(position);
......@@ -70,6 +71,8 @@ int main(int argc, char *argv[])
filename2= "test2_2";
file=file2=0;
get_options(argc,argv);
bzero(&hp_create_info, sizeof(hp_create_info));
write_count=update=opt_delete=0;
key_check=0;
......@@ -122,7 +125,7 @@ int main(int argc, char *argv[])
printf("- Creating heap-file\n");
if (heap_create(filename,keys,keyinfo,reclength,(ulong) flag*100000L,
(ulong) recant/2) ||
(ulong) recant/2, &hp_create_info) ||
!(file= heap_open(filename, 2)))
goto err;
signal(SIGINT,endprog);
......@@ -557,7 +560,7 @@ int main(int argc, char *argv[])
heap_close(file2);
printf("- Creating output heap-file 2\n");
if (heap_create(filename2,1,keyinfo,reclength,0L,0L) ||
if (heap_create(filename2,1,keyinfo,reclength,0L,0L,&hp_create_info) ||
!(file2= heap_open(filename2, 2)))
goto err;
......
......@@ -22,7 +22,8 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new)
{
HP_KEYDEF *keydef, *end, *p_lastinx;
byte *pos;
HP_SHARE *share=info->s;
bool auto_key_changed= 0;
HP_SHARE *share= info->s;
DBUG_ENTER("heap_update");
test_active(info);
......@@ -33,20 +34,23 @@ int heap_update(HP_INFO *info, const byte *old, const byte *heap_new)
if (--(share->records) < share->blength >> 1) share->blength>>= 1;
share->changed=1;
p_lastinx = share->keydef + info->lastinx;
for (keydef = share->keydef, end = keydef + share->keys; keydef < end;
keydef++)
p_lastinx= share->keydef + info->lastinx;
for (keydef= share->keydef, end= keydef + share->keys; keydef < end; keydef++)
{
if (hp_rec_key_cmp(keydef, old, heap_new))
{
if ((*keydef->delete_key)(info, keydef, old, pos, keydef == p_lastinx) ||
(*keydef->write_key)(info, keydef, heap_new, pos))
goto err;
if (share->auto_key == (uint) (keydef - share->keydef + 1))
auto_key_changed= 1;
}
}
memcpy(pos,heap_new,(size_t) share->reclength);
if (++(share->records) == share->blength) share->blength+= share->blength;
if (auto_key_changed)
heap_update_auto_increment(info, heap_new);
DBUG_RETURN(0);
err:
......
......@@ -61,6 +61,8 @@ int heap_write(HP_INFO *info, const byte *record)
info->current_ptr=pos;
info->current_hash_ptr=0;
info->update|=HA_STATE_AKTIV;
if (share->auto_key)
heap_update_auto_increment(info, record);
DBUG_RETURN(0);
err:
DBUG_PRINT("info",("Duplicate key: %d", keydef - share->keydef));
......
......@@ -50,6 +50,7 @@ typedef struct st_heapinfo /* Struct from heap_info */
ulong index_length;
uint reclength; /* Length of one record */
int errkey;
ulonglong auto_increment;
} HEAPINFO;
......@@ -115,6 +116,9 @@ typedef struct st_heap_share
#endif
my_bool delete_on_close;
LIST open_list;
uint auto_key;
uint auto_key_type; /* real type of the auto key segment */
ulonglong auto_increment;
} HP_SHARE;
struct st_hp_hash_info;
......@@ -140,6 +144,13 @@ typedef struct st_heap_info
LIST open_list;
} HP_INFO;
typedef struct st_heap_create_info
{
uint auto_key;
uint auto_key_type;
ulonglong auto_increment;
} HP_CREATE_INFO;
/* Prototypes for heap-functions */
extern HP_INFO *heap_open(const char *name, int mode);
......@@ -152,7 +163,8 @@ extern int heap_scan(register HP_INFO *info, byte *record);
extern int heap_delete(HP_INFO *info,const byte *buff);
extern int heap_info(HP_INFO *info,HEAPINFO *x,int flag);
extern int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
uint reclength, ulong max_records, ulong min_records);
uint reclength, ulong max_records, ulong min_records,
HP_CREATE_INFO *create_info);
extern int heap_delete_table(const char *name);
extern int heap_extra(HP_INFO *info,enum ha_extra_function function);
extern int heap_rename(const char *old_name,const char *new_name);
......@@ -163,7 +175,7 @@ extern int heap_rprev(HP_INFO *info,byte *record);
extern int heap_rfirst(HP_INFO *info,byte *record,int inx);
extern int heap_rlast(HP_INFO *info,byte *record,int inx);
extern void heap_clear(HP_INFO *info);
extern void heap_update_auto_increment(HP_INFO *info, const byte *record);
ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, const byte *start_key,
uint start_key_len,
enum ha_rkey_function start_search_flag,
......
......@@ -139,14 +139,14 @@ id parent_id level
1015 102 2
1010 102 2
explain select level from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used; Using index
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref level level 1 const 1 where used; Using index
explain select level,id from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used; Using index
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref level level 1 const 1 where used; Using index
explain select level,id,parent_id from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref level level 1 const 1 where used
select level,id from t1 where level=1;
level id
1 1002
......@@ -624,8 +624,8 @@ id parent_id level
1025 102 2
1016 102 2
explain select level from t1 where level=1;
table type possible_keys key key_len ref rows Extra
t1 ref level level 1 const 1 where used; Using index
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref level level 1 const 1 where used; Using index
select level,id from t1 where level=1;
level id
1 1004
......
......@@ -22,14 +22,13 @@ drop table if exists t1,t2;
create table t1 (b char(0) not null, index(b));
The used table handler can't index column 'b'
create table t1 (a int not null auto_increment,primary key (a)) type=heap;
The used table type doesn't support AUTO_INCREMENT columns
create table t1 (a int not null,b text) type=heap;
The used table type doesn't support BLOB/TEXT columns
create table t1 (a int ,primary key(a)) type=heap;
All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead
drop table if exists t1;
create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap;
The used table type doesn't support AUTO_INCREMENT columns
Incorrect table definition; There can only be one auto column and it must be defined as a key
create table t1 (ordid int(8), primary key (ordid));
All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead
create table not_existing_database.test (a int);
......
drop table if exists t1;
create table t1 (a int not null auto_increment,b int, primary key (a)) type=heap auto_increment=3;
insert into t1 values (1,1),(NULL,3),(NULL,4);
delete from t1 where a=4;
insert into t1 values (NULL,5),(NULL,6);
select * from t1;
a b
1 1
3 3
5 5
6 6
delete from t1 where a=6;
replace t1 values (3,1);
ALTER TABLE t1 add c int;
replace t1 values (3,3,3);
insert into t1 values (NULL,7,7);
update t1 set a=8,b=b+1,c=c+1 where a=7;
insert into t1 values (NULL,9,9);
select * from t1;
a b c
1 1 NULL
3 3 3
5 5 NULL
8 8 8
9 9 9
drop table t1;
create table t1 (
skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY,
sval char(20)
) type=heap;
insert into t1 values (NULL, "hello");
insert into t1 values (NULL, "hey");
select * from t1;
skey sval
1 hello
2 hey
select _rowid,t1._rowid,skey,sval from t1;
_rowid _rowid skey sval
1 1 1 hello
2 2 2 hey
drop table t1;
select (select 2);
(select 2)
2
drop table if exists t1,t2,t3,t4,t5,attend,clinic;
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
create table t1 (a int);
create table t2 (a int, b int);
create table t3 (a int);
......@@ -131,6 +131,8 @@ patient_uq clinic_uq
1 1
1 2
2 2
select * from t1 where a= (select a from t2,t4 where t2.b=t4.b);
Column: 'a' in field list is ambiguous
drop table if exists t1,t2,t3;
CREATE TABLE t3 (a varchar(20),b char(1) NOT NULL default '0');
INSERT INTO t3 VALUES ('W','a'),('A','c'),('J','b');
......@@ -147,4 +149,16 @@ W 1
SELECT * FROM t3 WHERE b = (SELECT MIN(b) FROM t3);
a b
W a
drop table t1,t2,t3,t4,t5,attend,clinic;
drop table if exists inscrit;
CREATE TABLE `inscrit` (
`pseudo` varchar(35) character set latin1 NOT NULL default '',
`email` varchar(60) character set latin1 NOT NULL default '',
PRIMARY KEY (`pseudo`),
UNIQUE KEY `email` (`email`)
) TYPE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC;
INSERT INTO inscrit (pseudo,email) VALUES ('joce','test');
INSERT INTO inscrit (pseudo,email) VALUES ('joce1','test1');
INSERT INTO inscrit (pseudo,email) VALUES ('2joce1','2test1');
SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo LIKE '%joce%');
Subselect returns more than 1 record
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
......@@ -22,12 +22,12 @@ drop table if exists t1;
!$1146 create table t2 select auto+1 from t1;
drop table if exists t1,t2;
!$1167 create table t1 (b char(0) not null, index(b));
!$1164 create table t1 (a int not null auto_increment,primary key (a)) type=heap;
create table t1 (a int not null auto_increment,primary key (a)) type=heap;
!$1163 create table t1 (a int not null,b text) type=heap;
!$1171 create table t1 (a int ,primary key(a)) type=heap;
drop table if exists t1;
!$1164 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap;
!$1075 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap;
!$1171 create table t1 (ordid int(8), primary key (ordid));
-- error 1044,1
......
#
# Test of auto_increment; The test for BDB tables is in bdb.test
#
drop table if exists t1;
create table t1 (a int not null auto_increment,b int, primary key (a)) type=heap auto_increment=3;
insert into t1 values (1,1),(NULL,3),(NULL,4);
delete from t1 where a=4;
insert into t1 values (NULL,5),(NULL,6);
select * from t1;
delete from t1 where a=6;
#show table status like "t1";
replace t1 values (3,1);
ALTER TABLE t1 add c int;
replace t1 values (3,3,3);
insert into t1 values (NULL,7,7);
update t1 set a=8,b=b+1,c=c+1 where a=7;
insert into t1 values (NULL,9,9);
select * from t1;
drop table t1;
create table t1 (
skey tinyint unsigned NOT NULL auto_increment PRIMARY KEY,
sval char(20)
) type=heap;
insert into t1 values (NULL, "hello");
insert into t1 values (NULL, "hey");
select * from t1;
select _rowid,t1._rowid,skey,sval from t1;
drop table t1;
select (select 2);
drop table if exists t1,t2,t3,t4,t5,attend,clinic;
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
create table t1 (a int);
create table t2 (a int, b int);
create table t3 (a int);
......@@ -53,6 +53,10 @@ insert into clinic values(1,"Oblastnaia bolnitsa"),(2,"Bolnitsa Krasnogo Kresta"
insert into attend values (1,1),(1,2),(2,2),(1,3);
select * from attend where exists (select * from clinic where uq = clinic_uq);
# not unique fields
-- error 1052
select * from t1 where a= (select a from t2,t4 where t2.b=t4.b);
# different tipes & group functions
drop table if exists t1,t2,t3;
......@@ -66,4 +70,19 @@ SELECT * FROM t1 WHERE b = (SELECT MIN(b) FROM t1);
SELECT * FROM t2 WHERE b = (SELECT MIN(b) FROM t2);
SELECT * FROM t3 WHERE b = (SELECT MIN(b) FROM t3);
drop table t1,t2,t3,t4,t5,attend,clinic;
drop table if exists inscrit;
CREATE TABLE `inscrit` (
`pseudo` varchar(35) character set latin1 NOT NULL default '',
`email` varchar(60) character set latin1 NOT NULL default '',
PRIMARY KEY (`pseudo`),
UNIQUE KEY `email` (`email`)
) TYPE=MyISAM CHARSET=latin1 ROW_FORMAT=DYNAMIC;
INSERT INTO inscrit (pseudo,email) VALUES ('joce','test');
INSERT INTO inscrit (pseudo,email) VALUES ('joce1','test1');
INSERT INTO inscrit (pseudo,email) VALUES ('2joce1','2test1');
-- error 1240
SELECT pseudo FROM inscrit WHERE pseudo=(SELECT pseudo FROM inscrit WHERE pseudo LIKE '%joce%');
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
\ No newline at end of file
......@@ -35,7 +35,9 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
{
if (!(file= heap_open(name, mode)) && my_errno == ENOENT)
{
if (!create(name, table, NULL))
HA_CREATE_INFO create_info;
bzero(&create_info, sizeof(create_info));
if (!create(name, table, &create_info))
file= heap_open(name, mode);
}
return (file ? 0 : 1);
......@@ -51,6 +53,8 @@ int ha_heap::write_row(byte * buf)
statistic_increment(ha_write_count,&LOCK_status);
if (table->time_stamp)
update_timestamp(buf+table->time_stamp-1);
if (table->next_number_field && buf == table->record[0])
update_auto_increment();
return heap_write(file,buf);
}
......@@ -161,6 +165,8 @@ void ha_heap::info(uint flag)
index_file_length=info.index_length;
max_data_file_length= info.max_records* info.reclength;
delete_length= info.deleted * info.reclength;
if (flag & HA_STATUS_AUTO)
auto_increment_value= info.auto_increment;
}
int ha_heap::extra(enum ha_extra_function operation)
......@@ -234,11 +240,11 @@ ha_rows ha_heap::records_in_range(int inx,
}
}
int ha_heap::create(const char *name, TABLE *table,
HA_CREATE_INFO *create_info)
{
uint key, parts, mem_per_row= 0;
uint auto_key= 0, auto_key_type= 0;
ulong max_rows;
HP_KEYDEF *keydef;
HA_KEYSEG *seg;
......@@ -296,19 +302,42 @@ int ha_heap::create(const char *name, TABLE *table,
seg->null_bit= 0;
seg->null_pos= 0;
}
if (field->flags & AUTO_INCREMENT_FLAG)
{
auto_key= key + 1;
auto_key_type= field->key_type();
}
}
}
mem_per_row+= MY_ALIGN(table->reclength + 1, sizeof(char*));
max_rows = (ulong) (current_thd->variables.max_heap_table_size /
mem_per_row);
HP_CREATE_INFO hp_create_info;
hp_create_info.auto_key= auto_key;
hp_create_info.auto_key_type= auto_key_type;
hp_create_info.auto_increment= (create_info->auto_increment_value ?
create_info->auto_increment_value - 1 : 0);
error= heap_create(fn_format(buff,name,"","",4+2),
table->keys,keydef, table->reclength,
((table->max_rows < max_rows && table->max_rows) ?
table->max_rows : max_rows),
table->min_rows);
table->min_rows, &hp_create_info);
my_free((gptr) keydef, MYF(0));
if (file)
info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
ref_length= sizeof(HEAP_PTR);
return (error);
}
void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
{
table->file->info(HA_STATUS_AUTO);
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
create_info->auto_increment_value= auto_increment_value;
}
longlong ha_heap::get_auto_increment()
{
ha_heap::info(HA_STATUS_AUTO);
return auto_increment_value;
}
......@@ -40,8 +40,7 @@ class ha_heap: public handler
ulong table_flags() const
{
return (HA_READ_RND_SAME | HA_NO_INDEX | HA_KEYPOS_TO_RNDPOS |
HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ |
HA_NO_AUTO_INCREMENT);
HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ);
}
ulong index_flags(uint inx) const
{
......@@ -63,6 +62,7 @@ class ha_heap: public handler
int write_row(byte * buf);
int update_row(const byte * old_data, byte * new_data);
int delete_row(const byte * buf);
longlong get_auto_increment();
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
......@@ -87,6 +87,7 @@ class ha_heap: public handler
int delete_table(const char *from);
int rename_table(const char * from, const char * to);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
void update_create_info(HA_CREATE_INFO *create_info);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
......
......@@ -432,7 +432,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (!field) // If field is not checked
{
Field *tmp;
if (!(tmp=find_field_in_tables(thd, this, tables, 0)))
if ((tmp= find_field_in_tables(thd, this, tables, 0)) == not_found_field)
{
/*
We can't find table field in table list of current select,
......@@ -445,14 +445,18 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
*/
SELECT_LEX *last= 0;
for (SELECT_LEX *sl= thd->lex.select->outer_select();
sl && !tmp;
sl;
sl= sl->outer_select())
tmp=find_field_in_tables(thd, this,
(TABLE_LIST*)(last= sl)->table_list.first,
0);
if ((tmp= find_field_in_tables(thd, this,
(TABLE_LIST*)
(last= sl)->table_list.first,
0)) != not_found_field)
break;
if (!tmp)
return -1;
else if (tmp == not_found_field)
{
// Call to produce appropriate error message
// call to return error code
find_field_in_tables(thd, this, tables, 1);
return -1;
}
......@@ -478,7 +482,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
tbl->shared= 1;
}
}
}
}
else if (!tmp)
return -1;
set_field(tmp);
}
else if (thd && thd->set_query_id && field->query_id != thd->query_id)
......@@ -786,7 +793,9 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
if (!ref)
{
if (!(ref= find_item_in_list(this, thd->lex.select->item_list, 0)))
if ((ref= find_item_in_list(this, thd->lex.select->item_list,
REPORT_EXCEPT_NOT_FOUND)) ==
(Item **)not_found_item)
{
/*
We can't find table field in table list of current select,
......@@ -795,17 +804,25 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
of view rules. For example if both tables (outer & current) have
field 'field' it is not mistake to refer to this field without
mention of table name, but if we join tables in one list it will
cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
cause error ER_NON_UNIQ_ERROR in find_item_in_list.
*/
SELECT_LEX *last=0;
for (SELECT_LEX *sl= thd->lex.select->outer_select();
sl && !ref;
sl;
sl= sl->outer_select())
ref= find_item_in_list(this, (last= sl)->item_list, 0);
if((ref= find_item_in_list(this, (last= sl)->item_list,
REPORT_EXCEPT_NOT_FOUND)) !=
(Item **)not_found_item)
break;
if (!ref)
{
return 1;
}
else if (ref == (Item **)not_found_item)
{
// Call to report error
find_item_in_list(this, thd->lex.select->item_list, 1);
find_item_in_list(this, thd->lex.select->item_list, REPORT_ALL_ERRORS);
return 1;
}
else
......@@ -831,6 +848,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
}
}
}
else if (!ref)
return 1;
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
......
......@@ -32,11 +32,22 @@ SUBSELECT TODO:
#include "mysql_priv.h"
#include "sql_select.h"
Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex,
select_subselect *result):
Item_subselect::Item_subselect():
Item(), engine_owner(1), value_assigned(0)
{
DBUG_ENTER("Item_subselect::Item_subselect");
assign_null();
/*
item value is NULL if select_subselect not changed this value
(i.e. some rows will be found returned)
*/
null_value= 1;
}
void Item_subselect::init(THD *thd, st_select_lex *select_lex,
select_subselect *result)
{
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
if (select_lex->next_select())
......@@ -45,12 +56,6 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex,
else
engine= new subselect_single_select_engine(thd, select_lex, result,
this);
assign_null();
/*
item value is NULL if select_subselect not changed this value
(i.e. some rows will be found returned)
*/
null_value= 1;
DBUG_VOID_RETURN;
}
......@@ -83,7 +88,8 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 1;
}
int res= engine->prepare();
fix_length_and_dec();
if (!res)
fix_length_and_dec();
return res;
}
......@@ -99,8 +105,9 @@ inline table_map Item_subselect::used_tables() const
Item_singleval_subselect::Item_singleval_subselect(THD *thd,
st_select_lex *select_lex):
Item_subselect(thd, select_lex, new select_singleval_subselect(this))
Item_subselect()
{
init(thd, select_lex, new select_singleval_subselect(this));
max_columns= 1;
maybe_null= 1;
}
......@@ -119,28 +126,38 @@ Item::Type Item_subselect::type() const
double Item_singleval_subselect::val ()
{
if (engine->exec())
{
assign_null();
return 0;
}
return real_value;
}
longlong Item_singleval_subselect::val_int ()
{
if (engine->exec())
{
assign_null();
return 0;
}
return int_value;
}
String *Item_singleval_subselect::val_str (String *str)
{
if (engine->exec() || null_value)
{
assign_null();
return 0;
}
return &str_value;
}
Item_exists_subselect::Item_exists_subselect(THD *thd,
st_select_lex *select_lex):
Item_subselect(thd, select_lex, new select_exists_subselect(this))
Item_subselect()
{
init(thd, select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX;
null_value= 0; //can't be NULL
maybe_null= 0; //can't be NULL
......@@ -157,21 +174,30 @@ void Item_exists_subselect::fix_length_and_dec()
double Item_exists_subselect::val ()
{
if (engine->exec())
{
assign_null();
return 0;
}
return (double) value;
}
longlong Item_exists_subselect::val_int ()
{
if (engine->exec())
{
assign_null();
return 0;
}
return value;
}
String *Item_exists_subselect::val_str(String *str)
{
if (engine->exec())
{
assign_null();
return 0;
}
str->set(value);
return str;
}
......
......@@ -39,8 +39,7 @@ class Item_subselect :public Item
uint max_columns;
public:
Item_subselect(THD *thd, st_select_lex *select_lex,
select_subselect* result);
Item_subselect();
Item_subselect(Item_subselect *item)
{
null_value= item->null_value;
......@@ -50,6 +49,14 @@ class Item_subselect :public Item
engine_owner= 0;
name= item->name;
}
/*
We need this method, because some compilers do not allow 'this'
pointer in constructor initialization list, but we need pass pointer
to subselect Item class to select_subselect classes constructor.
*/
void init (THD *thd, st_select_lex *select_lex, select_subselect *result);
~Item_subselect();
virtual void assign_null()
{
......
......@@ -457,6 +457,7 @@ bool wait_for_tables(THD *thd);
bool table_is_used(TABLE *table, bool wait_for_name_lock);
bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
void abort_locked_tables(THD *thd,const char *db, const char *table_name);
extern const Field *not_found_field;
Field *find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
bool report_error);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
......@@ -546,7 +547,11 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds, int *error);
Item ** find_item_in_list(Item *item, List<Item> &items, bool report_error);
enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
IGNORE_ERRORS};
extern const Item **not_found_item;
Item ** find_item_in_list(Item *item, List<Item> &items,
find_item_error_report_type report_error);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
List_iterator<Item> *it);
......
......@@ -1781,9 +1781,29 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
return field;
}
// Special Field pointer for find_field_in_tables returning
const Field *not_found_field= (Field*) 0x1;
/*
Find field in table list.
SYNOPSIS
find_field_in_tables()
thd - pointer to current thread structure
item - field item that should be found
tables - tables for scaning
report_error - if FALSE then do not report error if item not found and
return not_found_field;
RETURN VALUES
0 - field is not found or field is not unique, error message is
reported
not_found_field - function was called with report_error == FALSE and
field if not found, no error message reported
found field
*/
Field *
find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables,
find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
bool report_error)
{
Field *found=0;
......@@ -1829,13 +1849,18 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables,
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
table_name=buff;
}
my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),table_name,
thd->where);
if (report_error)
my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
table_name, thd->where);
else
return (Field*) not_found_field;
}
else
if (report_error)
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
item->full_name(),thd->where);
else
return (Field*) not_found_field;
return (Field*) 0;
}
bool allow_rowid= tables && !tables->next; // Only one table
......@@ -1850,11 +1875,10 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables,
return (Field*) 0;
if (found)
{
if (!report_error) // Returns first found
if (!thd->where) // Returns first found
break;
if (report_error)
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
name,thd->where);
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
name,thd->where);
return (Field*) 0;
}
found=field;
......@@ -1865,11 +1889,39 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables,
if (report_error)
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
MYF(0), item->full_name(), thd->where);
else
return (Field*) not_found_field;
return (Field*) 0;
}
// Special Item pointer for find_item_in_list returning
const Item **not_found_item= (const Item**) 0x1;
/*
Find Item in list of items (find_field_in_tables analog)
SYNOPSIS
find_item_in_list()
find - item to find
items - list of items
report_error
REPORT_ALL_ERRORS - report errors, return 0 if error
REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0
IGNORE_ERRORS - do not report errors, return 0 if error
RETURN VALUES
0 - item is not found or item is not unique, error message is
reported
not_found_item - function was called with report_error ==
REPORT_EXCEPT_NOT_FOUND and item if not found, no error
message reported
found field
*/
Item **
find_item_in_list(Item *find, List<Item> &items, bool report_error)
find_item_in_list(Item *find, List<Item> &items,
find_item_error_report_type report_error)
{
List_iterator<Item> li(items);
Item **found=0,*item;
......@@ -1894,7 +1946,7 @@ find_item_in_list(Item *find, List<Item> &items, bool report_error)
{
if ((*found)->eq(item,0))
continue; // Same field twice (Access?)
if (report_error)
if (report_error != IGNORE_ERRORS)
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
find->full_name(), current_thd->where);
return (Item**) 0;
......@@ -1917,10 +1969,17 @@ find_item_in_list(Item *find, List<Item> &items, bool report_error)
break;
}
}
if (!found && report_error)
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
find->full_name(), current_thd->where);
return found;
if (found)
return found;
else if (report_error != REPORT_EXCEPT_NOT_FOUND)
{
if (report_error == REPORT_ALL_ERRORS)
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
find->full_name(), current_thd->where);
return (Item **) 0;
}
else
return (Item **) not_found_item;
}
/****************************************************************************
......
......@@ -6487,7 +6487,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields,
order->in_field_list=1;
return 0;
}
Item **item=find_item_in_list(*order->item, fields, 0);
Item **item= find_item_in_list(*order->item, fields, IGNORE_ERRORS);
if (item)
{
order->item=item; // use it
......@@ -6587,7 +6587,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
thd->set_query_id=1; // Not really needed, but...
for (; new_field ; new_field= new_field->next)
{
if ((item= find_item_in_list(*new_field->item, fields, 0)))
if ((item= find_item_in_list(*new_field->item, fields, IGNORE_ERRORS)))
new_field->item=item; /* Change to shared Item */
else
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment