diff options
176 files changed, 9264 insertions, 5766 deletions
diff --git a/.bzrignore b/.bzrignore index 98d0f5c4bba..ab096c20d6e 100644 --- a/.bzrignore +++ b/.bzrignore @@ -772,3 +772,5 @@ ndb/lib/libNEWTON_BASICTEST_COMMON.so ndb/lib/libREP_API.so ndb/lib/libndbclient.so ndb/lib/libndbclient_extra.so +libmysqld/discover.cc +include/readline diff --git a/BUILD/compile-pentium-max b/BUILD/compile-pentium-max index 4563f5ae827..caf657a2049 100755 --- a/BUILD/compile-pentium-max +++ b/BUILD/compile-pentium-max @@ -9,6 +9,6 @@ extra_configs="$pentium_configs" extra_configs="$extra_configs --with-innodb --with-berkeley-db \ --with-embedded-server --enable-thread-safe-client \ - --with-openssl --with-vio --with-raid" + --with-openssl --with-vio --with-raid --with-ndbcluster" . "$path/FINISH.sh" diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index d844c855de3..52165ee5b7a 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -92,6 +92,7 @@ monty@donna.mysql.fi monty@hundin.mysql.fi monty@mashka.(none) monty@mashka.mysql.fi +monty@mishka.local monty@mishka.mysql.fi monty@mysql.com monty@narttu. diff --git a/Docs/net_doc.txt b/Docs/net_doc.txt index 8a25ef41d06..4f21383c06d 100644 --- a/Docs/net_doc.txt +++ b/Docs/net_doc.txt @@ -1,4 +1,4 @@ - MySQL Client - Server Protocol Ducumentation + MySQL Client/Server Protocol Documentation @@ -6,14 +6,14 @@ Introduction ------------ -This paper has an objective of a through description of the -client - server protocol which is embodied in MySQL. Particularly, +This paper has the objective of presenting a through description +of the client/server protocol that is embodied in MySQL. Particularly, this paper aims to document and describe: - manner in which MySQL server detects client connection requests and creates connection - manner in which MySQL client C API call connects to server - the - entire protocol of sending / receiving data by MySQL server and C API + entire protocol of sending/receiving data by MySQL server and C API code - manner in which queries are sent by client C API calls to server - manner in which query results are sent by server @@ -25,19 +25,22 @@ This paper does not have the goal or describing nor documenting other related MySQL issues, like usage of thread libraries, MySQL standard library set, MySQL strings library and other MySQL specific libraries, type definitions and utilities. - + Issues that are covered by this paper are contained in the following source code files: -- client/net.c and sql/net_serv.c, the two being identical +- libmysql/net.c and sql/net_serv.cc, the two being identical - client/libmysql.c (not entire file is covered) - include/mysql_com.h -- include/mysql.h +- include/mysql.h - sql/mysqld.cc (not entire file is covered) - sql/net_pkg.cc -- sql/sql_base.cc (not entire file is covered) +- sql/sql_base.cc (not entire file is covered) - sql/sql_select.cc (not entire file is covered) -- sql/sql_parse.cc (not entire file is covered) +- sql/sql_parse.cc (not entire file is covered) + +Note: libmysql/net.c was client/net.c prior to MySQL 3.23.11. +sql/net_serv.cc was sql/net_serv.c prior to MySQL 3.23.16. Beside this introduction this paper presents basic definitions, constants, structures and global variables, all related functions in @@ -48,30 +51,30 @@ functioning is described in the last chapter of this paper. Constants, structures and global variables ------------------------------------------ -This chapter will describe all constants, structures and -global variables relevant to client - server protocol. +This chapter will describe all constants, structures and +global variables relevant to client/server protocol. Constants They are important as they contain default values, the ones -that are valied if options are not set in any other way. Beside that +that are valid if options are not set in any other way. Beside that MySQL source code does not contain a single non-defined constant in -it's code. This description of constants does not include +its code. This description of constants does not include configuration and conditional compilation #defines. - -NAME_LEN - field and table name length, current value 64 -HOSTNAME_LENGTH - length of the host name, current value 64 -USERNAME_LENGTH - user name length, current vluae 16 -MYSQL_PORT - default TCP/IP port number, current value 3306 + +NAME_LEN - field and table name length, current value 64 +HOSTNAME_LENGTH - length of the hostname, current value 64 +USERNAME_LENGTH - username length, current value 16 +MYSQL_PORT - default TCP/IP port number, current value 3306 MYSQL_UNIX_ADDR - full path of the default Unix socket file, current value - "/tmp/mysql.sock" + "/tmp/mysql.sock" MYSQL_NAMEDPIPE - full path of the default NT pipe file, current value - "MySQL" -MYSQL_SERVICENAME - name of the MySQL Service on NT, current value "MySql" + "MySQL" +MYSQL_SERVICENAME - name of the MySQL Service on NT, current value "MySQL" NET_HEADER_SIZE - size of the network header, when no - compression is used, current value 4 + compression is used, current value 4 COMP_HEADER_SIZE - additional size of network header when - compression is used, current value 3 + compression is used, current value 3 What follows are set of constants, defined in source only, which define capabilities of the client built with that version of C @@ -79,601 +82,588 @@ API. Simply, when some new feature is added in client, that client feature is defined, so that server can detect what capabilities a client program has. -CLIENT_LONG_PASSWORD - client supports new more secure passwords -CLIENT_LONG_FLAG - client uses longer flags -CLIENT_CONNECT_WITH_DB - client can specify db on connect -CLIENT_COMPRESS - client can use compression protocol -CLIENT_ODBC - ODBC client -CLIENT_LOCAL_FILES - client can use LOAD DATA INFILE LOCAL -CLIENT_IGNORE_SPACE - client can Ignore spaces before '(' -CLIENT_CHANGE_USER - client supports the mysql_change_user() +CLIENT_LONG_PASSWORD - client supports new more secure passwords +CLIENT_LONG_FLAG - client uses longer flags +CLIENT_CONNECT_WITH_DB - client can specify db on connect +CLIENT_COMPRESS - client can use compression protocol +CLIENT_ODBC - ODBC client +CLIENT_LOCAL_FILES - client can use LOAD DATA INFILE LOCAL +CLIENT_IGNORE_SPACE - client can ignore spaces before '(' +CLIENT_CHANGE_USER - client supports the mysql_change_user() What follows are other constants, pertaining to timeouts and sizes -MYSQL_ERRMSG_SIZE - maximum size of error message string, current value 200 -NET_READ_TIMEOUT - read timeout, current value 30 sec. -NET_WRITE_TIMEOUT - write timeout, current value 60 sec. -NET_WAIT_TIMEOUT - wait for new query timeout, current value 8*60*60 - sec. i.e. 8 hours -packet_error - value returned in case of socket errors, current - value -1 -TES_BLOCKING - used in debug mode for setting up blocking testing -RETRY COUNT - number of times network read and write will be - retried, current value 1 +MYSQL_ERRMSG_SIZE - maximum size of error message string, current value 200 +NET_READ_TIMEOUT - read timeout, current value 30 seconds +NET_WRITE_TIMEOUT - write timeout, current value 60 seconds +NET_WAIT_TIMEOUT - wait for new query timeout, current value 8*60*60 + seconds, that is, 8 hours +packet_error - value returned in case of socket errors, current + value -1 +TES_BLOCKING - used in debug mode for setting up blocking testing +RETRY COUNT - number of times network read and write will be + retried, current value 1 There are also error messages for last_errno, which depict system errors, and are used on the server only. -ER_NET_PACKAGE_TOO_LARGE - packet is larger then max_allowed_packet -ER_OUT_OF_RESOURCES - practically no more memory +ER_NET_PACKAGE_TOO_LARGE - packet is larger than max_allowed_packet +ER_OUT_OF_RESOURCES - practically no more memory ER_NET_ERROR_ON_WRITE - error in writing to NT Named Pipe ER_NET_WRITE_INTERRUPTED - some signal or interrupt happened during write -ER_NET_READ_ERROR_FROM_PIPE - error in reading from NT Named Pipe -ER_NET_FCNTL_ERROR - error in trying to set fcntl on socket +ER_NET_READ_ERROR_FROM_PIPE - error in reading from NT Named Pipe +ER_NET_FCNTL_ERROR - error in trying to set fcntl on socket descriptor ER_NET_PACKETS_OUT_OF_ORDER - packet numbers on client and server side differ ER_NET_UNCOMPRESS_ERROR - error in uncompress of compressed packet - - Structs and eunms + + Structs and enums struct NET -this is MySQL's network handle structure, used in all client / server -read/write functions. On the server it is initialized and preserved in -each thread. On the client, it is a part of MYSQL struct, which is -MySQL handle used in all C API functions. This structure uniquely -identifies a connection, either on the server or client side. -This structure consists of the following -fields: - - Vio* vio; - explained above - HANDLE hPipe - Handle for NT Named Pipe file - my_socket fd - file descriptor used for both tcp socket and Unix socket file - int fcntl - contains info on fcntl options used on fd. Mostly - used for saving info if blocking is used or not - unsigned char *buff - network buffer used for storing data for - reading from / writing to socket - unsigned char,*buff_end - points to the end of buff - unsigned char *write_pos - present writing position in buff - unsigned char *read_pos - present reading postiion in - buff. This pointer is used for - reading data after calling - my_net_read function and function - that are just it's wrappers - char last_error[MYSQL_ERRMSG_SIZE] - holds last error message - unsigned int last_errno - holds last error code of the network - protocol. It's ossible values are - listed in above constants. It is - used only on the server side - unsigned int max_packet - holds current value of buff size - unsigned int timeout - stores read timeout value for that connection - unsigned int pkt_nr - stores a value of the current packet - number in a batch of packets. Used - primarily for detection of protocol - errors resulting in a mismatch - my_bool error - holds either 1 or 0 depending on the error condition - my_bool return_errno - if it's value != 0 then there is an - error in protocol mismatch between - client and server - my_bool compress - if true compression is used in the protocol - unsigned long remain_in_buf - used only in reading compressed - packets. Explained in my_net_read - unsigned long length - used only for storing a length of the - read packet. Explained in my_net_read - unsigned long buf_length - used only in reading compressed - packets. Explained in my_net_read - unsigned long where_b - used only in reading compressed - packets. Explained in my_net_read - short int more - used for reporting in mysql_list_processes - char save_char - used in reading compressed packets for saving - chars in order to make zero-delimited - strings. Explained in my_net_read - -Few typedefs will be defined for easier understanding of the text that +This is MySQL's network handle structure, used in all client/server +read/write functions. On the server, it is initialized and preserved +in each thread. On the client, it is a part of the MYSQL struct, +which is the MySQL handle used in all C API functions. This structure +uniquely identifies a connection, either on the server or client +side. It consists of the following fields: + + Vio* vio - explained above + HANDLE hPipe - Handle for NT Named Pipe file + my_socket fd - file descriptor used for both TCP/IP socket and + Unix socket file + int fcntl - contains info on fcntl options used on fd. Mostly + used for saving info if blocking is used or not + unsigned char *buff - network buffer used for storing data for + reading from/writing to socket + unsigned char,*buff_end - points to the end of buff + unsigned char *write_pos - present writing position in buff + unsigned char *read_pos - present reading position in buff. This + pointer is used for reading data after + calling my_net_read function and function + that are just its wrappers + char last_error[MYSQL_ERRMSG_SIZE] - holds last error message + unsigned int last_errno - holds last error code of the network + protocol. Its possible values are listed + in above constants. It is used only on + the server side + unsigned int max_packet - holds current value of buff size + unsigned int timeout - stores read timeout value for that connection + unsigned int pkt_nr - stores the value of the current packet number in + a batch of packets. Used primarily for + detection of protocol errors resulting in a + mismatch + my_bool error - holds either 1 or 0 depending on the error condition + my_bool return_errno - if its value != 0 then there is an error in + protocol mismatch between client and server + my_bool compress - if true compression is used in the protocol + unsigned long remain_in_buf - used only in reading compressed packets. + Explained in my_net_read + unsigned long length - used only for storing the length of the read + packet. Explained in my_net_read + unsigned long buf_length - used only in reading compressed packets. + Explained in my_net_read + unsigned long where_b - used only in reading compressed packets. + Explained in my_net_read + short int more - used for reporting in mysql_list_processes + char save_char - used in reading compressed packets for saving chars + in order to make zero-delimited strings. Explained + in my_net_read + +A few typedefs will be defined for easier understanding of the text that follows. - typedef char **MYSQL_ROW - data containing one row of values - typedef unsigned int MYSQL_FIELD_OFFSET - offset in bytes of - the current field - typedef MYSQL_ROWS *MYSQL_ROW_OFFSET - offset in bytes of - the current row +typedef char **MYSQL_ROW - data containing one row of values +typedef unsigned int MYSQL_FIELD_OFFSET - offset in bytes of the current field - struct MYSQL_FIELD - contains all info on the attributes of a +typedef MYSQL_ROWS *MYSQL_ROW_OFFSET - offset in bytes of the current row + +struct MYSQL_FIELD - contains all info on the attributes of a specific column in a result set, plus info on lengths of the column in a result set. This struct is tagged as st_mysql_field. This structure consists of the following fields: - char *name - name of column - char *table - table of column if column was a field and not - expression or constant - char *def - default value (set by mysql_list_fields) - enum enum_field_types type - see above - unsigned int length - width of column in a current row - unsigned int max_length - maximum width of that column in - entire result set - unsigned int flags - corresponding to Extra in DESCRIBE - unsigned int decimals - number of decimals in field + char *name - name of column + char *table - table of column if column was a field and not + an expression or constant + char *def - default value (set by mysql_list_fields) + enum enum_field_types type - see above + unsigned int length - width of column in the current row + unsigned int max_length - maximum width of that column in entire + result set + unsigned int flags - corresponding to Extra in DESCRIBE + unsigned int decimals - number of decimals in field - struct MYSQL_ROWS - a node for each row in the single linked +struct MYSQL_ROWS - a node for each row in the single linked list forming entire result set. This struct is tagged as st_mysql_rows, and has two fields: - struct st_mysql_rows *next - pointer to a next one - MYSQL_ROW data - see above + struct st_mysql_rows *next - pointer to the next one + MYSQL_ROW data - see above - struct MYSQL_DATA - contains all rows from result set. It is +struct MYSQL_DATA - contains all rows from result set. It is tagged as st_mysql_data and has following fields: - my_ulonglong rows - how many rows - unsigned int fields - how many columns - MYSQL_ROWS *data - see above. This is a first node of the - linked list - MEM_ROOT alloc - MEM_ROOT is MySQL memory allocation - structure, and this field is used to store - all fields and rows. + my_ulonglong rows - how many rows + unsigned int fields - how many columns + MYSQL_ROWS *data - see above. This is the first node of the linked list + MEM_ROOT alloc - MEM_ROOT is MySQL memory allocation structure, and + this field is used to store all fields and rows. + - - struct st_mysql_options - holds various client options, and +struct st_mysql_options - holds various client options, and contains following fields: - unsigned int connect_timeout - time in sec. for cennection - unsigned int client_flag - used to cold client capabilities - my_bool compress - boolean for compression - my_bool named_pipe - is Named Pipe used on NT - unsigned int port - what TCP port is used - char *host - host to connect to - char *init_command - command to be executed upon connection - char *user - account name on MySQL server - char *password - password for the above - char *unix_socket - full path for Unix socket file - char *db - default database - char *my_cnf_file - optional configuration file - char *my_cnf_group - optional header for options - - - struct MYSQL - MySQL client's handle. Required for any -operation issed from client to server. Tagged as st_mysql and having + unsigned int connect_timeout - time in seconds for connection + unsigned int client_flag - used to hold client capabilities + my_bool compress - boolean for compression + my_bool named_pipe - is Named Pipe used? (on NT) + unsigned int port - what TCP port is used + char *host - host to connect to + char *init_command - command to be executed upon connection + char *user - account name on MySQL server + char *password - password for the above + char *unix_socket - full path for Unix socket file + char *db - default database + char *my_cnf_file - optional configuration file + char *my_cnf_group - optional header for options + + +struct MYSQL - MySQL client's handle. Required for any +operation issued from client to server. Tagged as st_mysql and having following fields: - NET net - see above - char *host - host on which MySQL server is running - char *user - MySQL user name - char *passwd - password for above - char *unix_socket- full path of Unix socket file - char *server_version - version of the server - char *host_info - contains info on how has connection been - established, TCP port, socket or Named Pipe - char *info - used to store information on the query results, - like number of rows affected etc. - char *db - current database - unsigned int port -= TCP port in use - unsigned int client_flag - client capabilities - unsigned int server_capabilities - server capabilities - unsigned int protocol_version - version of the protocl - unsigned int field_count - used for storing number of fields - immidiately upon execution of a - query, but before fetching rows - unsigned long thread_id - server thread to which this connection is attached - my_ulonglong affected_rows - used for storing number of rows - immidiately upon execution of a - query, but before fetching rows - my_ulonglong insert_id - fetching LAST_INSERT_ID() through - client C API - my_ulonglong extra_info - used by mysqlshow - unsigned long packet_length - saving size of the first packet - upon execution of a query - enum mysql_status status - see above - MYSQL_FIELD *fields - see above - MEM_ROOT field_alloc - memory used for storing previous field - (fields) - my_bool free_me - boolean that flags if MYSQL was allocated in - mysql_init - my_bool reconnect - used to automatically reconnect - struct st_mysql_options options - see above - char scramble_buff[9] - key for scrambling password before - sending it to server - - - struct MYSQL_RES - tagged as st_mysql_res and used to store + NET net - see above + char *host - host on which MySQL server is running + char *user - MySQL username + char *passwd - password for above + char *unix_socket- full path of Unix socket file + char *server_version - version of the server + char *host_info - contains info on how has connection been + established, TCP port, socket or Named Pipe + char *info - used to store information on the query results, + like number of rows affected etc. + char *db - current database + unsigned int port - TCP port in use + unsigned int client_flag - client capabilities + unsigned int server_capabilities - server capabilities + unsigned int protocol_version - version of the protocol + unsigned int field_count - used for storing number of fields + immediately upon execution of a query, + but before fetching rows + unsigned long thread_id - server thread to which this connection + is attached + my_ulonglong affected_rows - used for storing number of rows + immediately upon execution of a query, + but before fetching rows + my_ulonglong insert_id - fetching LAST_INSERT_ID() through client C API + my_ulonglong extra_info - used by mysqlshow +unsigned long packet_length - saving size of the first packet upon + execution of a query + enum mysql_status status - see above + MYSQL_FIELD *fields - see above + MEM_ROOT field_alloc - memory used for storing previous field (fields) + my_bool free_me - boolean that flags if MYSQL was allocated in mysql_init + my_bool reconnect - used to automatically reconnect + struct st_mysql_options options - see above + char scramble_buff[9] - key for scrambling password before sending it + to server + + +struct MYSQL_RES - tagged as st_mysql_res and used to store entire result set from a single query. Contains following fields: - my_ulonglong row_count - number of rows - unsigned int field_count - number of columns - unsigned int current_field - cursor for fetching fields - MYSQL_FIELD *fields - see above - MYSQL_DATA *data - see above, and used in buffered reads, - i.e. mysql_store_result only - MYSQL_ROWS *data_cursor - pointing to the field of above "data" - MEM_ROOT field_alloc - memory allocation for above "fields" - MYSQL_ROW row - used for storing row by row in unbuffered - reads, i.e. in mysql_use_result - MYSQL_ROW current_row - cursor to the current row for buffered - reads - unsigned long *lengths - column lengths of current row - MYSQL *handle - see above, used in unbuffered reads, i.e. in - mysql_use_resultq - my_bool eof - used my mysql_fetch_row as a marker for end of data + my_ulonglong row_count - number of rows + unsigned int field_count - number of columns + unsigned int current_field - cursor for fetching fields + MYSQL_FIELD *fields - see above + MYSQL_DATA *data - see above, and used in buffered reads, that is, + mysql_store_result only + MYSQL_ROWS *data_cursor - pointing to the field of above "data" + MEM_ROOT field_alloc - memory allocation for above "fields" + MYSQL_ROW row - used for storing row by row in unbuffered reads, + that is, in mysql_use_result + MYSQL_ROW current_row - cursor to the current row for buffered reads + unsigned long *lengths - column lengths of current row + MYSQL *handle - see above, used in unbuffered reads, that is, in + mysql_use_result + my_bool eof - used by mysql_fetch_row as a marker for end of data + Global variables - Global variables +unsigned long max_allowed_packet - maximum allowable value of network + buffer. Default value - 1MB - unsigned long max_allowed_packet - maximum allowable value of - network buffer. Default - value - 1 Mb +unsigned long net_buffer_length - default, starting value of network + buffer - 8KB - unsigned long net_buffer_length - default, starting value of - network buffer - 8 Kb +unsigned long bytes_sent - total number of bytes written since startup + of the server - unsigned long bytes_sent - total number of bytes written since - startup of the server +unsigned long bytes_received - total number of bytes read since startup + of the server - unsigned long bytes_received - total number of bytes read - since startup of the server +Synopsis of the basic client/server protocol +-------------------------------------------- - Synopsis of the basic client - server protocol - ---------------------------------------------- - - Purpose of this chapter is to provide a complete picture of -the basic client - server protocol implemented in MySQL. It was felt -it is necessary after writting descriptions for all of the functions +Purpose of this chapter is to provide a complete picture of +the basic client/server protocol implemented in MySQL. It was felt +it is necessary after writing descriptions for all of the functions involved in basic protocol. There are at present 11 functions involved, with several structures, many constants etc, which are all -described in detail. But as a forest could not be seen from the trees, -so a concept of the protocol could not be deciphered easily from a -thourough documentation on minutae. +described in detail. But as a forest could not be seen from the trees, +so the concept of the protocol could not be deciphered easily from a +thorough documentation of minutiae. - Althouch concept of the protocol was not changed with the +Although the concept of the protocol was not changed with the introduction of vio system, embodied in violate.cc source file and VIO -system, the introduction of these has changed a code substantially. Before -VIO was introduced, functions for reading from / writing to network +system, the introduction of these has changed the code substantially. Before +VIO was introduced, functions for reading from/writing to network connection had to deal with various network standards. So, these functions depended on whether TCP port or Unix socket file or NT Named Pipe file is used. This is all changed now and single vio_ functions are called, while all this diversity is covered by vio_ functions. - In MySQL a specific buffered network input / output transport -model has been implemented. Although each operating system mah have -it's own buffering for network connections, MySQL has added it's own +In MySQL a specific buffered network input/output transport model +has been implemented. Although each operating system may have its +own buffering for network connections, MySQL has added its own buffering model. This same for each of the three transport protocol -types that are used in MySQL client - server communications, which are -tcp sockets (on all systems), Unix socket files on Unix and Unix-like -operating systems and Named Pipe files on NT. Alghouth tcp sockets -are omnipresent, the later two types have been added for local -connections. Those two connection types can be used in local modes -only, i.e. when both client and server reside on the same host, and -are introduced because they enable better speeds for local -connections. This is especially usefull for WWW type of -applications. Startup options of MySQl server allow that either tcp -sockets or local connection (OS dependent) can be disallowed. - - In order to be able to implement buffered input / output MySQL -allocates a buffer. A starting size of this buffer is determined by a -value of the global variable net_buffer_length, which can be changed -at MySQL server startup. This is, as explained only a startup length -of MySQL network buffer. As a signle item that has to be read / -written can be larger then that value, MySQL will increase buffer size -as long as that size reaches value of global variable -max_aallowed_packet, which is also settable at server startup. Maximum -value of this variable is limited by the way MySQL stores / reads -sizes of packets to be sent / read, which means by the way MySQL +types that are used in MySQL client/server communications, which +are TCP/IP sockets (on all systems), Unix socket files on Unix and +Unix-like operating systems and Named Pipe files on NT. Although +TCP/IP sockets are omnipresent, the latter two types have been added +for local connections. Those two connection types can be used in +local mode only, that is, when both client and server reside on the +same host, and are introduced because they enable better speeds for +local connections. This is especially useful for WWW type of +applications. Startup options of MySQL server allow that either +TCP/IP sockets or local connection (OS dependent) can be disallowed. + +In order to implement buffered input/output, MySQL allocates a +buffer. The starting size of this buffer is determined by the value +of the global variable net_buffer_length, which can be changed at +MySQL server startup. This is, as explained, only the startup length +of MySQL network buffer. Because a single item that has to be read +or written can be larger than that value, MySQL will increase buffer +size as long as that size reaches value of the global variable +max_allowed_packet, which is also settable at server startup. Maximum +value of this variable is limited by the way MySQL stores/reads +sizes of packets to be sent/read, which means by the way MySQL formats packages. - Basically each packet consists of two parts, a header and -data. In the case when compression is not used, header consists of 4 -bytes of which 3 contain a length of the packet to be sent and one -holds a packet number. When compression is used there are -onother 3 bytes which store a size of uncompressed data. Because of -the way MySQL packs length into 3 bytes, plus due to the usage of some +Basically each packet consists of two parts, a header and data. In +the case when compression is not used, header consists of 4 bytes +of which 3 contain the length of the packet to be sent and one holds +the packet number. When compression is used there are onother 3 +bytes which store the size of uncompressed data. Because of the way +MySQL packs length into 3 bytes, plus due to the usage of some special values in the most significant byte, maximum size of -max_allowed_packet is limited to 24 Mb at present. So, if compression -is not used, at first 4 bytes are written to the buffer and then data -itself. As MySQL buffers I/O logical packets are packet together until -packets fill up entire size of the buffer. That size no less then -net_buffer_size, but no greater then max_allowed_packet. So, actuall -writting to the network is done when this buffer is filled up. As -frequently sequence of buffers make a logicall unit, like a result -set, then at the end of sending data, even if buffer is not full, data -is written, i.e. flushed to the connection with a call of the -net_flush function. In order to maintain that no single packet can be -larger then this value, checks are made throughout a code, so that not -signle field or command could exceed that value. - - In order to maintain coherency in consicutive packets, each -packet is numbered and their number stored as a part of a header, as -explained above. Packets start with 0, so whenever a logical packet is -written, that number is incremented. On the other side when packets -are read, value that is fetched is compared with a value stored and if -there is no mismatch that value is incremented too. Packet number is -reset on the client side when unwanted connections are removed from -the connection and on the server side when a new command hsa been -started. - - - So, before writting, a buffer contains a sequence of logical -packets, consisting of header plus data consequtively. In the case -that compression is used, packet numbers are not stored in each header -of the logical packets, but a whole buffer, or a part of it if -flushing is done, containing one or more logical packets are -compressed. In that case a new larger header, is formed, and all -logical packets contained in the buffer are compressed together. This -way only one packet is formed which makes several logical packets, -which improves both speed and compression ratio. On the other side, -when this large compressed packet is read, it is furst uncompressed, -and then logical packets are sent, one by one, to the calling -functions. - - - All this functionality is described in detail in the following +max_allowed_packet is limited to 24MB at present. So, if compression +is not used, at first 4 bytes are written to the buffer and then +data itself. As MySQL buffers I/O logical packets are packet together +until packets fill up entire size of the buffer. That size no less +than net_buffer_size, but no greater than max_allowed_packet. So, +actual writing to the network is done when this buffer is filled +up. As frequently sequence of buffers make a logical unit, like a +result set, then at the end of sending data, even if buffer is not +full, data is written (flushed to the connection) with a call of +the net_flush function. So that no single packet can be larger than +this value, checks are made throughout the code to make sure that +no single field or command could exceed that value. + +In order to maintain coherency in consecutive packets, each packet +is numbered and their number stored as a part of a header, as +explained above. Packets start with 0, so whenever a logical packet +is written, that number is incremented. On the other side when +packets are read, value that is fetched is compared with the value +stored and if there is no mismatch that value is incremented, too. +Packet number is reset on the client side when unwanted connections +are removed from the connection and on the server side when a new +command has been started. + + +So, before writing, the buffer contains a sequence of logical +packets, consisting of header plus data consecutively. If compression +is used, packet numbers are not stored in each header of the logical +packets, but a whole buffer, or a part of it if flushing is done, +containing one or more logical packets are compressed. In that case +a new larger header, is formed, and all logical packets contained +in the buffer are compressed together. This way only one packet is +formed which makes several logical packets, which improves both +speed and compression ratio. On the other side, when this large +compressed packet is read, it is first uncompressed, and then logical +packets are sent, one by one, to the calling functions. + + +All this functionality is described in detail in the following chapter. It does not contain functions that form logical packets, or that read and write to connections but also functions that are used -for initialisation, clearing of connections. There are functions at +for initialization, clearing of connections. There are functions at higher level dealing with sending fields, rows, establishing connections, sending commands, but those are not explained in the following chapter. - - Functions utilized in client - server protocol - ---------------------------------------------- - First of all, functions are described that are involved in -praparing/ reading / writing data over TCP port , socket or named pipe -file, and functions directly related to those. All of these functions +Functions utilized in client/server protocol +-------------------------------------------- + +First of all, functions are described that are involved in preparing, +reading, or writing data over TCP port, Unix socket file, or named +pipe, and functions directly related to those. All of these functions are used both in server and client. Server and client specific code -segments will be documented in each function description. Each MySQl -function checks for errors in memory allocation / freeing, as well as -in every OS call, like the one dealing with files and sockets, and for -errors in indeginous MySQL function calls. This is expected, but has -to be said, as not to repeat it in every function description. +segments are documented in each function description. - Older versions of MySQL have utilized the following macros for -reading from / writing to socket. +Each MySQL function checks for errors in memory allocation and +freeing, as well as in every OS call, like the one dealing with +files and sockets, and for errors in indigenous MySQL function +calls. This is expected, but has to be said here so as not to repeat +it in every function description. - raw_net_read - calls OS function recv function that reads N - bytes from a socket into a buffer. Number of - bytes read is returned. +Older versions of MySQL have utilized the following macros for +reading from or writing to a socket. - raw_net_write - calls OS funciton send to write N bytes from - a buffer to socket. Number of bytes written - is returned. +raw_net_read - calls OS function recv function that reads N bytes +from a socket into a buffer. Number of bytes read is returned. - These macros are replaced with VIO (Virtual I/O) functions. +raw_net_write - calls OS function send to write N bytes from a +buffer to socket. Number of bytes written is returned. +These macros are replaced with VIO (Virtual I/O) functions. - Function name: my_net_init - - Parameters: struct NET *, enum_net_type, struct Vio - Return value : 1 for error, 0 for success +Function name: my_net_init - Function purpose: To initialize properly all NET fields, - allocate memory and set socket options +Parameters: struct NET *, enum_net_type, struct Vio - Function description +Return value: 1 for error, 0 for success - First of all, buff field of NET struct is allocated to the -size of net_buffer_lenght, and on failure function exits with 0. All -fields in NET are set to their default or starting values. As -net_buffer_length and max_allowed_packet are configurable, -max_allowed_packet is set equal to net_buffer_length it the later one -is greater. max_packet if set for that NET to net_buffer_lenght, and -buff_end points to buff end. vio feild is set to the second parameter. -If it is a real connection, which is a case when second parameter is -not null, then fd field is set by calling vio_fd function.read_pos and +Function purpose: To initialize properly all NET fields, + allocate memory and set socket options + +Function description + +First of all, buff field of NET struct is allocated to the size of +net_buffer_length, and on failure function exits with 0. All fields +in NET are set to their default or starting values. As net_buffer_length +and max_allowed_packet are configurable, max_allowed_packet is set +equal to net_buffer_length if the latter one is greater. max_packet +is set for that NET to net_buffer_length, and buff_end points to +buff end. vio field is set to the second parameter. If it is a +real connection, which is the case when second parameter is not +null, then fd field is set by calling vio_fd function. read_pos and write_pos to buff, while remaining integers are set to 0. If function -is run on the MySQL server on Unix and server is started in a test +is run on the MySQL server on Unix and server is started in a test mode that would require testing of blocking, then vio_blocking function is called. Last, fast throughput mode is set by a call to vio_fastsend function. - - Function name: net_end - - Parameters: struct NET * +Function name: net_end + +Parameters: struct NET * + +Return value: void - Return value : void +Function purpose: To release memory allocated to buff - Function purpose: To release memory alloceted to buff - - Function name: net_realloc (private, static function) - - Parameters: struct NET, unlong (unsigned long) +Function name: net_realloc (private, static function) - Return value : 1 for error, 0 for success +Parameters: struct NET, ulong (unsigned long) - Function purpose: To change memory allocated to buff +Return value: 1 for error, 0 for success - Function description +Function purpose: To change memory allocated to buff - New length of buff field of NET struct is passed as second -parameter. It is first checked versus max_allowd_packet and if greater -error is returned. New length is aligned to 4096 boundary. Then , buff -is reallocated, buff_end, max_packet and write_pas reset to the same -values as in my_net_init. +Function description +New length of buff field of NET struct is passed as second parameter. +It is first checked versus max_allowed_packet and if greater, an +error is returned. New length is aligned to 4096-byte boundary. Then, +buff is reallocated, buff_end, max_packet, and write_pas reset to +the same values as in my_net_init. - Function name: net_clear (used on client side only) - - Parameters: struct NET * - Return value : void +Function name: net_clear (used on client side only) - Function purpose: To read unread packets +Parameters: struct NET * - Function description +Return value: void - This function is used on client side only, and is executed +Function purpose: To read unread packets + +Function description + +This function is used on client side only, and is executed only if a program is not started in test mode. This function reads unread packets without processing them. First, non-blocking mode is -set on systems that have not non-blocking mode defined. This is -performed by checking a mode with vio_is_blocking function. and +set on systems that do not have non-blocking mode defined. This is +performed by checking the mode with vio_is_blocking function. and setting non-blocking mode by vio_blocking function. If this operation -was successfull, then packets are read by vio_read function, to which +was successful, then packets are read by vio_read function, to which vio field of NET is passed together with buff and max_packet field -values. field of the same struct at a length of max_packet. If +values. field of the same struct at a length of max_packet. If blocking was active before reading is performed, blocking is set with -vio_blocking function. AFter reading has been performed, pkt_nr is +vio_blocking function. After reading has been performed, pkt_nr is reset to 0 and write_pos reset to buff. In order to clarify some -matters non-blocking mode enables executing program to dissociate from +matters non-blocking mode enables executing program to dissociate from a connection, so that error in connection would not hang entire -program or it's thread. +program or its thread. + +Function name: net_flush - Function name: net_flush - - Parameters: struct NET * +Parameters: struct NET * - Return value : 1 for error, 0 for success +Return value: 1 for error, 0 for success - Function purpose: To write remaining bytes in buff to socket +Function purpose: To write remaining bytes in buff to socket - Function description +Function description - net_real_write (described below) is performed is write_pos +net_real_write (described below) is performed is write_pos differs from buff, both being fields of the only parameter. write_pos -is reset to buff. This function has to be used, as MySQL uses buffered -writes, as it will be more explained in a function net_write_buff. - - - Function name: my_net_write - - Parameters: struct NET *, const char *, ulong - - Return value : 1 for error, 0 for success - - Function purpose: Write a logical packet in a first parameter - of second parameter length - - Function description - - The purpose of this function is to prepare a logical packet -such that entire content of data, pointed to by second parametar and -in length of third parameter is sent to the other side. In case of -server, it is used for sending result sets, and in case of client it -is used for sending local data. This function foremost prepares a -header for the packet. Normal, header consists of 4 bytes, of which -first 3 bytes contain a length of the packet, thereby limiting a -maximum allowable length of a packet to 16 Mb, while a fourth byte -contains a packet number, which is used when one large packet has to -be divided into sequence of packets. This way each sub-packet gets -it's number which should be matched on the other side. When -compression is used another three bytes are added to packet header, -thus packet header is in that case increased to 7 bytes. Additional -three bytes are used to save a length of compressed data. As in -connection that uses compression option, code packs packets together,, -a header prepared by this function is later not used in writting to / -reading from network, but only to distinguish logical packets within a -buffered read operation. - - - This function, first stores a value for third parameter into a +is reset to buff. This function has to be used, as MySQL uses buffered +writes (as will be explained more in the function net_write_buff). + + +Function name: my_net_write + +Parameters: struct NET *, const char *, ulong + +Return value: 1 for error, 0 for success + +Function purpose: Write a logical packet in the second parameter + of third parameter length + +Function description + +The purpose of this function is to prepare a logical packet such +that entire content of data, pointed to by second parameter and in +length of third parameter is sent to the other side. In case of +server, it is used for sending result sets, and in case of client +it is used for sending local data. This function foremost prepares +a header for the packet. Normally, the header consists of 4 bytes, +of which the first 3 bytes contain the length of the packet, thereby +limiting a maximum allowable length of a packet to 16MB, while the +fourth byte contains the packet number, which is used when one large +packet has to be divided into sequence of packets. This way each +sub-packet gets its number which should be matched on the other +side. When compression is used another three bytes are added to +packet header, thus packet header is in that case increased to 7 +bytes. Additional three bytes are used to save the length of +compressed data. As in connection that uses compression option, +code packs packets together,, a header prepared by this function +is later not used in writing to / reading from network, but only +to distinguish logical packets within a buffered read operation. + + +This function, first stores the value of the third parameter into the first 3 bytes of local char variable of NET_HEADER_SIZE size by usage of function int3store. Then, at this point, if compression is not -used, pkt_nr is increased, and it's value stored in the last byte of -the said local char[] variable. If compression is used 0 is stored in -both values. Then those four bytes are sent to other side by the usage -of the function net_write_buff(to be explained later on), and -successfull, entire packet in second parameter of the length described +used, pkt_nr is increased, and its value stored in the last byte of +the said local char[] variable. If compression is used, 0 is stored in +both values. Then those four bytes are sent to other side by the usage +of the function net_write_buff(to be explained later on), and if +successful, entire packet in second parameter of the length described in third parameter is sent by the usage of the same function. - Function name: net_write_command - - Parameters: struct NET *, char, const char *, ulong +Function name: net_write_command - Return value : 1 for error, 0 for success +Parameters: struct NET *, char, const char *, ulong - Function purpose: Send a command with a packet as in previous - function +Return value: 1 for error, 0 for success - Function description +Function purpose: Send a command with a packet as in previous function - This function is very similar to the previous one. The only -difference is that first packet is enlarged by one byte, so that a -command precedes a packet to be sent. This is implemented by -increasing fist packet by one byte, which contains a command code. As -command codes do not use a range of values that are used by chararcter +Function description + +This function is very similar to the previous one. The only +difference is that first packet is enlarged by one byte, so that the +command precedes the packet to be sent. This is implemented by +increasing first packet by one byte, which contains a command code. As +command codes do not use the range of values that are used by character sets, so when the other side receives a packet, first byte after header contains a command code. This function is used by client for sending all commands and queries, and by server in connection process and for sending errors. - - Function name: net_write_buff (private, static function) - - Parameters: struct NET *, const char *, uint - Return value : 1 for error, 0 for success +Function name: net_write_buff (private, static function) + +Parameters: struct NET *, const char *, uint - Function purpose: To write a packet of vany size by cutting it - and using next function for writing it +Return value: 1 for error, 0 for success - Function description +Function purpose: To write a packet of any size by cutting it +and using next function for writing it - This function was created after compression feature has been +Function description + +This function was created after compression feature has been added to MySQL. This function supposes that packets have already been -properly formatted, regarding packet header etc. Principal reason for -this function existst because a packet that is sent by client or -server does not have to be less then max_packet. So this function -first calculeates how much data has been left in a buff, by getting a +properly formatted, regarding packet header etc. The principal reason for +this function to exist is because a packet that is sent by client or +server does not have to be less than max_packet. So this function +first calculates how much data has been left in a buff, by getting a difference between buff_end and write_pos and storing it to local -variable left_length. Then a loop is run as long as a length to be -sent is greater then length of left bytes (left_length). In a loop +variable left_length. Then a loop is run as long as the length to be +sent is greater than length of left bytes (left_length). In a loop data from second parameter is copied to buff at write_pos, as much as -it can be, i.e. by left_length. Then net_real_write function is called +it can be, that is, by left_length. Then net_real_write function is called (see below) with NET, buff, and max_packet parameters. This function -is the lowest level fucntion that writes data over established -connection. In a loop, write_pos is reset to buff, a pointer to data -(second parameter) is moved by teh amount of data sent (left_length), -length of data to be sent (third parameter) is decreased by the amount -sent (left_length) and left_length is reset to max_packet value, which -ends a loop. This logic was necessary, as there could have been some +is the lowest level function that writes data over established +connection. In the loop, write_pos is reset to buff, the pointer to data +(second parameter) is moved by the amount of data sent (left_length), +length of data to be sent (third parameter) is decreased by the amount +sent (left_length) and left_length is reset to max_packet value, which +ends the loop. This logic was necessary, as there could have been some data yet unsent (write_pos != buf), while data to be sent could be as -large as necessary, thus requiring many loops. At the end of function, -remaining data in second parameter are copied to buff at write_pos, by +large as necessary, thus requiring many loops. At the end of function, +remaining data in second parameter are copied to buff at write_pos, by the remaining length of data to be sent (third parameter). So, in the next call of this function remaining data will be sent, as buff is -used in a call to net_real_write. It is very important to note that if -a packet to be sent is less then a number of bytes that are still +used in the call to net_real_write. It is very important to note that if +a packet to be sent is less than the number of bytes that are still available in buff, then there will be no writing over network, but only logical packets will be added one after another. This will -accelerate network traffic, plus if a compression is used, the +accelerate network traffic, plus if compression is used, the expected compression rate would be higher. That is why server or client functions that sends data uses at the end of data net_flush -function described above. +function described above. + +Function name: net_real_write - Function name: net_real_write - - Parameters: struct NET *, const char *, ulong +Parameters: struct NET *, const char *, ulong - Return value : 1 for error, 0 for success +Return value: 1 for error, 0 for success - Function purpose: To write data to a socket or pipe, with - compression if used +Function purpose: To write data to a socket or pipe, with +compression if used - Function description +Function description - First, more field is set to 2, to enable reporting in +First, more field is set to 2, to enable reporting in mysql_list_processes. Then if compression is enabled on that connection, a new local buffer (variable b) is initialized to the length of total header (normal header + compression header) and if no -memory is available error is returned. This buffer (b) is used for -holding a fineal, compressed packet to be written ove -connection. Furthermore in compressiion initialization, Second +memory is available, an error is returned. This buffer (b) is used for +holding the final, compressed packet to be written over the +connection. Furthermore in compression initialization, second parameter at length of third parameter is copied to the local buffer b, and MySQL's wrapped zlib's compression function is run at total header offset of the local buffer. Please, do note that this function @@ -683,263 +673,271 @@ important to be cognizant of the fact that this algorithm makes possible that a single compressed packet contains several logical packets. In this way compression rate is increased and network throughput is increased as well. However, this algorithm has -consequences on the other sided, that reads compressed packet, which -is covered in my_net_read function. After compression is done, a full -compression header is properly formed with a packet number, +consequences on the other side, that reads compressed packet, which +is covered in my_net_read function. After compression is done, the full +compression header is properly formed with the packet number, compressed and uncompressed lengths. At the end of compression code, third parameter is increased by total header length, as the original header is not used (see above), and second parameter, pointer to data, -is set to point to local buffer b, in order that a further flow of -function is independent of compression. . If a function is executed +is set to point to local buffer b, in order that the further flow of +function is independent of compression. If a function is executed on server side, a thread alarm initialized and if non-blocking is active set at NET_WRITE_TIMEOUT. Two local (char *) pointers are initialized, pos at beginning of second parameter, and end at end of -data. Then a loop is run as long as all data is written, which means -as long as pos != end. First vio_write function is called, with +data. Then the loop is run as long as all data is written, which means +as long as pos != end. First vio_write function is called, with parameters of vio field, pos and size of data (end - pos). Number of bytes written over connection is saved in local variable (length). If error is returned local bool variable (interrupted) is set according to the return value of the vio_should_retry called with vio field as parameter. This bool variable indicates whether writing was -interrupted in some way or not. Firther, error from vio_write is -differently treated on Unix versus other OS's (Win32 or OS/2). On Unix -an alarm is set if one is not in use, no bytes have been written and -there has been no interruption. Also, in that case, if connection is -not in blocking mode, a sub - loop is run as long as blocking is not -set with vio_blocking function. Withing a loop another run of above -vio_write is run based on return value of vio_is_retry function, --provided number of repeated writes is less then RETRY_COUNT. If that -is not a case, error field of struct NET. is set to 1 and function -exits. At the exit of sub-llop number of reruns already executed is -reset to zero and another run of above vio_write function is -attempted. If a function is run on Win32 and OS/2, and in the case -that function flow was not interrupted and thread alarm is not in use, -again a main loop is continued until pos != end. In the case that this -function is executed on thread safe client program, a communication -flow is tested on EINTR, caused by context switching, by use of -vio_errno function, in which case a loop is continued. At the end of -processing of the error from vio_write, error field of struct NET is -set, and if on server last_errno field is set to -ER_NET_WRITE_INTERRUPTED in the case thatb local bool variable -(interrupted) is true or to ER_NET_ERROR_ON_WRITE. Before the end of -loop, in order to make possible evaluation of the loop condition, pos -is increased by a value writen in last iteration (length). Also global -variable bytes_sent is increased by the same value, for status -purposes. At the end of the functions more fields is reset, in case -of compression, combression buffer (b) memory is released and if -thread is still in use, it is ended and blocking state is reset to -it's original state, and function returns error is all bytes are not -written. - - - - Function name: my_real_read (private, static function) - - Parameters: struct NET *, ulong * - - Return value : length of bytes read - - Function purpose: low level network connection read function - - Function description - - This function has made as a separate one when compression was -introduced in MySQL client - server protocol . It contains basic, low +interrupted in some way or not. + +Further, error from vio_write is treated differently on Unix versus +other OS's (Win32 or OS/2). On Unix an alarm is set if one is not +in use, no bytes have been written and there has been no interruption. +Also, in that case, if connection is not in blocking mode, a sub-loop +is run as long as blocking is not set with vio_blocking function. +Within the loop another run of above vio_write is run based on +return value of vio_is_retry function, provided number of repeated +writes is less than RETRY_COUNT. If that is not the case, error +field of struct NET is set to 1 and function exits. At the exit +of sub-loop number of reruns already executed is reset to zero and +another run of above vio_write function is attempted. If the function +is run on Win32 and OS/2, and in the case that function flow was +not interrupted and thread alarm is not in use, again the main loop +is continued until pos != end. In the case that this function is +executed on thread safe client program, a communication flow is +tested on EINTR, caused by context switching, by use of vio_errno +function, in which case the loop is continued. At the end of +processing of the error from vio_write, error field of struct NET +is set, and if on server last_errno field is set to +ER_NET_WRITE_INTERRUPTED in the case that local bool variable +(interrupted) is true or to ER_NET_ERROR_ON_WRITE. Before the end +of loop, in order to make possible evaluation of the loop condition, +pos is increased by the value written in last iteration (length). +Also global variable bytes_sent is increased by the same value, for +status purposes. At the end of the functions more fields is reset, +in case of compression, compression buffer (b) memory is released +and if thread is still in use, it is ended and blocking state is +reset to its original state, and function returns error is all bytes +are not written. + + + +Function name: my_real_read (private, static function) + +Parameters: struct NET *, ulong * + +Return value: length of bytes read + +Function purpose: low level network connection read function + +Function description + +This function has made as a separate one when compression was +introduced in MySQL client/server protocol . It contains basic, low level network reading functionality, while all dealings with compressed packets are handled in next function. Compression in this -function is only handled in as much to unfold a length of uncompressed +function is only handled in as much to unfold the length of uncompressed data. First blocking state of connection is saved in local bool -variable net_blocking, and field more is set 1 for deteiled reporting +variable net_blocking, and field more is set 1 for detailed reporting in mysqld_list_processes. A new thread alarm is initialized, in order -to enable read timout handling, and if on server and a connection can +to enable read timeout handling, and if on server and a connection can block a program, the alarm is set at a value of timeout field. Local -pointer is set to the position of the next logical packet, with it's +pointer is set to the position of the next logical packet, with its header skipped, which is at field where_b offset from buff. Next, a -two time run code is entered. A loop is run exactly two times becase +two time run code is entered. A loop is run exactly two times because first time number of bytes to be fetched (remain) are set to the header size, which is different when compression is used or not used on the connection. After first fetch has been done, number of packets that will be received in second iteration is well known, as fetched -header contains a size of packet, packet number ,and in a case of -compression a size of uncompressed packet. Then as long, as there are -bytes to read a loop is entered with ffirst reading data from network +header contains the size of packet, packet number, and in the case of +compression, the size of the uncompressed packet. Then, as long as there are +bytes to read the loop is entered with first reading data from network connection with vio_read function, called with parameters of field vio, current position and remaining number of bytes, which value is -hold by local variable (remain) initialized at a value of header size, +hold by local variable (remain) initialized at the value of header size, which differs if compression is used. Number of bytes read are -returned in local length variable. If error is returned local bool +returned in local length variable. If error is returned local bool variable (interrupted) is set according to the return value of the vio_should_retry called with vio field as parameter. This bool variable indicates whether reading was interrupted in some way or not. -Firther, error from vio_read is differently treated on Unix versus -other OS's (Win32 or OS/2). On Unix an alarm is set if one is not in -use, no bytes have been read and there has been no interruption. Also, -in that case, if connection is not in blocking mode, a sub - loop is -run as long as blocking is not set with vio_blocking function. Withing -a loop another run of above vio_read is run based on return value of -vio_is_retry function, -provided number of repeated writes is less -then RETRY_COUNT. If that is not a case, error field of struct NET. is -set to 1 and function exits. At the exit of sub-llop number of reruns -already executed is reset to zero and another run of above vio_read -function is attempted. If a function is run on Win32 and OS/2, and in -the case that function flow was not interrupted and thread alarm is -not in use, again a main loop is continued as long as there are bytes -remaining. In the case that this function is executed on thread safe -client program, then if a another run should be made, which is decided -by the output of vio_should_retry function, in which case a loop is -continued. At the end of processing of the error from vio_read, error -field of struct NET is set, and if on server last_errno field is set -to ER_NET_READ_INTERRUPTED in the case thatb local bool variable -(interrupted) is true or to ER_NET_ERROR_ON_READ. In case of such an -error this function exits and returns error. In a case when there is -no error, number of remaining bytes (remain) is decreased by a number -of bytes read, which should be zero, but in case it is not the entire -code is still in while (remain > 0) loop, which will be exited -immediately if it is. This has been done to accomodate errors in the -traffic level and for the very slow connections. Current position in -field buff is also moved by the amount of bytes read by vio_read -funciton, and global variable bytes_received is increased by the same -value in a thread safe manner. When a loop that is run until necessary -bytes are read (remain) is finished, then if external loop is in it's -first run, of the two, packet sequencing is tested on consistency by -comparing a number contained at 4th byte in header with pkt_nre -field. Header location is found at where_b offset to field_b. Usage of -where_b is obligatory due to the possible compression usage. If there -is no compression on a connection, then where_b is always 0. If there -is a discrepancy, then first byte of the header is checked whether it -is equal to 255, because when error is sent by a server, or by a -client if it is sending data (like in LOAD DATA INFILE LOCAL...), then -first byte in header is set to 255. If it is not 255, then an error on -packets being out of order is printed. In any case, on server, -last_errno field is set to ER_NET_PACKETS_OUT_OF_ORDER and a function -returns with the error, i.e. value returned is packet_error. If a -check on serial number of packet is successful, pkt_nr field is -incremented in order to enable checking packet order with next packet -and if compression is used, uncompressed length is extracted from a -proper position in header and returned in the second parameter of this -function. Length of the packet is saved, for the purpose of a proper -return value from this function. Still in the first iteration of the -main loop, a check must be made if field buff could accomodate entire -package that comes, in it's compressed or uncompressed form. This is -done in such a way, because zlib's compress and uncompress functions -use a same memory area for compression / uncompression. Necessary -field buff length is equal to current offset where data are (where_b -which is zero for non-compression), plus the larger value of -compressed or uncompressed package to be read in a second run. If this -value is larger then a current length of field buff, which is read -from field max_packet, then feild buff has to be reallocated. IF -reallocation with net_realloc function fails, function is returned -with error. Before a second loop is started, length to be read is set -to the length of expected data and current position (pos) is set at -where_b offset from field buff. At the end of function, if alarm is -set, which is a case if it is run on server or on a client if a -function is interrupted and another run of vio_read is attempted, -alarm is ended and blocking state is resotred from the saved local bool -variable net_blocking. Function returns number of bytes read or the -error (packet_error). - - - - - Function name: my_net_read - - Parameters: struct NET * - - Return value : length of bytes read - - Function purpose: Highest level general purpose reading function - - Function description - - First, if compression is not used, my_real_read is called, -with struct NET * a first parameter, and pointer to local ulong -complen as a second parameter, but it's value is not used here. -Number of bytes read is returned in local ulong variable len. read_pos -field is set to an offset of value of where_b field from field -buff. where_b field actually denotes where in field buff is a current -packet. If returned number of bytes read (local variable len) does not -signal that an error in packet trnasmission occured, i.e. it is not -set to packet_error, then a string contained in read_pos is zero -terminated. Simply, the end of a string starting at read_pos, and -ending at read_pos + len, is set to zero. This is done in that way, -because mysql_use_result expects a zero terminated string, and -function returns with a value local variable len. This ends this -function in the case that compression is not used and a remaining code -is executed only if compression is enabled on the connection. In -order to explain how is compressed packet logically cut into -meningfull packets, a full meaning of several NET feilds should be -explained. First of all, fields in NET are used and not local -variables, as all values should be saved between consecutive calls of -this function. Simply, this function is called in order to return + +Further, error from vio_read is treated differently on Unix versus +other OS's (Win32 or OS/2). On Unix an alarm is set if one is not +in use, no bytes have been read and there has been no interruption. +Also, in that case, if connection is not in blocking mode, a sub-loop +is run as long as blocking is not set with vio_blocking function. +Within the loop another run of above vio_read is run based on return +value of vio_is_retry function, provided number of repeated writes +is less than RETRY_COUNT. If that is not the case, error field of +struct NET is set to 1 and function exits. At the exit of sub-loop +number of reruns already executed is reset to zero and another run +of above vio_read function is attempted. If the function is run on +Win32 and OS/2, and in the case that function flow was not interrupted +and thread alarm is not in use, again the main loop is continued +as long as there are bytes remaining. In the case that this function +is executed on thread safe client program, then if another run +should be made, which is decided by the output of vio_should_retry +function, in which case the loop is continued. At the end of +processing of the error from vio_read, error field of struct NET +is set, and if on server last_errno field is set to ER_NET_READ_INTERRUPTED +in the case that local bool variable (interrupted) is true or to +ER_NET_ERROR_ON_READ. In case of such an error this function exits +and returns error. In the case when there is no error, number of +remaining bytes (remain) is decreased by the number of bytes read, +which should be zero, but in case it is not the entire code is still +in while (remain > 0) loop, which will be exited immediately if it +is. This has been done to accommodate errors in the traffic level +and for the very slow connections. Current position in field buff +is also moved by the amount of bytes read by vio_read function, and +global variable bytes_received is increased by the same value in a +thread safe manner. When the loop that is run until necessary bytes +are read (remain) is finished, then if external loop is in its first +run, of the two, packet sequencing is tested for consistency by +comparing the number contained at 4th byte in header with pkt_nr +field. Header location is found at where_b offset to field_b. Usage +of where_b is obligatory due to the possible compression usage. If +there is no compression on a connection, then where_b is always 0. +If there is a discrepancy, then first byte of the header is checked +whether it is equal to 255, because when error is sent by the server, +or by a client if it is sending data (like in LOAD DATA INFILE +LOCAL...), then first byte in header is set to 255. If it is not +255, then an error on packets being out of order is printed. In any +case, on server, last_errno field is set to ER_NET_PACKETS_OUT_OF_ORDER +and the function returns with an error, that is, the value returned is +packet_error. If a check on serial number of packet is successful, +pkt_nr field is incremented in order to enable checking packet order +with next packet and if compression is used, uncompressed length +is extracted from a proper position in header and returned in the +second parameter of this function. Length of the packet is saved, +for the purpose of a proper return value from this function. Still +in the first iteration of the main loop, a check must be made if +field buff could accommodate entire package that comes, in its +compressed or uncompressed form. This is done in such a way, because +zlib's compress and uncompress functions use the same memory area +for compression and uncompression. Necessary field buff length is +equal to current offset where data are (where_b which is zero for +non-compression), plus the larger value of compressed or uncompressed +package to be read in a second run. If this value is larger than +the current length of field buff, which is read from field max_packet, +then field buff has to be reallocated. If reallocation with net_realloc +function fails, the function returns an error. Before a second +loop is started, length to be read is set to the length of expected +data and current position (pos) is set at where_b offset from field +buff. At the end of function, if alarm is set, which is the case +if it is run on server or on a client if a function is interrupted +and another run of vio_read is attempted, alarm is ended and blocking +state is restored from the saved local bool variable net_blocking. +Function returns number of bytes read or the error (packet_error). + + +Function name: my_net_read + +Parameters: struct NET * + +Return value: length of bytes read + +Function purpose: Highest level general purpose reading function + +Function description + +First, if compression is not used, my_real_read is called, with +struct NET * a first parameter, and pointer to local ulong complen +as a second parameter, but its value is not used here. Number of +bytes read is returned in local ulong variable len. read_pos field +is set to an offset of value of where_b field from field buff. +where_b field actually denotes where in field buff is the current +packet. If returned number of bytes read (local variable len) does +not signal that an error in packet transmission occurred (that is, +it is not set to packet_error), then the string contained in read_pos +is zero terminated. Simply, the end of the string starting at +read_pos, and ending at read_pos + len, is set to zero. This is +done in that way, because mysql_use_result expects a zero terminated +string, and function returns with a value local variable len. This +ends this function in the case that compression is not used and the +remaining code is executed only if compression is enabled on the +connection. + +In order to explain how a compressed packet logically is cut into +meningful packets, the full meaning of several NET fields should +be explained. First of all, fields in NET are used and not local +variables, as all values should be saved between consecutive calls +of this function. Simply, this function is called in order to return logical packets, but this function does not need to call my_real_read -function everytime, because when a large packet is uncompressed, it -may, but not necessarily so, contain several logical -packets. Therefore, in oreder to preserve data on logical packets -local variables are not used. Instead fields in NET struct are -used. Field remain_in_buf denotes how many bytes of entire -uncompressed packets is still contained withing buff. field buf_length -saves a value of the length of entire uncompressed packet. field -save_char is used to save a character at a position where a packet -ends, which character has to be replaced with a zero, '\0', in order -to make a logical packet zero delimited, for mysql_use_result. Field -length stores a value of the length of compressed packet. Field -read_pos as usual, points to the current reading position. This char * -pointer is used by all fucntion calling this function in order to -fetch their data. Field buff is not used for that purpose, but -read_pos is used instead. This change was introduced with compression, -when algorihtm accomodated grouping of several packets together. Now, -that meanings of all relevant NET fields is complained, we can proceed -with a flow of this functinn in case when compression is -active. First, if there are remaining portions of compressed packet in -a field buff, saved character value is set at a position where zero -char '\0' was inserted to enable a string do be zero delimited for -mysql_use_result. Then a loop is started. In the first part of the -loop, if there are remaining bytes, local uchar *pos variable is set -at a current position in field buff where a new packet starts. This -position is an (buf_length - remain_in_buf) offset in field buff. As -it is possible that next logical packet is not read to the full length -in the remaining of the field buf, several things had to be -inspected. It should be noted that data that is read from -net_rweal_read contains only logical packets containing 4 byte headers -only, being 4 byte headers prepared by my_net_write or -net_write_command. But, when written, logical packet could be so -divided that only a part of header is read in. Therefore after pointer -to the start of the next packet has been saved, a check is made -whether number of remaining bytes in buffer is less then 4, being 3 -bytes for length and one byte for packet number. If it is greater, -then a length of the logical packet is extracted and saved a length -field. Then a check is made whether entire packet is contained withing -a buf, i.e. a check is made that a logical packet is fully contained -in a buffer. In that case, number of bytes remaining in buffer is -decreased by a full length of logical packet ( 4 + length field), -read_pos is moved forward by 4 bytes to skip header and be set at a -beginning of data in logical packet, length field is saved for a value -to be returned in function and a loop is exited. In a case that -entire logical packet is not contained within a buffer, then if length -of the entire buffer differs from remaining length of logical packet, -it (logical packet) is moved to the beginning of the field buff. If -length of the entire buffer equals the remaining length of logical -packet, where_b and buf_length fields are set to 0. This is done so -that in both cases buffer is ready to accept next part of packet. In -order to get a next part of a packet, still within a loop, +function everytime, because when a large packet is uncompressed, +it may, but not necessarily so, contain several logical packets. +Therefore, in order to preserve data on logical packets local +variables are not used. Instead fields in NET struct are used. Field +remain_in_buf denotes how many bytes of entire uncompressed packets +is still contained within buff. field buf_length saves the value +of the length of entire uncompressed packet. field save_char is +used to save the character at the position where the packet ends, +which character has to be replaced with a zero, '\0', in order to +make a logical packet zero delimited, for mysql_use_result. Field +length stores the value of the length of compressed packet. Field +read_pos as usual, points to the current reading position. This +char * pointer is used by all functions that call this function in +order to fetch their data. Field buff is not used for that purpose, +but read_pos is used instead. This change was introduced with +compression, when algorithm accommodated grouping of several packets +together. + +Now that meanings of all relevant NET fields are explained, +we can proceed with the flow of this function for the case when +compression is active. First, if there are remaining portions of +compressed packet in a field buff, saved character value is set at +the position where zero char '\0' was inserted to enable the string +to be zero delimited for mysql_use_result. Then a loop is started. +In the first part of the loop, if there are remaining bytes, local +uchar *pos variable is set at the current position in field buff +where a new packet starts. This position is an (buf_length - +remain_in_buf) offset in field buff. As it is possible that next +logical packet is not read to the full length in the remaining of +the field buf, several things had to be inspected. It should be +noted that data that is read from net_real_read contains only logical +packets containing 4 byte headers only, being 4 byte headers prepared +by my_net_write or net_write_command. But, when written, logical +packet could be so divided that only a part of header is read in. +Therefore after pointer to the start of the next packet has been +saved, a check is made whether number of remaining bytes in buffer +is less than 4, being 3 bytes for length and one byte for packet +number. If it is greater, then the length of the logical packet is +extracted and saved a length field. Then a check is made whether +entire packet is contained within a buf, that is, a check is made +that the logical packet is fully contained in the buffer. In that +case, number of bytes remaining in buffer is decreased by the full +length of logical packet (4 + length field), read_pos is moved +forward by 4 bytes to skip header and be set at a beginning of data +in logical packet, length field is saved for the value to be returned +in function and the loop is exited. In the case that the entire +logical packet is not contained within the buffer, then if length of +the entire buffer differs from remaining length of logical packet, +it (logical packet) is moved to the beginning of the field buff. +If length of the entire buffer equals the remaining length of logical +packet, where_b and buf_length fields are set to 0. This is done +so that in both cases buffer is ready to accept next part of packet. + +In order to get a next part of a packet, still within a loop, my_real_read function is called and length of compressed packet is returned to a local len variable, and length of compressed data is -returned in complen variable. In a case of non-compression value of -complen is zero. If packet_error is from my_real_read function, this -function returns also with packet_error. If it is not a packet_error -my_uncompress function is called to uncompress data. It is called with -offset of where_b data from field buff, as it is a postion where -compressed packet starts, and with len and complen values, being -lengths of compressed and uncompressed data. If there is no -compression, 0 is returned for uncompressed size from my_real_read -function, and my_uncompress wrapper function is made to skip zlib -uncompress in that case. If error is returned fom my_uncompress, -error field is set to 1, if on server last_errno is set to -ER_NET_UNCOMPRESS_ERROR and loop is exited and function returns with -packet_error. If not, buf_length and reamin_in_buf fields are set to -the uncompressed size of buffer and a loop is continued. When a loop -is exited save_char field is used to save a char at end of a logical -packet, which is an offset of field len from position in field buff -pointed by field read_os, in order that zero char is set at the same -position, for mysql_use_result. Function returns a length of the -logical packet without it's header. +returned in complen variable. In the case of non-compression value +of complen is zero. If packet_error is from my_real_read function, +this function returns also with packet_error. If it is not a +packet_error, my_uncompress function is called to uncompress data. +It is called with offset of where_b data from field buff, as it is +the position where compressed packet starts, and with len and complen +values, being lengths of compressed and uncompressed data. If there +is no compression, 0 is returned for uncompressed size from +my_real_read function, and my_uncompress wrapper function is made +to skip zlib uncompress in that case. If error is returned from +my_uncompress, error field is set to 1, if on server last_errno is +set to ER_NET_UNCOMPRESS_ERROR and loop is exited and function +returns with packet_error. If not, buf_length and remain_in_buf +fields are set to the uncompressed size of buffer and the loop is +continued. When the loop is exited save_char field is used to save +the char at end of a logical packet, which is an offset of field +len from position in field buff pointed by field read_pos, in order +that zero char is set at the same position, for mysql_use_result. +Function returns the length of the logical packet without its header. diff --git a/client/client_priv.h b/client/client_priv.h index aa1de85f489..854d205e585 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -43,5 +43,5 @@ enum options_client OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION,OPT_MYSQL_PROTOCOL, OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM, OPT_SKIP_OPTIMIZATION, OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH, - OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET + OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_CREATE_OPTIONS }; diff --git a/client/mysqldump.c b/client/mysqldump.c index 0951fdbcbae..1707e9c564b 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -37,7 +37,7 @@ ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov */ -#define DUMP_VERSION "10.6" +#define DUMP_VERSION "10.7" #include <my_global.h> #include <my_sys.h> @@ -91,7 +91,6 @@ static char insert_pat[12 * 1024],*opt_password=0,*current_user=0, *opt_compatible_mode_str= 0, *err_ptr= 0; static char compatible_mode_normal_str[255]; -static char *default_charset= (char*) MYSQL_UNIVERSAL_CLIENT_CHARSET; static ulong opt_compatible_mode= 0; static uint opt_mysql_port= 0, err_len= 0; static my_string opt_mysql_unix_port=0; @@ -104,7 +103,9 @@ FILE *md_result_file; static char *shared_memory_base_name=0; #endif static uint opt_protocol= 0; +static char *default_charset= (char*) MYSQL_UNIVERSAL_CLIENT_CHARSET; static CHARSET_INFO *charset_info= &my_charset_latin1; +const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; const char *compatible_mode_names[]= { @@ -132,9 +133,6 @@ static struct my_option my_long_options[] = "Dump all the databases. This will be same as --databases with all databases selected.", (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"all", 'a', "Include all MySQL specific create options.", - (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1, - 0, 0, 0, 0, 0}, {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.", (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, @@ -148,7 +146,7 @@ static struct my_option my_long_options[] = "Directory where character sets are.", (gptr*) &charsets_dir, (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"compatible", OPT_COMPATIBLE, - "Change the dump to be compatible with a given mode. By default tables are dumped without any restrictions. Legal modes are: ansi, mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, no_table_options, no_field_options. One can use several modes separated by commas. Note: Requires MySQL server version 4.1.0 or higher. This option does a no operation on earlier server versions.", + "Change the dump to be compatible with a given mode. By default tables are dumped in a format optimized for MySQL. Legal modes are: ansi, mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, no_table_options, no_field_options. One can use several modes separated by commas. Note: Requires MySQL server version 4.1.0 or higher. This option is ignored with earlier server versions.", (gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"compact", OPT_COMPACT, @@ -160,12 +158,21 @@ static struct my_option my_long_options[] = {"compress", 'C', "Use compression in server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"create-options", OPT_CREATE_OPTIONS, + "Include all MySQL specific create options.", + (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1, + 0, 0, 0, 0, 0}, {"databases", 'B', "To dump several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames. 'USE db_name;' will be included in the output.", (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef DBUG_OFF + {"debug", '#', "This is a non-debug version. Catch this and exit", + 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#else + {"debug", '#', "Output debug log", (gptr*) &default_dbug_option, + (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", (gptr*) &default_charset, (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -463,7 +470,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_disable_keys=0; break; case '#': - DBUG_PUSH(argument ? argument : "d:t:o"); + DBUG_PUSH(argument ? argument : default_dbug_option); break; #include <sslopt-case.h> case 'V': print_version(); exit(0); @@ -483,7 +490,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case (int) OPT_SKIP_OPTIMIZATION: extended_insert= opt_drop= opt_lock= quick= create_options= - opt_disable_keys= lock_tables= 0; + opt_disable_keys= lock_tables= opt_set_charset= 0; break; case (int) OPT_COMPACT: if (opt_compact) @@ -859,11 +866,11 @@ static void print_xml_row(FILE *xml_file, const char *row_name, { if ((*row)[i]) { - fputs(" ", xml_file); + fputc(' ', xml_file); print_quoted_xml(xml_file, field->name, field->name_length); fputs("=\"", xml_file); print_quoted_xml(xml_file, (*row)[i], lengths[i]); - fputs("\"", xml_file); + fputc('"', xml_file); } } fputs(" />\n", xml_file); @@ -897,6 +904,9 @@ static uint getTableStructure(char *table, char* db) sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", (opt_quoted || opt_keywords)); + if (!create_options) + strmov(strend(insert_pat), "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 'NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */"); + result_table= quote_name(table, table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); if (!opt_xml && !mysql_query(sock,insert_pat)) @@ -978,8 +988,10 @@ static uint getTableStructure(char *table, char* db) } else { - /* fprintf(stderr, "%s: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n", - my_progname, mysql_error(sock)); */ + if (verbose) + fprintf(stderr, + "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n", + my_progname, mysql_error(sock)); sprintf(insert_pat,"show fields from %s", result_table); if (mysql_query(sock,insert_pat) || !(tableRes=mysql_store_result(sock))) @@ -1172,7 +1184,7 @@ static uint getTableStructure(char *table, char* db) else { fputs("/*!",sql_file); - print_value(sql_file,tableRes,row,"type=","Type",0); + print_value(sql_file,tableRes,row,"engine=","Engine",0); print_value(sql_file,tableRes,row,"","Create_options",0); print_value(sql_file,tableRes,row,"comment=","Comment",1); fputs(" */",sql_file); @@ -1413,12 +1425,12 @@ static void dumpTable(uint numFields, char *table) fputs("Aborting dump (out of memory)",stderr); safe_exit(EX_EOM); } - dynstr_append(&extended_row,"\'"); + dynstr_append(&extended_row,"'"); extended_row.length += mysql_real_escape_string(&mysql_connection, &extended_row.str[extended_row.length],row[i],length); extended_row.str[extended_row.length]='\0'; - dynstr_append(&extended_row,"\'"); + dynstr_append(&extended_row,"'"); } else { @@ -1432,9 +1444,9 @@ static void dumpTable(uint numFields, char *table) if (field->type == FIELD_TYPE_DECIMAL) { /* add " signs around */ - dynstr_append(&extended_row, "\""); + dynstr_append(&extended_row, "'"); dynstr_append(&extended_row, ptr); - dynstr_append(&extended_row, "\""); + dynstr_append(&extended_row, "'"); } else dynstr_append(&extended_row, ptr); @@ -1442,7 +1454,7 @@ static void dumpTable(uint numFields, char *table) } } else - dynstr_append(&extended_row,"\'\'"); + dynstr_append(&extended_row,"''"); } else if (dynstr_append(&extended_row,"NULL")) { @@ -1486,9 +1498,9 @@ static void dumpTable(uint numFields, char *table) else if (field->type == FIELD_TYPE_DECIMAL) { /* add " signs around */ - fputs("\"", md_result_file); + fputc('\'', md_result_file); fputs(ptr, md_result_file); - fputs("\"", md_result_file); + fputc('\'', md_result_file); } else fputs(ptr, md_result_file); diff --git a/configure.in b/configure.in index 94ad5a47991..6ccbf087b91 100644 --- a/configure.in +++ b/configure.in @@ -2228,7 +2228,6 @@ if expr "$SYSTEM_TYPE" : ".*netware.*" > /dev/null; then # For NetWare, do not need readline echo "Skipping readline" else -mkdir include/readline if [test "$with_libedit" = "yes"] || [test "$with_libedit" = "undefined"] && [test "$with_readline" = "undefined"] then @@ -2236,7 +2235,7 @@ then readline_basedir="libedit" readline_dir="$readline_topdir/$readline_basedir" readline_link="\$(top_builddir)/cmd-line-utils/libedit/liblibedit.a" - readline_h_ln_cmd="\$(LN) \$(top_builddir)/cmd-line-utils/libedit/readline/*.h readline/" + readline_h_ln_cmd="\$(LN) -s \$(top_builddir)/cmd-line-utils/libedit/readline readline" compile_libedit=yes AC_DEFINE_UNQUOTED(USE_LIBEDIT_INTERFACE) elif test "$with_readline" = "yes" @@ -2245,7 +2244,7 @@ then readline_basedir="readline" readline_dir="$readline_topdir/$readline_basedir" readline_link="\$(top_builddir)/cmd-line-utils/readline/libreadline.a" - readline_h_ln_cmd="\$(LN) \$(top_builddir)/cmd-line-utils/readline/*.h readline/" + readline_h_ln_cmd="\$(LN) -s \$(top_builddir)/cmd-line-utils/readline readline" compile_readline=yes AC_DEFINE_UNQUOTED(USE_NEW_READLINE_INTERFACE) else diff --git a/include/Makefile.am b/include/Makefile.am index 3adbb31f235..01b8f295be4 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -39,23 +39,23 @@ SUPERCLEANFILES = mysql_version.h my_config.h DISTCLEANFILES = sched.h $(SUPERCLEANFILES) clean: - $(RM) -f readline/* + $(RM) -fr readline distclean: - $(RM) -f readline/* + $(RM) -fr readline all-local: my_config.h # Since we include my_config.h it better exist from the beginning link_sources: $(CP) ../config.h my_config.h - $(RM) -f readline/* + -$(RM) -fr readline @readline_h_ln_cmd@ # Keep automake happy my_config.h: ../config.h $(CP) ../config.h my_config.h - $(RM) -f readline/* + -$(RM) -fr readline @readline_h_ln_cmd@ # These files should not be included in distributions since they are diff --git a/include/m_ctype.h b/include/m_ctype.h index e5f1c4fc3c0..9e69a3c8f91 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -90,7 +90,7 @@ enum my_lex_states MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END, MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL, MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE, - MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_COLON, + MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_SEMICOLON, MY_LEX_SET_VAR, MY_LEX_USER_END, MY_LEX_HOSTNAME, MY_LEX_SKIP, MY_LEX_USER_VARIABLE_DELIMITER, MY_LEX_SYSTEM_VAR, MY_LEX_IDENT_OR_KEYWORD, diff --git a/include/my_base.h b/include/my_base.h index 61d4c4e3225..54c739bde23 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -287,6 +287,9 @@ enum ha_base_keytype { #define HA_ERR_ROW_IS_REFERENCED 152 /* Cannot delete a parent row */ #define HA_ERR_NO_SAVEPOINT 153 /* No savepoint with that name */ #define HA_ERR_NON_UNIQUE_BLOCK_SIZE 154 /* Non unique key block size */ +#define HA_ERR_OLD_METADATA 155 /* The frm file on disk is old */ +#define HA_ERR_TABLE_EXIST 156 /* The table existed in storage engine */ +#define HA_ERR_NO_CONNECTION 157 /* Could not connect to storage engine */ /* Other constants */ diff --git a/include/myisam.h b/include/myisam.h index ed4f4aff8fe..452b32dbefd 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -36,7 +36,7 @@ extern "C" { /* defines used by myisam-funktions */ /* The following defines can be increased if necessary */ -#define MI_MAX_KEY 32 /* Max allowed keys */ +#define MI_MAX_KEY 64 /* Max allowed keys */ #define MI_MAX_KEY_SEG 16 /* Max segments for key */ #define MI_MAX_KEY_LENGTH 1000 diff --git a/include/mysql_embed.h b/include/mysql_embed.h index 7a169d4133e..8e65087c566 100644 --- a/include/mysql_embed.h +++ b/include/mysql_embed.h @@ -26,6 +26,7 @@ #undef HAVE_OPENSSL #undef HAVE_ISAM #undef HAVE_SMEM /* No shared memory */ +#undef HAVE_NDBCLUSTER_DB /* No NDB cluster */ #define DONT_USE_RAID diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c index 77bb4231404..8388009dc9c 100644 --- a/innobase/btr/btr0btr.c +++ b/innobase/btr/btr0btr.c @@ -589,28 +589,29 @@ btr_page_get_father_for_rec( if (btr_node_ptr_get_child_page_no(node_ptr) != buf_frame_get_page_no(page)) { - fprintf(stderr, -"InnoDB: Dump of the child page:\n"); + fputs("InnoDB: Dump of the child page:\n", stderr); buf_page_print(buf_frame_align(page)); - fprintf(stderr, -"InnoDB: Dump of the parent page:\n"); + fputs("InnoDB: Dump of the parent page:\n", stderr); buf_page_print(buf_frame_align(node_ptr)); - fprintf(stderr, -"InnoDB: Corruption of an index tree: table %s, index %s,\n" + fputs("InnoDB: Corruption of an index tree: table ", stderr); + ut_print_name(stderr, + UT_LIST_GET_FIRST(tree->tree_indexes)->table_name); + fputs(", index ", stderr); + ut_print_name(stderr, + UT_LIST_GET_FIRST(tree->tree_indexes)->name); + fprintf(stderr, ",\n" "InnoDB: father ptr page no %lu, child page no %lu\n", - (UT_LIST_GET_FIRST(tree->tree_indexes))->table_name, - (UT_LIST_GET_FIRST(tree->tree_indexes))->name, - (unsigned long) btr_node_ptr_get_child_page_no(node_ptr), - (unsigned long) buf_frame_get_page_no(page)); + (ulong) btr_node_ptr_get_child_page_no(node_ptr), + (ulong) buf_frame_get_page_no(page)); page_rec_print(page_rec_get_next(page_get_infimum_rec(page))); page_rec_print(node_ptr); - fprintf(stderr, + fputs( "InnoDB: You should dump + drop + reimport the table to fix the\n" "InnoDB: corruption. If the crash happens at the database startup, see\n" -"InnoDB: section 6.1 of http://www.innodb.com/ibman.html about forcing\n" -"InnoDB: recovery. Then dump + drop + reimport.\n"); +"InnoDB: section 6.1 of http://www.innodb.com/ibman.php about forcing\n" +"InnoDB: recovery. Then dump + drop + reimport.\n", stderr); } ut_a(btr_node_ptr_get_child_page_no(node_ptr) == @@ -1053,7 +1054,7 @@ btr_root_raise_and_insert( /* We play safe and reset the free bits for the new page */ -/* printf("Root raise new page no %lu\n", +/* fprintf(stderr, "Root raise new page no %lu\n", buf_frame_get_page_no(new_page)); */ ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), @@ -1602,7 +1603,7 @@ func_start: /* 5. Move then the records to the new page */ if (direction == FSP_DOWN) { -/* printf("Split left\n"); */ +/* fputs("Split left\n", stderr); */ page_move_rec_list_start(new_page, page, move_limit, mtr); left_page = new_page; @@ -1610,7 +1611,7 @@ func_start: lock_update_split_left(right_page, left_page); } else { -/* printf("Split right\n"); */ +/* fputs("Split right\n", stderr); */ page_move_rec_list_end(new_page, page, move_limit, mtr); left_page = page; @@ -1646,7 +1647,7 @@ func_start: ibuf_update_free_bits_for_two_pages_low(cursor->index, left_page, right_page, mtr); - /* printf("Split and insert done %lu %lu\n", + /* fprintf(stderr, "Split and insert done %lu %lu\n", buf_frame_get_page_no(left_page), buf_frame_get_page_no(right_page)); */ return(rec); @@ -1666,7 +1667,7 @@ func_start: /* We play safe and reset the free bits for new_page */ ibuf_reset_free_bits(cursor->index, new_page); - /* printf("Split second round %lu\n", + /* fprintf(stderr, "Split second round %lu\n", buf_frame_get_page_no(page)); */ n_iterations++; ut_ad(n_iterations < 2); @@ -1680,7 +1681,7 @@ func_start: ibuf_update_free_bits_for_two_pages_low(cursor->index, left_page, right_page, mtr); - /* printf("Split and insert done %lu %lu\n", + /* fprintf(stderr, "Split and insert done %lu %lu\n", buf_frame_get_page_no(left_page), buf_frame_get_page_no(right_page)); */ @@ -1927,7 +1928,7 @@ btr_compress( left_page_no = btr_page_get_prev(page, mtr); right_page_no = btr_page_get_next(page, mtr); -/* printf("Merge left page %lu right %lu \n", left_page_no, +/* fprintf(stderr, "Merge left page %lu right %lu \n", left_page_no, right_page_no); */ node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); @@ -2164,6 +2165,7 @@ btr_discard_page( ut_ad(btr_check_node_ptr(tree, merge_page, mtr)); } +#ifdef UNIV_DEBUG /***************************************************************** Prints size info of a B-tree. */ @@ -2177,8 +2179,9 @@ btr_print_size( mtr_t mtr; if (tree->type & DICT_IBUF) { - printf( - "Sorry, cannot print info of an ibuf tree: use ibuf functions\n"); + fputs( + "Sorry, cannot print info of an ibuf tree: use ibuf functions\n", + stderr); return; } @@ -2189,14 +2192,14 @@ btr_print_size( seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; - printf("INFO OF THE NON-LEAF PAGE SEGMENT\n"); + fputs("INFO OF THE NON-LEAF PAGE SEGMENT\n", stderr); fseg_print(seg, &mtr); if (!(tree->type & DICT_UNIVERSAL)) { seg = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; - printf("INFO OF THE LEAF PAGE SEGMENT\n"); + fputs("INFO OF THE LEAF PAGE SEGMENT\n", stderr); fseg_print(seg, &mtr); } @@ -2224,7 +2227,7 @@ btr_print_recursive( ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); - printf("NODE ON LEVEL %lu page number %lu\n", + fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n", (ulong) btr_page_get_level(page, mtr), (ulong) buf_frame_get_page_no(page)); @@ -2271,8 +2274,8 @@ btr_print_tree( mtr_t mtr; page_t* root; - printf("--------------------------\n"); - printf("INDEX TREE PRINT\n"); + fputs("--------------------------\n" + "INDEX TREE PRINT\n", stderr); mtr_start(&mtr); @@ -2284,6 +2287,7 @@ btr_print_tree( btr_validate_tree(tree); } +#endif /* UNIV_DEBUG */ /**************************************************************** Checks that the node pointer to a page is appropriate. */ @@ -2329,6 +2333,22 @@ btr_check_node_ptr( } /**************************************************************** +Display identification information for a record. */ +static +void +btr_index_rec_validate_report( +/*==========================*/ + page_t* page, /* in: index page */ + rec_t* rec, /* in: index record */ + dict_index_t* index) /* in: index */ +{ + fputs("InnoDB: Record in ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, ", page %lu, at offset %lu\n", + buf_frame_get_page_no(page), (ulint)(rec - page)); +} + +/**************************************************************** Checks the size and number of fields in a record based on the definition of the index. */ @@ -2342,13 +2362,10 @@ btr_index_rec_validate( should print hex dump of record and page on error */ { - dtype_t* type; - byte* data; ulint len; ulint n; ulint i; page_t* page; - char err_buf[1000]; page = buf_frame_align(rec); @@ -2363,14 +2380,9 @@ btr_index_rec_validate( n = dict_index_get_n_fields(index); if (rec_get_n_fields(rec) != n) { - fprintf(stderr, -"InnoDB: Record in index %s in table %s, page %lu, at offset %lu\n" -"InnoDB: has %lu fields, should have %lu\n", - index->name, index->table_name, - (unsigned long) buf_frame_get_page_no(page), - (unsigned long) (rec - page), - (unsigned long) rec_get_n_fields(rec), - (unsigned long) n); + btr_index_rec_validate_report(page, rec, index); + fprintf(stderr, "InnoDB: has %lu fields, should have %lu\n", + (ulong) rec_get_n_fields(rec), (ulong) n); if (!dump_on_error) { @@ -2379,16 +2391,17 @@ btr_index_rec_validate( buf_page_print(page); - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: corrupt record %s\n", err_buf); + fputs("InnoDB: corrupt record ", stderr); + rec_print(stderr, rec); + putc('\n', stderr); return(FALSE); } for (i = 0; i < n; i++) { - data = rec_get_nth_field(rec, i, &len); + dtype_t* type = dict_index_get_nth_type(index, i); - type = dict_index_get_nth_type(index, i); + rec_get_nth_field(rec, i, &len); if ((dict_index_get_nth_field(index, i)->prefix_len == 0 && len != UNIV_SQL_NULL && dtype_is_fixed_size(type) @@ -2399,15 +2412,10 @@ btr_index_rec_validate( && len != dict_index_get_nth_field(index, i)->prefix_len)) { + btr_index_rec_validate_report(page, rec, index); fprintf(stderr, -"InnoDB: Record in index %s in table %s, page %lu, at offset %lu\n" "InnoDB: field %lu len is %lu, should be %lu\n", - index->name, index->table_name, - (unsigned long) buf_frame_get_page_no(page), - (unsigned long) (rec - page), - (unsigned long) i, - (unsigned long) len, - (unsigned long) dtype_get_fixed_size(type)); + (ulong) i, (ulong) len, (ulong) dtype_get_fixed_size(type)); if (!dump_on_error) { @@ -2416,9 +2424,9 @@ btr_index_rec_validate( buf_page_print(page); - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, - "InnoDB: corrupt record %s\n", err_buf); + fputs("InnoDB: corrupt record ", stderr); + rec_print(stderr, rec); + putc('\n', stderr); return(FALSE); } @@ -2438,7 +2446,6 @@ btr_index_page_validate( page_t* page, /* in: index page */ dict_index_t* index) /* in: index */ { - rec_t* rec; page_cur_t cur; ibool ret = TRUE; @@ -2446,14 +2453,12 @@ btr_index_page_validate( page_cur_move_to_next(&cur); for (;;) { - rec = (&cur)->rec; - if (page_cur_is_after_last(&cur)) { break; } - if (!btr_index_rec_validate(rec, index, TRUE)) { + if (!btr_index_rec_validate(cur.rec, index, TRUE)) { return(FALSE); } @@ -2465,6 +2470,46 @@ btr_index_page_validate( } /**************************************************************** +Report an error on one page of an index tree. */ +static +void +btr_validate_report1( + /* out: TRUE if ok */ + dict_index_t* index, /* in: index */ + ulint level, /* in: B-tree level */ + page_t* page) /* in: index page */ +{ + fprintf(stderr, "InnoDB: Error in page %lu of ", + buf_frame_get_page_no(page)); + dict_index_name_print(stderr, index); + if (level) { + fprintf(stderr, ", index tree level %lu", level); + } + putc('\n', stderr); +} + +/**************************************************************** +Report an error on two pages of an index tree. */ +static +void +btr_validate_report2( + /* out: TRUE if ok */ + dict_index_t* index, /* in: index */ + ulint level, /* in: B-tree level */ + page_t* page1, /* in: first index page */ + page_t* page2) /* in: second index page */ +{ + fprintf(stderr, "InnoDB: Error in pages %lu and %lu of ", + buf_frame_get_page_no(page1), + buf_frame_get_page_no(page2)); + dict_index_name_print(stderr, index); + if (level) { + fprintf(stderr, ", index tree level %lu", level); + } + putc('\n', stderr); +} + +/**************************************************************** Validates index tree level. */ static ibool @@ -2489,7 +2534,6 @@ btr_validate_level( ibool ret = TRUE; dict_index_t* index; mtr_t mtr; - char err_buf[1000]; mtr_start(&mtr); @@ -2520,10 +2564,7 @@ loop: /* Check ordering etc. of records */ if (!page_validate(page, index)) { - fprintf(stderr, -"InnoDB: Error in page %lu in index %s table %s, index tree level %lu\n", - (ulong) buf_frame_get_page_no(page), index->name, - index->table_name, (ulong) level); + btr_validate_report1(index, level, page); ret = FALSE; } else if (level == 0) { @@ -2553,25 +2594,22 @@ loop: page_rec_get_next(page_get_infimum_rec(right_page)), UT_LIST_GET_FIRST(tree->tree_indexes)) >= 0) { - fprintf(stderr, - "InnoDB: Error on pages %lu and %lu in index %s table %s\n", - (ulong) buf_frame_get_page_no(page), - (ulong) right_page_no, - index->name, index->table_name); + btr_validate_report2(index, level, page, right_page); - fprintf(stderr, - "InnoDB: records in wrong order on adjacent pages\n"); + fputs("InnoDB: records in wrong order" + " on adjacent pages\n", stderr); buf_page_print(page); buf_page_print(right_page); - rec_sprintf(err_buf, 900, - page_rec_get_prev(page_get_supremum_rec(page))); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - - rec_sprintf(err_buf, 900, - page_rec_get_next(page_get_infimum_rec(right_page))); - fprintf(stderr, "InnoDB: record %s\n", err_buf); + fputs("InnoDB: record ", stderr); + rec_print(stderr, page_rec_get_prev( + page_get_supremum_rec(page))); + putc('\n', stderr); + fputs("InnoDB: record ", stderr); + rec_print(stderr, page_rec_get_next( + page_get_infimum_rec(right_page))); + putc('\n', stderr); ret = FALSE; } @@ -2594,32 +2632,27 @@ loop: || node_ptr != btr_page_get_father_for_rec(tree, page, page_rec_get_prev(page_get_supremum_rec(page)), &mtr)) { - fprintf(stderr, - "InnoDB: Error on page %lu in index %s table %s\n", - (unsigned long) buf_frame_get_page_no(page), - index->name, index->table_name); + btr_validate_report1(index, level, page); - fprintf(stderr, - "InnoDB: node pointer to the page is wrong\n"); + fputs("InnoDB: node pointer to the page is wrong\n", + stderr); buf_page_print(father_page); buf_page_print(page); - rec_sprintf(err_buf, 900, node_ptr); - - fprintf(stderr, "InnoDB: node ptr %s\n", err_buf); + fputs("InnoDB: node ptr ", stderr); + rec_print(stderr, node_ptr); - fprintf(stderr, + fprintf(stderr, "\n" "InnoDB: node ptr child page n:o %lu\n", (unsigned long) btr_node_ptr_get_child_page_no(node_ptr)); - rec_sprintf(err_buf, 900, + fputs("InnoDB: record on page ", stderr); + rec_print(stderr, btr_page_get_father_for_rec(tree, page, page_rec_get_prev(page_get_supremum_rec(page)), &mtr)); - - fprintf(stderr, "InnoDB: record on page %s\n", - err_buf); + putc('\n', stderr); ret = FALSE; goto node_ptr_fails; @@ -2637,27 +2670,19 @@ loop: if (cmp_dtuple_rec(node_ptr_tuple, node_ptr) != 0) { - fprintf(stderr, - "InnoDB: Error on page %lu in index %s table %s\n", - (ulong) buf_frame_get_page_no(page), - index->name, index->table_name); + btr_validate_report1(index, level, page); buf_page_print(father_page); buf_page_print(page); - fprintf(stderr, - "InnoDB: Error: node ptrs differ on levels > 0\n"); - - rec_sprintf(err_buf, 900, node_ptr); - - fprintf(stderr, "InnoDB: node ptr %s\n", - err_buf); - rec_sprintf(err_buf, 900, - page_rec_get_next( + fputs("InnoDB: Error: node ptrs differ" + " on levels > 0\n" + "InnoDB: node ptr ", stderr); + rec_print(stderr, node_ptr); + fputs("InnoDB: first rec ", stderr); + rec_print(stderr, page_rec_get_next( page_get_infimum_rec(page))); - - fprintf(stderr, "InnoDB: first rec %s\n", - err_buf); + putc('\n', stderr); ret = FALSE; mem_heap_free(heap); @@ -2689,13 +2714,12 @@ loop: if (right_node_ptr != page_rec_get_next(node_ptr)) { ret = FALSE; - fprintf(stderr, - "InnoDB: node pointer to the right page is wrong\n"); + fputs( + "InnoDB: node pointer to the right page is wrong\n", + stderr); - fprintf(stderr, - "InnoDB: Error on page %lu in index %s table %s\n", - (unsigned long) buf_frame_get_page_no(page), - index->name, index->table_name); + btr_validate_report1(index, level, + page); buf_page_print(father_page); buf_page_print(page); @@ -2709,13 +2733,12 @@ loop: page_get_infimum_rec( right_father_page))) { ret = FALSE; - fprintf(stderr, - "InnoDB: node pointer 2 to the right page is wrong\n"); + fputs( + "InnoDB: node pointer 2 to the right page is wrong\n", + stderr); - fprintf(stderr, - "InnoDB: Error on page %lu in index %s table %s\n", - (unsigned long) buf_frame_get_page_no(page), - index->name, index->table_name); + btr_validate_report1(index, level, + page); buf_page_print(father_page); buf_page_print(right_father_page); @@ -2727,13 +2750,12 @@ loop: != btr_page_get_next(father_page, &mtr)) { ret = FALSE; - fprintf(stderr, - "InnoDB: node pointer 3 to the right page is wrong\n"); + fputs( + "InnoDB: node pointer 3 to the right page is wrong\n", + stderr); - fprintf(stderr, - "InnoDB: Error on page %lu in index %s table %s\n", - (unsigned long) buf_frame_get_page_no(page), - index->name, index->table_name); + btr_validate_report1(index, level, + page); buf_page_print(father_page); buf_page_print(right_father_page); diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c index fdc8343e190..e67d1d76113 100644 --- a/innobase/btr/btr0cur.c +++ b/innobase/btr/btr0cur.c @@ -120,7 +120,6 @@ static void btr_cur_latch_leaves( /*=================*/ - dict_tree_t* tree __attribute__((unused)), /* in: index tree */ page_t* page, /* in: leaf page where the search converged */ ulint space, /* in: space id */ @@ -133,7 +132,7 @@ btr_cur_latch_leaves( ulint right_page_no; page_t* get_page; - ut_ad(tree && page && mtr); + ut_ad(page && mtr); if (latch_mode == BTR_SEARCH_LEAF) { @@ -366,17 +365,19 @@ btr_cur_search_to_nth_level( B-tree. These let us end up in the right B-tree leaf. In that leaf we use the original search mode. */ - if (mode == PAGE_CUR_GE) { + switch (mode) { + case PAGE_CUR_GE: page_mode = PAGE_CUR_L; - } else if (mode == PAGE_CUR_G) { + break; + case PAGE_CUR_G: page_mode = PAGE_CUR_LE; - } else if (mode == PAGE_CUR_LE) { - page_mode = PAGE_CUR_LE; - } else if (mode == PAGE_CUR_LE_OR_EXTENDS) { - page_mode = PAGE_CUR_LE_OR_EXTENDS; - } else { - ut_ad(mode == PAGE_CUR_L); - page_mode = PAGE_CUR_L; + break; + default: + ut_ad(mode == PAGE_CUR_L + || mode == PAGE_CUR_LE + || mode == PAGE_CUR_LE_OR_EXTENDS); + page_mode = mode; + break; } /* Loop and search until we arrive at the desired level */ @@ -451,7 +452,7 @@ retry_page_get: if (height == 0) { if (rw_latch == RW_NO_LATCH) { - btr_cur_latch_leaves(tree, page, space, + btr_cur_latch_leaves(page, space, page_no, latch_mode, cursor, mtr); } @@ -478,6 +479,9 @@ retry_page_get: /* If this is the desired level, leave the loop */ + ut_ad(height + == btr_page_get_level(page_cur_get_page(page_cursor), mtr)); + if (level == height) { if (level > 0) { @@ -591,7 +595,7 @@ btr_cur_open_at_index_side( } if (height == 0) { - btr_cur_latch_leaves(tree, page, space, page_no, + btr_cur_latch_leaves(page, space, page_no, latch_mode, cursor, mtr); /* In versions <= 3.23.52 we had forgotten to @@ -697,7 +701,7 @@ btr_cur_open_at_rnd_pos( } if (height == 0) { - btr_cur_latch_leaves(tree, page, space, page_no, + btr_cur_latch_leaves(page, space, page_no, latch_mode, cursor, mtr); } @@ -830,6 +834,24 @@ btr_cur_ins_lock_and_undo( } /***************************************************************** +Report information about a transaction. */ +static +void +btr_cur_trx_report( +/*===============*/ + const trx_t* trx, /* in: transaction */ + const dict_index_t* index, /* in: index */ + const char* op) /* in: operation */ +{ + fprintf(stderr, "Trx with id %lu %lu going to ", + ut_dulint_get_high(trx->id), + ut_dulint_get_low(trx->id)); + fputs(op, stderr); + dict_index_name_print(stderr, index); + putc('\n', stderr); +} + +/***************************************************************** Tries to perform an insert to a page in an index tree, next to cursor. It is assumed that mtr holds an x-latch on the page. The operation does not succeed if there is too little space on the page. If there is just @@ -876,18 +898,13 @@ btr_cur_optimistic_insert( index = cursor->index; if (!dtuple_check_typed_no_assert(entry)) { - fprintf(stderr, -"InnoDB: Error in a tuple to insert into table %s index %s\n", - index->table_name, index->name); + fputs("InnoDB: Error in a tuple to insert into ", stderr); + dict_index_name_print(stderr, index); } if (btr_cur_print_record_ops && thr) { - printf( - "Trx with id %lu %lu going to insert to table %s index %s\n", - (unsigned long) ut_dulint_get_high(thr_get_trx(thr)->id), - (unsigned long) ut_dulint_get_low(thr_get_trx(thr)->id), - index->table_name, index->name); - dtuple_print(entry); + btr_cur_trx_report(thr_get_trx(thr), index, "insert into "); + dtuple_print(stderr, entry); } ut_ad(mtr_memo_contains(mtr, buf_block_align(page), @@ -980,21 +997,15 @@ calculate_sizes_again: *rec = page_cur_tuple_insert(page_cursor, entry, mtr); - if (!(*rec)) { - char* err_buf = mem_alloc(1000); - - dtuple_sprintf(err_buf, 900, entry); - - fprintf(stderr, - "InnoDB: Error: cannot insert tuple %s to index %s of table %s\n" - "InnoDB: max insert size %lu\n", - err_buf, index->name, index->table->name, - (unsigned long) max_size); - - mem_free(err_buf); + if (!*rec) { + fputs("InnoDB: Error: cannot insert tuple ", stderr); + dtuple_print(stderr, entry); + fputs(" into ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, "\nInnoDB: max insert size %lu\n", + (ulong) max_size); + ut_error; } - - ut_a(*rec); /* <- We calculated above the record would fit */ } #ifdef BTR_CUR_HASH_ADAPT @@ -1010,7 +1021,8 @@ calculate_sizes_again: lock_update_insert(*rec); } -/* printf("Insert to page %lu, max ins size %lu, rec %lu ind type %lu\n", +/* fprintf(stderr, "Insert into page %lu, max ins size %lu," + " rec %lu ind type %lu\n", buf_frame_get_page_no(page), max_size, rec_size + PAGE_DIR_SLOT_SIZE, type); */ @@ -1363,12 +1375,8 @@ btr_cur_update_in_place( trx = thr_get_trx(thr); if (btr_cur_print_record_ops && thr) { - printf( - "Trx with id %lu %lu going to update table %s index %s\n", - (unsigned long) ut_dulint_get_high(thr_get_trx(thr)->id), - (unsigned long) ut_dulint_get_low(thr_get_trx(thr)->id), - index->table_name, index->name); - rec_print(rec); + btr_cur_trx_report(trx, index, "update "); + rec_print(stderr, rec); } /* Do lock checking and undo logging */ @@ -1467,12 +1475,8 @@ btr_cur_optimistic_update( index = cursor->index; if (btr_cur_print_record_ops && thr) { - printf( - "Trx with id %lu %lu going to update table %s index %s\n", - (unsigned long) ut_dulint_get_high(thr_get_trx(thr)->id), - (unsigned long) ut_dulint_get_low(thr_get_trx(thr)->id), - index->table_name, index->name); - rec_print(rec); + btr_cur_trx_report(thr_get_trx(thr), index, "update "); + rec_print(stderr, rec); } ut_ad(mtr_memo_contains(mtr, buf_block_align(page), @@ -2016,12 +2020,8 @@ btr_cur_del_mark_set_clust_rec( index = cursor->index; if (btr_cur_print_record_ops && thr) { - printf( - "Trx with id %lu %lu going to del mark table %s index %s\n", - (unsigned long) ut_dulint_get_high(thr_get_trx(thr)->id), - (unsigned long) ut_dulint_get_low(thr_get_trx(thr)->id), - index->table_name, index->name); - rec_print(rec); + btr_cur_trx_report(thr_get_trx(thr), index, "del mark "); + rec_print(stderr, rec); } ut_ad(index->type & DICT_CLUSTERED); @@ -2156,12 +2156,9 @@ btr_cur_del_mark_set_sec_rec( rec = btr_cur_get_rec(cursor); if (btr_cur_print_record_ops && thr) { - printf( - "Trx with id %lu %lu going to del mark table %s index %s\n", - (unsigned long) ut_dulint_get_high(thr_get_trx(thr)->id), - (unsigned long) ut_dulint_get_low(thr_get_trx(thr)->id), - cursor->index->table_name, cursor->index->name); - rec_print(rec); + btr_cur_trx_report(thr_get_trx(thr), cursor->index, + "del mark "); + rec_print(stderr, rec); } err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index, diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index 2093d5ea757..f2b03f9f348 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -803,7 +803,7 @@ btr_search_guess_on_hash( success = FALSE; /* - printf("Tree id %lu, page index id %lu fold %lu\n", + fprintf(stderr, "Tree id %lu, page index id %lu fold %lu\n", ut_dulint_get_low(tree_id), ut_dulint_get_low(btr_page_get_index_id(page)), fold); @@ -1517,8 +1517,9 @@ check_next_rec: ha_insert_for_fold(table, ins_fold, ins_rec); /* - printf("Hash insert for %s, fold %lu\n", - cursor->index->name, ins_fold); + fputs("Hash insert for ", stderr); + dict_index_name_print(stderr, cursor->index); + fprintf(stderr, " fold %lu\n", ins_fold); */ } else { ha_insert_for_fold(table, next_fold, next_rec); @@ -1545,7 +1546,6 @@ btr_search_validate(void) ulint n_page_dumps = 0; ibool ok = TRUE; ulint i; - char rec_str[500]; rw_lock_x_lock(&btr_search_latch); @@ -1566,29 +1566,25 @@ btr_search_validate(void) fprintf(stderr, " InnoDB: Error in an adaptive hash index pointer to page %lu\n" -"ptr mem address %lu index id %lu %lu, node fold %lu, rec fold %lu\n", - (ulong) buf_frame_get_page_no(page), - (ulong)(node->data), - (ulong) ut_dulint_get_high(btr_page_get_index_id(page)), - (ulong) ut_dulint_get_low(btr_page_get_index_id(page)), - (ulong) node->fold, - (ulong) rec_fold((rec_t*)(node->data), - block->curr_n_fields, - block->curr_n_bytes, - btr_page_get_index_id(page))); - - rec_sprintf(rec_str, 450, (rec_t*)(node->data)); - - fprintf(stderr, - "InnoDB: Record %s\n" - "InnoDB: on that page.", rec_str); - - fprintf(stderr, -"Page mem address %lu, is hashed %lu, n fields %lu, n bytes %lu\n" +"ptr mem address %p index id %lu %lu, node fold %lu, rec fold %lu\n", + (ulong) buf_frame_get_page_no(page), + node->data, + (ulong) ut_dulint_get_high(btr_page_get_index_id(page)), + (ulong) ut_dulint_get_low(btr_page_get_index_id(page)), + (ulong) node->fold, + (ulong) rec_fold((rec_t*)(node->data), + block->curr_n_fields, + block->curr_n_bytes, + btr_page_get_index_id(page))); + + fputs("InnoDB: Record ", stderr); + rec_print(stderr, (rec_t*)(node->data)); + fprintf(stderr, "\nInnoDB: on that page." +"Page mem address %p, is hashed %lu, n fields %lu, n bytes %lu\n" "side %lu\n", - (ulong) page, (ulong) block->is_hashed, - (ulong) block->curr_n_fields, - (ulong) block->curr_n_bytes, (ulong) block->curr_side); + page, (ulong) block->is_hashed, + (ulong) block->curr_n_fields, + (ulong) block->curr_n_bytes, (ulong) block->curr_side); if (n_page_dumps < 20) { buf_page_print(page); diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 844880238fa..7a5ef3c5e14 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -223,12 +223,14 @@ in the free list to the frames. buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */ -ulint buf_dbg_counter = 0; /* This is used to insert validation +#ifdef UNIV_DEBUG +static ulint buf_dbg_counter = 0; /* This is used to insert validation operations in excution in the debug version */ ibool buf_debug_prints = FALSE; /* If this is set TRUE, the program prints info whenever read-ahead or flush occurs */ +#endif /* UNIV_DEBUG */ /************************************************************************ Calculates a page checksum which is stored to the page when it is written @@ -372,19 +374,12 @@ buf_page_print( dict_index_t* index; ulint checksum; ulint old_checksum; - char* buf; - - buf = mem_alloc(4 * UNIV_PAGE_SIZE); - - ut_sprintf_buf(buf, read_buf, UNIV_PAGE_SIZE); ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Page dump in ascii and hex (%lu bytes):\n%s", - (ulong) UNIV_PAGE_SIZE, buf); - fprintf(stderr, "InnoDB: End of page dump\n"); - - mem_free(buf); + fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n", + (ulint)UNIV_PAGE_SIZE); + ut_print_buf(stderr, read_buf, UNIV_PAGE_SIZE); + fputs("InnoDB: End of page dump\n", stderr); checksum = buf_calc_page_new_checksum(read_buf); old_checksum = buf_calc_page_old_checksum(read_buf); @@ -433,17 +428,16 @@ buf_page_print( index = dict_index_find_on_id_low( btr_page_get_index_id(read_buf)); if (index) { - fprintf(stderr, - "InnoDB: and table %s index %s\n", - index->table_name, - index->name); + fputs("InnoDB: (", stderr); + dict_index_name_print(stderr, index); + fputs(")\n", stderr); } } } else if (fil_page_get_type(read_buf) == FIL_PAGE_INODE) { - fprintf(stderr, "InnoDB: Page may be an 'inode' page\n"); + fputs("InnoDB: Page may be an 'inode' page\n", stderr); } else if (fil_page_get_type(read_buf) == FIL_PAGE_IBUF_FREE_LIST) { - fprintf(stderr, - "InnoDB: Page may be an insert buffer free list page\n"); + fputs("InnoDB: Page may be an insert buffer free list page\n", + stderr); } } @@ -1551,11 +1545,12 @@ buf_page_init( "InnoDB: Error: page %lu %lu already found from the hash table\n", (ulong) space, (ulong) offset); +#ifdef UNIV_DEBUG buf_print(); buf_LRU_print(); buf_validate(); buf_LRU_validate(); - +#endif /* UNIV_DEBUG */ ut_a(0); } @@ -1732,11 +1727,12 @@ buf_page_create( /* If we get here, the page was not in buf_pool: init it there */ +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("Creating space %lu page %lu to buffer\n", - (ulong) space, - (ulong) offset); + fprintf(stderr, "Creating space %lu page %lu to buffer\n", + (ulong) space, (ulong) offset); } +#endif /* UNIV_DEBUG */ block = free_block; @@ -1789,8 +1785,6 @@ buf_page_io_complete( /*=================*/ buf_block_t* block) /* in: pointer to the block in question */ { - dict_index_t* index; - dulint id; ulint io_type; ulint read_page_no; @@ -1823,17 +1817,17 @@ buf_page_io_complete( "InnoDB: Database page corruption on disk or a failed\n" "InnoDB: file read of page %lu.\n", (ulong) block->offset); - fprintf(stderr, - "InnoDB: You may have to recover from a backup.\n"); + fputs( + "InnoDB: You may have to recover from a backup.\n", stderr); buf_page_print(block->frame); fprintf(stderr, "InnoDB: Database page corruption on disk or a failed\n" "InnoDB: file read of page %lu.\n", (ulong) block->offset); - fprintf(stderr, - "InnoDB: You may have to recover from a backup.\n"); - fprintf(stderr, + fputs( + "InnoDB: You may have to recover from a backup.\n", stderr); + fputs( "InnoDB: It is also possible that your operating\n" "InnoDB: system has corrupted its own file cache\n" "InnoDB: and rebooting your computer removes the\n" @@ -1844,12 +1838,13 @@ buf_page_io_complete( "InnoDB: the corrupt table. You can use CHECK\n" "InnoDB: TABLE to scan your table for corruption.\n" "InnoDB: Look also at section 6.1 of\n" - "InnoDB: http://www.innodb.com/ibman.html about\n" - "InnoDB: forcing recovery.\n"); + "InnoDB: http://www.innodb.com/ibman.php about\n" + "InnoDB: forcing recovery.\n", stderr); if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { - fprintf(stderr, - "InnoDB: Ending processing because of a corrupt database page.\n"); + fputs( + "InnoDB: Ending processing because of a corrupt database page.\n", + stderr); exit(1); } } @@ -1888,9 +1883,11 @@ buf_page_io_complete( rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ); +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("Has read "); + fputs("Has read ", stderr); } +#endif /* UNIV_DEBUG */ } else { ut_ad(io_type == BUF_IO_WRITE); @@ -1903,31 +1900,21 @@ buf_page_io_complete( buf_pool->n_pages_written++; +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("Has written "); + fputs("Has written ", stderr); } +#endif /* UNIV_DEBUG */ } mutex_exit(&(buf_pool->mutex)); +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("page space %lu page no %lu", (ulong) block->space, - (ulong) block->offset); - id = btr_page_get_index_id(block->frame); - - index = NULL; - /* The following can cause deadlocks if used: */ - /* - index = dict_index_get_if_in_cache(id); - - if (index) { - printf(" index name %s table %s", index->name, - index->table->name); - } - */ - - printf("\n"); + fprintf(stderr, "page space %lu page no %lu\n", + (ulong) block->space, (ulong) block->offset); } +#endif /* UNIV_DEBUG */ } /************************************************************************* @@ -1956,6 +1943,7 @@ buf_pool_invalidate(void) mutex_exit(&(buf_pool->mutex)); } +#ifdef UNIV_DEBUG /************************************************************************* Validates the buffer buf_pool data structure. */ @@ -2027,16 +2015,14 @@ buf_validate(void) } if (n_lru + n_free > buf_pool->curr_size) { - printf("n LRU %lu, n free %lu\n", (ulong) n_lru, - (ulong) n_free); + fprintf(stderr, "n LRU %lu, n free %lu\n", (ulong) n_lru, (ulong) n_free); ut_error; } ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru); if (UT_LIST_GET_LEN(buf_pool->free) != n_free) { - printf("Free list len %lu, free blocks %lu\n", - (ulong) UT_LIST_GET_LEN(buf_pool->free), - (ulong) n_free); + fprintf(stderr, "Free list len %lu, free blocks %lu\n", + (ulong) UT_LIST_GET_LEN(buf_pool->free), (ulong) n_free); ut_error; } ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush); @@ -2079,23 +2065,24 @@ buf_print(void) mutex_enter(&(buf_pool->mutex)); - printf("buf_pool size %lu \n", (ulong) size); - printf("database pages %lu \n", (ulong) UT_LIST_GET_LEN(buf_pool->LRU)); - printf("free pages %lu \n", (ulong) UT_LIST_GET_LEN(buf_pool->free)); - printf("modified database pages %lu \n", - (ulong) UT_LIST_GET_LEN(buf_pool->flush_list)); - - printf("n pending reads %lu \n", (ulong) buf_pool->n_pend_reads); - - printf("n pending flush LRU %lu list %lu single page %lu\n", - (ulong) buf_pool->n_flush[BUF_FLUSH_LRU], - (ulong) buf_pool->n_flush[BUF_FLUSH_LIST], - (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); - - printf("pages read %lu, created %lu, written %lu\n", - (ulong) buf_pool->n_pages_read, - (ulong) buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written); + fprintf(stderr, + "buf_pool size %lu\n" + "database pages %lu\n" + "free pages %lu\n" + "modified database pages %lu\n" + "n pending reads %lu\n" + "n pending flush LRU %lu list %lu single page %lu\n" + "pages read %lu, created %lu, written %lu\n", + (ulong) size, + (ulong) UT_LIST_GET_LEN(buf_pool->LRU), + (ulong) UT_LIST_GET_LEN(buf_pool->free), + (ulong) UT_LIST_GET_LEN(buf_pool->flush_list), + (ulong) buf_pool->n_pend_reads, + (ulong) buf_pool->n_flush[BUF_FLUSH_LRU], + (ulong) buf_pool->n_flush[BUF_FLUSH_LIST], + (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE], + (ulong) buf_pool->n_pages_read, buf_pool->n_pages_created, + (ulong) buf_pool->n_pages_written); /* Count the number of blocks belonging to each index in the buffer */ @@ -2138,16 +2125,17 @@ buf_print(void) for (i = 0; i < n_found; i++) { index = dict_index_get_if_in_cache(index_ids[i]); - printf("Block count for index %lu in buffer is about %lu", + fprintf(stderr, + "Block count for index %lu in buffer is about %lu", (ulong) ut_dulint_get_low(index_ids[i]), (ulong) counts[i]); if (index) { - printf(" index name %s table %s", index->name, - index->table->name); + putc(' ', stderr); + dict_index_name_print(stderr, index); } - printf("\n"); + putc('\n', stderr); } mem_free(index_ids); @@ -2155,6 +2143,7 @@ buf_print(void) ut_a(buf_validate()); } +#endif /* UNIV_DEBUG */ /************************************************************************* Returns the number of pending buf pool ios. */ @@ -2198,57 +2187,42 @@ Prints info of the buffer i/o. */ void buf_print_io( /*=========*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end)/* in: buffer end */ + FILE* file) /* in/out: buffer where to print */ { time_t current_time; double time_elapsed; ulint size; ut_ad(buf_pool); - - if (buf_end - buf < 400) { - - return; - } - size = buf_pool->curr_size; mutex_enter(&(buf_pool->mutex)); - buf += sprintf(buf, - "Buffer pool size %lu\n", (ulong) size); - buf += sprintf(buf, - "Free buffers %lu\n", (ulong) UT_LIST_GET_LEN(buf_pool->free)); - buf += sprintf(buf, - "Database pages %lu\n", (ulong) UT_LIST_GET_LEN(buf_pool->LRU)); -/* - buf += sprintf(buf, - "Lock heap buffers %lu\n", (ulong) buf_pool->n_lock_heap_pages); - buf += sprintf(buf, - "Hash index buffers %lu\n", (ulong) buf_pool->n_adaptive_hash_pages); -*/ - buf += sprintf(buf, - "Modified db pages %lu\n", - (ulong) UT_LIST_GET_LEN(buf_pool->flush_list)); if (srv_use_awe) { - buf += sprintf(buf, + fprintf(stderr, "AWE: Buffer pool memory frames %lu\n", (ulong) buf_pool->n_frames); - buf += sprintf(buf, + fprintf(stderr, "AWE: Database pages and free buffers mapped in frames %lu\n", (ulong) UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped)); } - - buf += sprintf(buf, "Pending reads %lu \n", (ulong) buf_pool->n_pend_reads); - - buf += sprintf(buf, + fprintf(file, + "Buffer pool size %lu\n" + "Free buffers %lu\n" + "Database pages %lu\n" + "Modified db pages %lu\n" + "Pending reads %lu\n" "Pending writes: LRU %lu, flush list %lu, single page %lu\n", - (ulong) (buf_pool->n_flush[BUF_FLUSH_LRU] - + buf_pool->init_flush[BUF_FLUSH_LRU]), - (ulong) (buf_pool->n_flush[BUF_FLUSH_LIST] - + buf_pool->init_flush[BUF_FLUSH_LIST]), + (ulong) size, + (ulong) UT_LIST_GET_LEN(buf_pool->free), + (ulong) UT_LIST_GET_LEN(buf_pool->LRU), + (ulong) UT_LIST_GET_LEN(buf_pool->flush_list), + (ulong) buf_pool->n_pend_reads, + (ulong) buf_pool->n_flush[BUF_FLUSH_LRU] + + buf_pool->init_flush[BUF_FLUSH_LRU], + (ulong) buf_pool->n_flush[BUF_FLUSH_LIST] + + buf_pool->init_flush[BUF_FLUSH_LIST], (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); current_time = time(NULL); @@ -2256,11 +2230,12 @@ buf_print_io( buf_pool->last_printout_time); buf_pool->last_printout_time = current_time; - buf += sprintf(buf, "Pages read %lu, created %lu, written %lu\n", - (ulong) buf_pool->n_pages_read, - (ulong) buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written); - buf += sprintf(buf, "%.2f reads/s, %.2f creates/s, %.2f writes/s\n", + fprintf(file, + "Pages read %lu, created %lu, written %lu\n" + "%.2f reads/s, %.2f creates/s, %.2f writes/s\n", + (ulong) buf_pool->n_pages_read, + (ulong) buf_pool->n_pages_created, + (ulong) buf_pool->n_pages_written, (buf_pool->n_pages_read - buf_pool->n_pages_read_old) / time_elapsed, (buf_pool->n_pages_created - buf_pool->n_pages_created_old) @@ -2269,21 +2244,21 @@ buf_print_io( / time_elapsed); if (srv_use_awe) { - buf += sprintf(buf, "AWE: %.2f page remaps/s\n", + fprintf(file, "AWE: %.2f page remaps/s\n", (buf_pool->n_pages_awe_remapped - buf_pool->n_pages_awe_remapped_old) / time_elapsed); } if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) { - buf += sprintf(buf, "Buffer pool hit rate %lu / 1000\n", + fprintf(file, "Buffer pool hit rate %lu / 1000\n", (ulong) (1000 - ((1000 * (buf_pool->n_pages_read - buf_pool->n_pages_read_old)) / (buf_pool->n_page_gets - buf_pool->n_page_gets_old)))); } else { - buf += sprintf(buf, - "No buffer pool page gets since the last printout\n"); + fputs("No buffer pool page gets since the last printout\n", + file); } buf_pool->n_page_gets_old = buf_pool->n_page_gets; @@ -2332,8 +2307,9 @@ buf_all_freed(void) if (!buf_flush_ready_for_replace(block)) { - /* printf("Page %lu %lu still fixed or dirty\n", - block->space, block->offset); */ + fprintf(stderr, + "Page %lu %lu still fixed or dirty\n", + (ulong) block->space, (ulong) block->offset); ut_error; } } diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index c568d5925fa..885bcf06456 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -32,6 +32,7 @@ flushed along with the original page. */ #define BUF_FLUSH_AREA ut_min(BUF_READ_AHEAD_AREA,\ buf_pool->curr_size / 16) +#ifdef UNIV_DEBUG /********************************************************************** Validates the flush list. */ static @@ -39,6 +40,7 @@ ibool buf_flush_validate_low(void); /*========================*/ /* out: TRUE if ok */ +#endif /* UNIV_DEBUG */ /************************************************************************ Inserts a modified block into the flush list. */ @@ -193,7 +195,7 @@ buf_flush_write_complete( buf_pool->LRU_flush_ended++; } - /* printf("n pending flush %lu\n", + /* fprintf(stderr, "n pending flush %lu\n", buf_pool->n_flush[block->flush_type]); */ if ((buf_pool->n_flush[block->flush_type] == 0) @@ -420,8 +422,8 @@ buf_flush_write_block_low( ut_ad(!ut_dulint_is_zero(block->newest_modification)); #ifdef UNIV_LOG_DEBUG - printf( - "Warning: cannot force log to disk in the log debug version!\n"); + fputs("Warning: cannot force log to disk in the log debug version!\n", + stderr); #else /* Force the log to the disk before writing the modified block */ log_write_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE); @@ -511,11 +513,13 @@ buf_flush_try_page( rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE); } +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("Flushing page space %lu, page no %lu \n", - (ulong) block->space, - (ulong) block->offset); + fprintf(stderr, + "Flushing page space %lu, page no %lu \n", + (ulong) block->space, (ulong) block->offset); } +#endif /* UNIV_DEBUG */ buf_flush_write_block_low(block); @@ -599,12 +603,14 @@ buf_flush_try_page( rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE); +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf( + fprintf(stderr, "Flushing single page space %lu, page no %lu \n", (ulong) block->space, (ulong) block->offset); } +#endif /* UNIV_DEBUG */ buf_flush_write_block_low(block); @@ -645,7 +651,7 @@ buf_flush_try_neighbors( high = offset + 1; } - /* printf("Flush area: low %lu high %lu\n", low, high); */ + /* fprintf(stderr, "Flush area: low %lu high %lu\n", low, high); */ if (high > fil_space_get_size(space)) { high = fil_space_get_size(space); @@ -793,7 +799,7 @@ buf_flush_batch( page_count += buf_flush_try_neighbors(space, offset, flush_type); - /* printf( + /* fprintf(stderr, "Flush type %lu, page no %lu, neighb %lu\n", flush_type, offset, page_count - old_page_count); */ @@ -831,17 +837,16 @@ buf_flush_batch( buf_flush_buffered_writes(); +#ifdef UNIV_DEBUG if (buf_debug_prints && page_count > 0) { - if (flush_type == BUF_FLUSH_LRU) { - printf("Flushed %lu pages in LRU flush\n", - (ulong) page_count); - } else if (flush_type == BUF_FLUSH_LIST) { - printf("Flushed %lu pages in flush list flush\n", - (ulong) page_count); - } else { - ut_error; - } + ut_a(flush_type == BUF_FLUSH_LRU + || flush_type == BUF_FLUSH_LIST); + fprintf(stderr, flush_type == BUF_FLUSH_LRU + ? "Flushed %lu pages in LRU flush\n" + : "Flushed %lu pages in flush list flush\n", + (ulong) page_count); } +#endif /* UNIV_DEBUG */ return(page_count); } @@ -933,6 +938,7 @@ buf_flush_free_margin(void) } } +#ifdef UNIV_DEBUG /********************************************************************** Validates the flush list. */ static @@ -982,3 +988,4 @@ buf_flush_validate(void) return(ret); } +#endif /* UNIV_DEBUG */ diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index c5faec17890..053161986e4 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -97,13 +97,14 @@ scan_again: } if (block->space == id) { +#ifdef UNIV_DEBUG if (buf_debug_prints) { printf( "Dropping space %lu page %lu\n", (ulong) block->space, (ulong) block->offset); } - +#endif if (block->is_hashed) { page_no = block->offset; @@ -207,12 +208,16 @@ buf_LRU_search_and_free_block( while (block != NULL) { ut_a(block->in_LRU_list); if (buf_flush_ready_for_replace(block)) { + +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf( + fprintf(stderr, "Putting space %lu page %lu to free list\n", (ulong) block->space, (ulong) block->offset); } +#endif /* UNIV_DEBUG */ + buf_LRU_block_remove_hashed_page(block); mutex_exit(&(buf_pool->mutex)); @@ -404,28 +409,21 @@ loop: fprintf(stderr, "InnoDB: Warning: difficult to find free blocks from\n" "InnoDB: the buffer pool (%lu search iterations)! Consider\n" - "InnoDB: increasing the buffer pool size.\n", - (ulong) n_iterations); - fprintf(stderr, + "InnoDB: increasing the buffer pool size.\n" "InnoDB: It is also possible that in your Unix version\n" "InnoDB: fsync is very slow, or completely frozen inside\n" "InnoDB: the OS kernel. Then upgrading to a newer version\n" "InnoDB: of your operating system may help. Look at the\n" - "InnoDB: number of fsyncs in diagnostic info below.\n"); - - fprintf(stderr, - "InnoDB: Pending flushes (fsync) log: %lu; buffer pool: %lu\n", - (ulong) fil_n_pending_log_flushes, - (ulong) fil_n_pending_tablespace_flushes); - fprintf(stderr, - "InnoDB: %lu OS file reads, %lu OS file writes, %lu OS fsyncs\n", - (ulong) os_n_file_reads, - (ulong) os_n_file_writes, - (ulong) os_n_fsyncs); - - fprintf(stderr, + "InnoDB: number of fsyncs in diagnostic info below.\n" + "InnoDB: Pending flushes (fsync) log: %lu; buffer pool: %lu\n" + "InnoDB: %lu OS file reads, %lu OS file writes, %lu OS fsyncs\n" "InnoDB: Starting InnoDB Monitor to print further\n" - "InnoDB: diagnostics to the standard output.\n"); + "InnoDB: diagnostics to the standard output.\n", + (ulong) n_iterations, + (ulong) fil_n_pending_log_flushes, + (ulong) fil_n_pending_tablespace_flushes, + (ulong) os_n_file_reads, (ulong) os_n_file_writes, + (ulong) os_n_fsyncs); mon_value_was = srv_print_innodb_monitor; started_monitor = TRUE; @@ -855,11 +853,12 @@ buf_LRU_block_remove_hashed_page( (ulong) block); } +#ifdef UNIV_DEBUG buf_print(); buf_LRU_print(); buf_validate(); buf_LRU_validate(); - +#endif ut_a(0); } @@ -889,6 +888,7 @@ buf_LRU_block_free_hashed_page( buf_LRU_block_free_non_file_page(block); } +#ifdef UNIV_DEBUG /************************************************************************** Validates the LRU list. */ @@ -975,7 +975,7 @@ buf_LRU_print(void) ut_ad(buf_pool); mutex_enter(&(buf_pool->mutex)); - printf("Pool ulint clock %lu\n", (ulong) buf_pool->ulint_clock); + fprintf(stderr, "Pool ulint clock %lu\n", (ulong) buf_pool->ulint_clock); block = UT_LIST_GET_FIRST(buf_pool->LRU); @@ -983,39 +983,40 @@ buf_LRU_print(void) while (block != NULL) { - printf("BLOCK %lu ", (ulong) block->offset); + fprintf(stderr, "BLOCK %lu ", (ulong) block->offset); if (block->old) { - printf("old "); + fputs("old ", stderr); } if (block->buf_fix_count) { - printf("buffix count %lu ", (ulong) block->buf_fix_count); + fprintf(stderr, "buffix count %lu ", + (ulong) block->buf_fix_count); } if (block->io_fix) { - printf("io_fix %lu ", (ulong) block->io_fix); + fprintf(stderr, "io_fix %lu ", (ulong) block->io_fix); } if (ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0) { - printf("modif. "); + fputs("modif. ", stderr); } - printf("LRU pos %lu ", (ulong) block->LRU_position); - frame = buf_block_get_frame(block); - printf("type %lu ", (ulong) fil_page_get_type(frame)); - printf("index id %lu ", (ulong) ut_dulint_get_low( - btr_page_get_index_id(frame))); + fprintf(stderr, "LRU pos %lu type %lu index id %lu ", + (ulong) block->LRU_position, + (ulong) fil_page_get_type(frame), + (ulong) ut_dulint_get_low(btr_page_get_index_id(frame))); block = UT_LIST_GET_NEXT(LRU, block); - len++; - if (len % 10 == 0) { - printf("\n"); + if (++len == 10) { + len = 0; + putc('\n', stderr); } } mutex_exit(&(buf_pool->mutex)); } +#endif /* UNIV_DEBUG */ diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c index 5ba27b8fee8..e0f8291977e 100644 --- a/innobase/buf/buf0rea.c +++ b/innobase/buf/buf0rea.c @@ -97,7 +97,8 @@ buf_read_page_low( log mutex: the read must be handled before other reads which might incur ibuf operations and thus write to the log */ - printf("Log debug: reading replicate page in sync mode\n"); + fputs("Log debug: reading replicate page in sync mode\n", + stderr); sync = TRUE; } @@ -117,7 +118,6 @@ buf_read_page_low( or is being dropped; if we succeed in initing the page in the buffer pool for read, then DISCARD cannot proceed until the read has completed */ - block = buf_page_init_for_read(err, mode, space, tablespace_version, offset); if (block == NULL) { @@ -125,11 +125,14 @@ buf_read_page_low( return(0); } +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("Posting read request for page %lu, sync %lu\n", + fprintf(stderr, + "Posting read request for page %lu, sync %lu\n", (ulong) offset, (ulong) sync); } +#endif ut_a(block->state == BUF_BLOCK_FILE_PAGE); @@ -281,12 +284,14 @@ buf_read_ahead_random( os_aio_simulated_wake_handler_threads(); +#ifdef UNIV_DEBUG if (buf_debug_prints && (count > 0)) { - - printf("Random read-ahead space %lu offset %lu pages %lu\n", + fprintf(stderr, + "Random read-ahead space %lu offset %lu pages %lu\n", (ulong) space, (ulong) offset, (ulong) count); } +#endif /* UNIV_DEBUG */ return(count); } @@ -566,11 +571,13 @@ buf_read_ahead_linear( /* Flush pages from the end of the LRU list if necessary */ buf_flush_free_margin(); +#ifdef UNIV_DEBUG if (buf_debug_prints && (count > 0)) { - printf( + fprintf(stderr, "LINEAR read-ahead space %lu offset %lu pages %lu\n", (ulong) space, (ulong) offset, (ulong) count); } +#endif /* UNIV_DEBUG */ return(count); } @@ -629,9 +636,13 @@ buf_read_ibuf_merge_pages( /* Flush pages from the end of the LRU list if necessary */ buf_flush_free_margin(); +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("Ibuf merge read-ahead pages %lu\n", (ulong) n_stored); + fprintf(stderr, + "Ibuf merge read-ahead space %lu pages %lu\n", + (ulong) space, (ulong) n_stored); } +#endif /* UNIV_DEBUG */ } /************************************************************************ @@ -695,8 +706,10 @@ buf_read_recv_pages( /* Flush pages from the end of the LRU list if necessary */ buf_flush_free_margin(); +#ifdef UNIV_DEBUG if (buf_debug_prints) { - printf("Recovery applies read-ahead pages %lu\n", - (ulong) n_stored); + fprintf(stderr, + "Recovery applies read-ahead pages %lu\n", (ulong) n_stored); } +#endif /* UNIV_DEBUG */ } diff --git a/innobase/data/data0data.c b/innobase/data/data0data.c index 0ed0efeb160..97ec1a1acd9 100644 --- a/innobase/data/data0data.c +++ b/innobase/data/data0data.c @@ -12,7 +12,6 @@ Created 5/30/1994 Heikki Tuuri #include "data0data.ic" #endif -#include "ut0rnd.h" #include "rem0rec.h" #include "rem0cmp.h" #include "page0page.h" @@ -22,12 +21,10 @@ Created 5/30/1994 Heikki Tuuri byte data_error; /* data pointers of tuple fields are initialized to point here for error checking */ +#ifdef UNIV_DEBUG ulint data_dummy; /* this is used to fool the compiler in dtuple_validate */ - -byte data_buf[8192]; /* used in generating test tuples */ -ulint data_rnd = 756511; - +#endif /* UNIV_DEBUG */ /* Some non-inlined functions used in the MySQL interface: */ void @@ -215,16 +212,15 @@ dtuple_check_typed_no_assert( { dfield_t* field; ulint i; - char err_buf[1000]; if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) { fprintf(stderr, "InnoDB: Error: index entry has %lu fields\n", (ulong) dtuple_get_n_fields(tuple)); - - dtuple_sprintf(err_buf, 900, tuple); - fprintf(stderr, -"InnoDB: Tuple contents: %s\n", err_buf); + dump: + fputs("InnoDB: Tuple contents: ", stderr); + dtuple_print(stderr, tuple); + putc('\n', stderr); return(FALSE); } @@ -234,12 +230,7 @@ dtuple_check_typed_no_assert( field = dtuple_get_nth_field(tuple, i); if (!dfield_check_typed_no_assert(field)) { - - dtuple_sprintf(err_buf, 900, tuple); - fprintf(stderr, -"InnoDB: Tuple contents: %s\n", err_buf); - - return(FALSE); + goto dump; } } @@ -291,6 +282,7 @@ dtuple_check_typed( return(TRUE); } +#ifdef UNIV_DEBUG /************************************************************** Validates the consistency of a tuple which must be complete, i.e, all fields must have been set. */ @@ -338,6 +330,7 @@ dtuple_validate( return(TRUE); } +#endif /* UNIV_DEBUG */ /***************************************************************** Pretty prints a dfield value according to its data type. */ @@ -356,7 +349,7 @@ dfield_print( data = dfield_get_data(dfield); if (len == UNIV_SQL_NULL) { - printf("NULL"); + fputs("NULL", stderr); return; } @@ -366,18 +359,12 @@ dfield_print( if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) { for (i = 0; i < len; i++) { - - if (isprint((char)(*data))) { - printf("%c", (char)*data); - } else { - printf(" "); - } - - data++; + int c = *data++; + putc(isprint(c) ? c : ' ', stderr); } } else if (mtype == DATA_INT) { ut_a(len == 4); /* only works for 32-bit integers */ - printf("%i", (int)mach_read_from_4(data)); + fprintf(stderr, "%d", (int)mach_read_from_4(data)); } else { ut_error; } @@ -402,7 +389,7 @@ dfield_print_also_hex( data = dfield_get_data(dfield); if (len == UNIV_SQL_NULL) { - printf("NULL"); + fputs("NULL", stderr); return; } @@ -414,15 +401,12 @@ dfield_print_also_hex( print_also_hex = FALSE; for (i = 0; i < len; i++) { - - if (isprint((char)(*data))) { - printf("%c", (char)*data); - } else { + int c = *data++; + if (!isprint(c)) { print_also_hex = TRUE; - printf(" "); + c = ' '; } - - data++; + putc(c, stderr); } if (!print_also_hex) { @@ -430,18 +414,18 @@ dfield_print_also_hex( return; } - printf(" Hex: "); + fputs(" Hex: ", stderr); data = dfield_get_data(dfield); for (i = 0; i < len; i++) { - printf("%02lx", (ulong)*data); + fprintf(stderr, "%02lx", (ulint)*data); data++; } } else if (mtype == DATA_INT) { - ut_a(len == 4); /* inly works for 32-bit integers */ - printf("%i", (int)mach_read_from_4(data)); + ut_a(len == 4); /* only works for 32-bit integers */ + fprintf(stderr, "%d", (int)mach_read_from_4(data)); } else { ut_error; } @@ -453,6 +437,7 @@ The following function prints the contents of a tuple. */ void dtuple_print( /*=========*/ + FILE* f, /* in: output stream */ dtuple_t* tuple) /* in: tuple */ { dfield_t* field; @@ -461,73 +446,24 @@ dtuple_print( n_fields = dtuple_get_n_fields(tuple); - printf("DATA TUPLE: %lu fields;\n", (ulong) n_fields); - - for (i = 0; i < n_fields; i++) { - printf(" %lu:", (ulong) i); - - field = dtuple_get_nth_field(tuple, i); - - if (field->len != UNIV_SQL_NULL) { - ut_print_buf(field->data, field->len); - } else { - printf(" SQL NULL"); - } - - printf(";"); - } - - printf("\n"); - - dtuple_validate(tuple); -} - -/************************************************************** -The following function prints the contents of a tuple to a buffer. */ - -ulint -dtuple_sprintf( -/*===========*/ - /* out: printed length in bytes */ - char* buf, /* in: print buffer */ - ulint buf_len,/* in: buf length in bytes */ - dtuple_t* tuple) /* in: tuple */ -{ - dfield_t* field; - ulint n_fields; - ulint len; - ulint i; - - len = 0; - - n_fields = dtuple_get_n_fields(tuple); + fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields); for (i = 0; i < n_fields; i++) { - if (len + 30 > buf_len) { - - return(len); - } - - len += sprintf(buf + len, " %lu:", (ulong) i); + fprintf(f, " %lu:", (ulong) i); field = dtuple_get_nth_field(tuple, i); if (field->len != UNIV_SQL_NULL) { - if (5 * field->len + len + 30 > buf_len) { - - return(len); - } - - len += ut_sprintf_buf(buf + len, field->data, - field->len); + ut_print_buf(f, field->data, field->len); } else { - len += sprintf(buf + len, " SQL NULL"); + fputs(" SQL NULL", f); } - len += sprintf(buf + len, ";"); + putc(';', f); } - return(len); + putc('\n', f); + ut_ad(dtuple_validate(tuple)); } /****************************************************************** @@ -561,7 +497,6 @@ dtuple_convert_big_rec( ibool is_externally_stored; ulint i; ulint j; - char err_buf[1000]; ut_a(dtuple_check_typed_no_assert(entry)); @@ -570,10 +505,9 @@ dtuple_convert_big_rec( if (size > 1000000000) { fprintf(stderr, "InnoDB: Warning: tuple size very big: %lu\n", (ulong) size); - - dtuple_sprintf(err_buf, 900, entry); - fprintf(stderr, -"InnoDB: Tuple contents: %s\n", err_buf); + fputs("InnoDB: Tuple contents: ", stderr); + dtuple_print(stderr, entry); + putc('\n', stderr); } heap = mem_heap_create(size + dtuple_get_n_fields(entry) diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c index 71ce5ff3d58..698b5361dfa 100644 --- a/innobase/data/data0type.c +++ b/innobase/data/data0type.c @@ -104,6 +104,7 @@ dtype_form_prtype( return(old_prtype + (charset_coll << 16)); } +#ifdef UNIV_DEBUG /************************************************************************* Validates a data type structure. */ @@ -122,6 +123,7 @@ dtype_validate( return(TRUE); } +#endif /* UNIV_DEBUG */ /************************************************************************* Prints a data type structure. */ @@ -140,19 +142,19 @@ dtype_print( mtype = type->mtype; prtype = type->prtype; if (mtype == DATA_VARCHAR) { - printf("DATA_VARCHAR"); + fputs("DATA_VARCHAR", stderr); } else if (mtype == DATA_CHAR) { - printf("DATA_CHAR"); + fputs("DATA_CHAR", stderr); } else if (mtype == DATA_BINARY) { - printf("DATA_BINARY"); + fputs("DATA_BINARY", stderr); } else if (mtype == DATA_INT) { - printf("DATA_INT"); + fputs("DATA_INT", stderr); } else if (mtype == DATA_MYSQL) { - printf("DATA_MYSQL"); + fputs("DATA_MYSQL", stderr); } else if (mtype == DATA_SYS) { - printf("DATA_SYS"); + fputs("DATA_SYS", stderr); } else { - printf("type %lu", (ulong) mtype); + fprintf(stderr, "type %lu", (ulong) mtype); } len = type->len; @@ -160,24 +162,24 @@ dtype_print( if ((type->mtype == DATA_SYS) || (type->mtype == DATA_VARCHAR) || (type->mtype == DATA_CHAR)) { - printf(" "); + putc(' ', stderr); if (prtype == DATA_ROW_ID) { - printf("DATA_ROW_ID"); + fputs("DATA_ROW_ID", stderr); len = DATA_ROW_ID_LEN; } else if (prtype == DATA_ROLL_PTR) { - printf("DATA_ROLL_PTR"); + fputs("DATA_ROLL_PTR", stderr); len = DATA_ROLL_PTR_LEN; } else if (prtype == DATA_TRX_ID) { - printf("DATA_TRX_ID"); + fputs("DATA_TRX_ID", stderr); len = DATA_TRX_ID_LEN; } else if (prtype == DATA_MIX_ID) { - printf("DATA_MIX_ID"); + fputs("DATA_MIX_ID", stderr); } else if (prtype == DATA_ENGLISH) { - printf("DATA_ENGLISH"); + fputs("DATA_ENGLISH", stderr); } else { - printf("prtype %lu", (ulong) mtype); + fprintf(stderr, "prtype %lu", (ulong) mtype); } } - printf(" len %lu prec %lu", (ulong) len, (ulong) type->prec); + fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec); } diff --git a/innobase/dict/dict0boot.c b/innobase/dict/dict0boot.c index 46cf6c7788d..8e1629819f3 100644 --- a/innobase/dict/dict0boot.c +++ b/innobase/dict/dict0boot.c @@ -71,7 +71,8 @@ dict_hdr_get_new_id( compile wrong */ if (0 == ut_dulint_cmp(id, ut_dulint_max)) { - printf("Max id\n"); + /* TO DO: remove this code, or make it conditional */ + ut_dbg_null_ptr = 0; } id = ut_dulint_add(id, 1); diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index 6a951317d47..f0b5906ec50 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -25,71 +25,6 @@ Created 1/8/1996 Heikki Tuuri #include "trx0roll.h" #include "usr0sess.h" -/* Maximum lengths of identifiers in MySQL, in bytes */ -#define MAX_TABLE_NAME_LEN 64 -#define MAX_COLUMN_NAME_LEN 64 -#define MAX_IDENTIFIER_LEN 255 - -/********************************************************************* -Based on a table object, this function builds the entry to be inserted -in the SYS_TABLES system table. */ -static -dtuple_t* -dict_create_sys_tables_tuple( -/*=========================*/ - /* out: the tuple which should be inserted */ - dict_table_t* table, /* in: table */ - mem_heap_t* heap); /* in: memory heap from which the memory for - the built tuple is allocated */ -/********************************************************************* -Based on a table object, this function builds the entry to be inserted -in the SYS_COLUMNS system table. */ -static -dtuple_t* -dict_create_sys_columns_tuple( -/*==========================*/ - /* out: the tuple which should be inserted */ - dict_table_t* table, /* in: table */ - ulint i, /* in: column number */ - mem_heap_t* heap); /* in: memory heap from which the memory for - the built tuple is allocated */ -/********************************************************************* -Based on an index object, this function builds the entry to be inserted -in the SYS_INDEXES system table. */ -static -dtuple_t* -dict_create_sys_indexes_tuple( -/*==========================*/ - /* out: the tuple which should be inserted */ - dict_index_t* index, /* in: index */ - mem_heap_t* heap, /* in: memory heap from which the memory for - the built tuple is allocated */ - trx_t* trx); /* in: transaction handle */ -/********************************************************************* -Based on an index object, this function builds the entry to be inserted -in the SYS_FIELDS system table. */ -static -dtuple_t* -dict_create_sys_fields_tuple( -/*=========================*/ - /* out: the tuple which should be inserted */ - dict_index_t* index, /* in: index */ - ulint i, /* in: field number */ - mem_heap_t* heap); /* in: memory heap from which the memory for - the built tuple is allocated */ -/********************************************************************* -Creates the tuple with which the index entry is searched for -writing the index tree root page number, if such a tree is created. */ -static -dtuple_t* -dict_create_search_tuple( -/*=====================*/ - /* out: the tuple for search */ - dtuple_t* tuple, /* in: the tuple inserted in the SYS_INDEXES - table */ - mem_heap_t* heap); /* in: memory heap from which the memory for - the built tuple is allocated */ - /********************************************************************* Based on a table object, this function builds the entry to be inserted in the SYS_TABLES system table. */ @@ -97,7 +32,6 @@ static dtuple_t* dict_create_sys_tables_tuple( /*=========================*/ - /* out: the tuple which should be inserted */ dict_table_t* table, /* in: table */ mem_heap_t* heap) /* in: memory heap from which the memory for the built tuple is allocated */ @@ -359,9 +293,8 @@ dict_create_sys_indexes_tuple( /*==========================*/ /* out: the tuple which should be inserted */ dict_index_t* index, /* in: index */ - mem_heap_t* heap, /* in: memory heap from which the memory for + mem_heap_t* heap) /* in: memory heap from which the memory for the built tuple is allocated */ - trx_t* trx) /* in: transaction handle */ { dict_table_t* sys_indexes; dict_table_t* table; @@ -369,7 +302,6 @@ dict_create_sys_indexes_tuple( dfield_t* dfield; byte* ptr; - UT_NOT_USED(trx); #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ @@ -415,7 +347,9 @@ dict_create_sys_indexes_tuple( dfield_set_data(dfield, ptr, 4); /* 7: SPACE --------------------------*/ - ut_a(DICT_SYS_INDEXES_SPACE_NO_FIELD == 7); +#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 7 +#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7" +#endif dfield = dtuple_get_nth_field(entry, 5); @@ -425,7 +359,9 @@ dict_create_sys_indexes_tuple( dfield_set_data(dfield, ptr, 4); /* 8: PAGE_NO --------------------------*/ - ut_a(DICT_SYS_INDEXES_PAGE_NO_FIELD == 8); +#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 8 +#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8" +#endif dfield = dtuple_get_nth_field(entry, 6); @@ -593,8 +529,7 @@ dict_build_index_def_step( index->page_no = FIL_NULL; - row = dict_create_sys_indexes_tuple(index, node->heap, - thr_get_trx(thr)); + row = dict_create_sys_indexes_tuple(index, node->heap); node->ind_row = row; ins_node_set_new_row(node->ind_def, row); @@ -630,7 +565,6 @@ ulint dict_create_index_tree_step( /*========================*/ /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ - que_thr_t* thr, /* in: query thread */ ind_node_t* node) /* in: index create node */ { dict_index_t* index; @@ -643,7 +577,6 @@ dict_create_index_tree_step( #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ - UT_NOT_USED(thr); index = node->index; table = node->table; @@ -1003,7 +936,7 @@ dict_create_index_step( if (node->state == INDEX_CREATE_INDEX_TREE) { - err = dict_create_index_tree_step(thr, node); + err = dict_create_index_tree_step(node); if (err != DB_SUCCESS) { @@ -1101,13 +1034,13 @@ dict_create_or_check_foreign_constraint_tables(void) if (table1) { fprintf(stderr, "InnoDB: dropping incompletely created SYS_FOREIGN table\n"); - row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx); + row_drop_table_for_mysql((char*)"SYS_FOREIGN", trx, TRUE); } if (table2) { fprintf(stderr, "InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n"); - row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS", trx); + row_drop_table_for_mysql((char*)"SYS_FOREIGN_COLS", trx, TRUE); } fprintf(stderr, @@ -1157,8 +1090,8 @@ dict_create_or_check_foreign_constraint_tables(void) fprintf(stderr, "InnoDB: dropping incompletely created SYS_FOREIGN tables\n"); - row_drop_table_for_mysql((char *) "SYS_FOREIGN", trx); - row_drop_table_for_mysql((char *) "SYS_FOREIGN_COLS", trx); + row_drop_table_for_mysql((char*)"SYS_FOREIGN", trx, TRUE); + row_drop_table_for_mysql((char*)"SYS_FOREIGN_COLS", trx, TRUE); error = DB_MUST_GET_MORE_FILE_SPACE; } @@ -1207,11 +1140,22 @@ dict_create_add_foreigns_to_dictionary( que_t* graph; ulint number = start_id + 1; ulint len; - ulint namelen; ulint error; - char* ebuf = dict_foreign_err_buf; + FILE* ef = dict_foreign_err_file; ulint i; - char buf[10000]; + char* sql; + char* sqlend; + /* This procedure builds an InnoDB stored procedure which will insert + the necessary rows into SYS_FOREIGN and SYS_FOREIGN_COLS. */ + static const char str1[] = "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n" + "BEGIN\n" + "INSERT INTO SYS_FOREIGN VALUES("; + static const char str2[] = ");\n"; + static const char str3[] = + "INSERT INTO SYS_FOREIGN_COLS VALUES("; + static const char str4[] = + "COMMIT WORK;\n" + "END;\n"; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1231,58 +1175,75 @@ loop: return(DB_SUCCESS); } - /* Build an InnoDB stored procedure which will insert the necessary - rows to SYS_FOREIGN and SYS_FOREIGN_COLS */ - - len = 0; - - len += sprintf(buf, - "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n" - "BEGIN\n"); - - namelen = strlen(table->name); - ut_a(namelen < MAX_TABLE_NAME_LEN); - if (foreign->id == NULL) { /* Generate a new constraint id */ - foreign->id = mem_heap_alloc(foreign->heap, namelen + 20); + ulint namelen = strlen(table->name); + char* id = mem_heap_alloc(foreign->heap, namelen + 20); /* no overflow if number < 1e13 */ - sprintf(foreign->id, "%s_ibfk_%lu", table->name, (ulong) number); - number++; + sprintf(id, "%s_ibfk_%lu", table->name, (ulong) number++); + foreign->id = id; } - ut_a(strlen(foreign->id) < MAX_IDENTIFIER_LEN); - ut_a(len < (sizeof buf) - - 46 - 2 * MAX_TABLE_NAME_LEN - MAX_IDENTIFIER_LEN - 20); + len = (sizeof str1) + (sizeof str2) + (sizeof str4) - 3 + + 9/* ' and , chars */ + 10/* 32-bit integer */ + + ut_strlenq(foreign->id, '\'') * (foreign->n_fields + 1) + + ut_strlenq(table->name, '\'') + + ut_strlenq(foreign->referenced_table_name, '\''); + + for (i = 0; i < foreign->n_fields; i++) { + len += 9/* ' and , chars */ + 10/* 32-bit integer */ + + (sizeof str3) + (sizeof str2) - 2 + + ut_strlenq(foreign->foreign_col_names[i], '\'') + + ut_strlenq(foreign->referenced_col_names[i], '\''); + } - len += sprintf(buf + len, - "INSERT INTO SYS_FOREIGN VALUES('%s', '%s', '%s', %lu);\n", - foreign->id, - table->name, - foreign->referenced_table_name, - (ulong) (foreign->n_fields - + (foreign->type << 24))); + sql = sqlend = mem_alloc(len + 1); + + /* INSERT INTO SYS_FOREIGN VALUES(...); */ + memcpy(sqlend, str1, (sizeof str1) - 1); + sqlend += (sizeof str1) - 1; + *sqlend++ = '\''; + sqlend = ut_strcpyq(sqlend, '\'', foreign->id); + *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; + sqlend = ut_strcpyq(sqlend, '\'', table->name); + *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; + sqlend = ut_strcpyq(sqlend, '\'', foreign->referenced_table_name); + *sqlend++ = '\'', *sqlend++ = ','; + sqlend += sprintf(sqlend, "%010lu", + foreign->n_fields + (foreign->type << 24)); + memcpy(sqlend, str2, (sizeof str2) - 1); + sqlend += (sizeof str2) - 1; for (i = 0; i < foreign->n_fields; i++) { - ut_a(len < (sizeof buf) - - 51 - 2 * MAX_COLUMN_NAME_LEN - - MAX_IDENTIFIER_LEN - 20); - - len += sprintf(buf + len, - "INSERT INTO SYS_FOREIGN_COLS VALUES('%s', %lu, '%s', '%s');\n", - foreign->id, - (ulong) i, - foreign->foreign_col_names[i], - foreign->referenced_col_names[i]); + /* INSERT INTO SYS_FOREIGN_COLS VALUES(...); */ + memcpy(sqlend, str3, (sizeof str3) - 1); + sqlend += (sizeof str3) - 1; + *sqlend++ = '\''; + sqlend = ut_strcpyq(sqlend, '\'', foreign->id); + *sqlend++ = '\''; *sqlend++ = ','; + sqlend += sprintf(sqlend, "%010lu", (ulong) i); + *sqlend++ = ','; *sqlend++ = '\''; + sqlend = ut_strcpyq(sqlend, '\'', + foreign->foreign_col_names[i]); + *sqlend++ = '\''; *sqlend++ = ','; *sqlend++ = '\''; + sqlend = ut_strcpyq(sqlend, '\'', + foreign->referenced_col_names[i]); + *sqlend++ = '\''; + memcpy(sqlend, str2, (sizeof str2) - 1); + sqlend += (sizeof str2) - 1; } - ut_a(len < (sizeof buf) - 19); - len += sprintf(buf + len,"COMMIT WORK;\nEND;\n"); + memcpy(sqlend, str4, sizeof str4); + sqlend += sizeof str4; - graph = pars_sql(buf); + ut_a(sqlend == sql + len + 1); + + graph = pars_sql(sql); ut_a(graph); + mem_free(sql); + graph->trx = trx; trx->graph = NULL; @@ -1298,14 +1259,17 @@ loop: if (error == DB_DUPLICATE_KEY) { mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(ebuf); - ut_a(strlen(ebuf) < DICT_FOREIGN_ERR_BUF_LEN - - MAX_TABLE_NAME_LEN - MAX_IDENTIFIER_LEN - 201); - sprintf(ebuf + strlen(ebuf), -" Error in foreign key constraint creation for table %s.\n" -"A foreign key constraint of name %s\n" -"already exists (note that internally InnoDB adds 'databasename/'\n" -"in front of the user-defined constraint name).\n", table->name, foreign->id); + rewind(ef); + ut_print_timestamp(ef); + fputs(" Error in foreign key constraint creation for table ", + ef); + ut_print_name(ef, table->name); + fputs(".\nA foreign key constraint of name ", ef); + ut_print_name(ef, foreign->id); + fputs("\nalready exists." + " (Note that internally InnoDB adds 'databasename/'\n" + "in front of the user-defined constraint name).\n", + ef); mutex_exit(&dict_foreign_err_mutex); @@ -1318,12 +1282,12 @@ loop: "InnoDB: internal error number %lu\n", (ulong) error); mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(ebuf); - ut_a(strlen(ebuf) < DICT_FOREIGN_ERR_BUF_LEN - - MAX_TABLE_NAME_LEN - 124); - sprintf(ebuf + strlen(ebuf), -" Internal error in foreign key constraint creation for table %s.\n" -"See the MySQL .err log in the datadir for more information.\n", table->name); + ut_print_timestamp(ef); + fputs(" Internal error in foreign key constraint creation" + " for table ", ef); + ut_print_name(ef, table->name); + fputs(".\n" + "See the MySQL .err log in the datadir for more information.\n", ef); mutex_exit(&dict_foreign_err_mutex); return(error); diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index cf4b0482aa2..b22d93d6bd8 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -43,16 +43,16 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve #define DICT_HEAP_SIZE 100 /* initial memory heap size when creating a table or index object */ -#define DICT_POOL_PER_PROCEDURE_HASH 512 /* buffer pool max size per stored - procedure hash table fixed size in - bytes */ #define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table hash table fixed size in bytes */ #define DICT_POOL_PER_COL_HASH 128 /* buffer pool max size per column hash table fixed size in bytes */ #define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data dictionary varying size in bytes */ - + +/* Identifies generated InnoDB foreign key names */ +static char dict_ibfk[] = "_ibfk_"; + /************************************************************************** Adds a column to the data dictionary hash table. */ static @@ -132,16 +132,6 @@ dict_index_build_internal_non_clust( dict_index_t* index); /* in: user representation of a non-clustered index */ /************************************************************************** -In an index tree, finds the index corresponding to a record in the tree. */ -UNIV_INLINE -dict_index_t* -dict_tree_find_index_low( -/*=====================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec); /* in: record for which to find correct - index */ -/************************************************************************** Removes a foreign constraint struct from the dictionet cache. */ static void @@ -177,40 +167,31 @@ dict_foreign_free( /*==============*/ dict_foreign_t* foreign); /* in, own: foreign key struct */ -/* Buffers for storing detailed information about the latest foreign key +/* Stream for storing detailed information about the latest foreign key and unique key errors */ -char* dict_foreign_err_buf = NULL; -char* dict_unique_err_buf = NULL; +FILE* dict_foreign_err_file = NULL; mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign and unique error buffers */ /************************************************************************ Checks if the database name in two table names is the same. */ -static + ibool dict_tables_have_same_db( /*=====================*/ - /* out: TRUE if same db name */ - char* name1, /* in: table name in the form dbname '/' tablename */ - char* name2) /* in: table name in the form dbname '/' tablename */ + /* out: TRUE if same db name */ + const char* name1, /* in: table name in the form + dbname '/' tablename */ + const char* name2) /* in: table name in the form + dbname '/' tablename */ { - ulint i; - - for (i = 0; i < 100000; i++) { - if (name1[i] == '/' && name2[i] == '/') { - + for (; *name1 == *name2; name1++, name2++) { + if (*name1 == '/') { return(TRUE); } - - if (name1[i] != name2[i]) { - - return(FALSE); - } + ut_a(*name1); /* the names must contain '/' */ } - - ut_error; - return(FALSE); } @@ -223,18 +204,11 @@ dict_remove_db_name( /* out: table name */ char* name) /* in: table name in the form dbname '/' tablename */ { - ulint i; - - for (i = 0; i < 100000 ; i++) { - if (name[i] == '/') { - - return(name + i + 1); - } - } - - ut_error; - - return(NULL); + char* s; + s = strchr(name, '/'); + ut_a(s); + if (s) s++; + return(s); } /************************************************************************ @@ -243,21 +217,14 @@ Get the database name length in a table name. */ ulint dict_get_db_name_len( /*=================*/ - /* out: database name length */ - char* name) /* in: table name in the form dbname '/' tablename */ + /* out: database name length */ + const char* name) /* in: table name in the form + dbname '/' tablename */ { - ulint i; - - for (i = 0; i < 100000 ; i++) { - if (name[i] == '/') { - - return(i); - } - } - - ut_error; - - return(0); + const char* s; + s = strchr(name, '/'); + ut_a(s); + return(s - name); } /************************************************************************ @@ -706,9 +673,6 @@ dict_init(void) dict_sys->col_hash = hash_create(buf_pool_get_max_size() / (DICT_POOL_PER_COL_HASH * UNIV_WORD_SIZE)); - dict_sys->procedure_hash = hash_create(buf_pool_get_max_size() / - (DICT_POOL_PER_PROCEDURE_HASH * - UNIV_WORD_SIZE)); dict_sys->size = 0; UT_LIST_INIT(dict_sys->table_LRU); @@ -716,10 +680,7 @@ dict_init(void) rw_lock_create(&dict_operation_lock); rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION); - dict_foreign_err_buf = mem_alloc(DICT_FOREIGN_ERR_BUF_LEN); - dict_foreign_err_buf[0] = '\0'; - dict_unique_err_buf = mem_alloc(DICT_FOREIGN_ERR_BUF_LEN); - dict_unique_err_buf[0] = '\0'; + dict_foreign_err_file = tmpfile(); mutex_create(&dict_foreign_err_mutex); mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH); } @@ -934,7 +895,6 @@ dict_table_rename_in_cache( dict_index_t* index; ulint fold; ulint old_size; - char* name_buf; char* old_name; ibool success; ulint i; @@ -984,16 +944,9 @@ dict_table_rename_in_cache( /* Remove table from the hash tables of tables */ HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, ut_fold_string(table->name), table); - old_name = mem_heap_alloc(table->heap, ut_strlen(table->name) + 1); - - ut_strcpy(old_name, table->name); - - name_buf = mem_heap_alloc(table->heap, ut_strlen(new_name) + 1); - - ut_memcpy(name_buf, new_name, ut_strlen(new_name) + 1); + old_name = mem_heap_strdup(table->heap, table->name); + table->name = mem_heap_strdup(table->heap, new_name); - table->name = name_buf; - /* Add table to hash table of tables */ HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, table); @@ -1060,30 +1013,27 @@ dict_table_rename_in_cache( ut_strlen(table->name) + 1); } - sprintf(foreign->foreign_table_name, "%s", table->name); + strcpy(foreign->foreign_table_name, table->name); - if (ut_str_contains(foreign->id, '/')) { + if (strchr(foreign->id, '/')) { ulint db_len; - char old_id[2000]; + char* old_id; /* This is a >= 4.0.18 format id */ - ut_a(ut_strlen(foreign->id) < 1999); - - ut_strcpy(old_id, foreign->id); + old_id = mem_strdup(foreign->id); if (ut_strlen(foreign->id) > ut_strlen(old_name) - + ut_strlen("_ibfk_") + + ((sizeof dict_ibfk) - 1) && 0 == ut_memcmp(foreign->id, old_name, ut_strlen(old_name)) && 0 == ut_memcmp( foreign->id + ut_strlen(old_name), - (char*)"_ibfk_", ut_strlen("_ibfk_"))) { + dict_ibfk, (sizeof dict_ibfk) - 1)) { /* This is a generated >= 4.0.18 format id */ - if (ut_strlen(table->name) - > ut_strlen(old_name)) { + if (ut_strlen(table->name) > ut_strlen(old_name)) { foreign->id = mem_heap_alloc( foreign->heap, ut_strlen(table->name) @@ -1092,7 +1042,8 @@ dict_table_rename_in_cache( /* Replace the prefix 'databasename/tablename' with the new names */ - sprintf(foreign->id, "%s%s", table->name, + strcpy(foreign->id, table->name); + strcat(foreign->id, old_id + ut_strlen(old_name)); } else { /* This is a >= 4.0.18 format id where the user @@ -1112,9 +1063,11 @@ dict_table_rename_in_cache( ut_memcpy(foreign->id, table->name, db_len); - sprintf(foreign->id + db_len, "%s", + strcpy(foreign->id + db_len, dict_remove_db_name(old_id)); } + + mem_free(old_id); } foreign = UT_LIST_GET_NEXT(foreign_list, foreign); @@ -1133,7 +1086,7 @@ dict_table_rename_in_cache( ut_strlen(table->name) + 1); } - sprintf(foreign->referenced_table_name, "%s", table->name); + strcpy(foreign->referenced_table_name, table->name); foreign = UT_LIST_GET_NEXT(referenced_list, foreign); } @@ -1185,7 +1138,11 @@ dict_table_remove_from_cache( #endif /* UNIV_SYNC_DEBUG */ ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - /* printf("Removing table %s from dictionary cache\n", table->name); */ +#if 0 + fputs("Removing table ", stderr); + ut_print_name(stderr, table->name, ULINT_UNDEFINED); + fputs(" from dictionary cache\n", stderr); +#endif /* Remove the foreign constraints from the cache */ foreign = UT_LIST_GET_LAST(table->foreign_list); @@ -2056,7 +2013,7 @@ dict_foreign_find_index( /*====================*/ /* out: matching index, NULL if not found */ dict_table_t* table, /* in: table */ - char** columns,/* in: array of column names */ + const char** columns,/* in: array of column names */ ulint n_cols, /* in: number of columns */ dict_index_t* types_idx)/* in: NULL or an index to whose types the column types must match */ @@ -2081,11 +2038,8 @@ dict_foreign_find_index( break; } - if (ut_strlen(columns[i]) != - ut_strlen(col_name) - || 0 != ut_cmp_in_lower_case(columns[i], - col_name, - ut_strlen(col_name))) { + if (0 != ut_cmp_in_lower_case(columns[i], + col_name)) { break; } @@ -2111,6 +2065,45 @@ dict_foreign_find_index( } /************************************************************************** +Report an error in a foreign key definition. */ +static +void +dict_foreign_error_report_low( + FILE* file, /* in: output stream */ + const char* name) /* in: table name */ +{ + rewind(file); + ut_print_timestamp(file); + fputs(" Error in foreign key constraint of table ", file); + ut_print_name(file, name); + fputs(":\n", file); +} + +/************************************************************************** +Report an error in a foreign key definition. */ +static +void +dict_foreign_error_report( + FILE* file, /* in: output stream */ + dict_foreign_t* fk, /* in: foreign key constraint */ + const char* msg) /* in: the error message */ +{ + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(file, fk->foreign_table_name); + fputs(msg, file); + fputs(" Constraint:\n", file); + dict_print_info_on_foreign_key_in_create_format(file, fk); + if (fk->foreign_index) { + fputs("\nThe index in the foreign key in table is ", file); + ut_print_name(file, fk->foreign_index->name); + fputs( +"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", + file); + } + mutex_exit(&dict_foreign_err_mutex); +} + +/************************************************************************** Adds a foreign key constraint object to the dictionary cache. May free the object if there already is an object with the same identifier in. At least one of the foreign table and the referenced table must already @@ -2124,10 +2117,10 @@ dict_foreign_add_to_cache( { dict_table_t* for_table; dict_table_t* ref_table; - dict_foreign_t* for_in_cache = NULL; + dict_foreign_t* for_in_cache = NULL; dict_index_t* index; - ibool added_to_referenced_list = FALSE; - char* buf = dict_foreign_err_buf; + ibool added_to_referenced_list= FALSE; + FILE* ef = dict_foreign_err_file; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex))); @@ -2157,30 +2150,16 @@ dict_foreign_add_to_cache( if (for_in_cache->referenced_table == NULL && ref_table) { index = dict_foreign_find_index(ref_table, - for_in_cache->referenced_col_names, - for_in_cache->n_fields, - for_in_cache->foreign_index); + (const char**) for_in_cache->referenced_col_names, + for_in_cache->n_fields, + for_in_cache->foreign_index); if (index == NULL) { - mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s:\n" + dict_foreign_error_report(ef, for_in_cache, "there is no index in referenced table which would contain\n" "the columns as the first columns, or the data types in the\n" -"referenced table do not match to the ones in table. Constraint:\n", - for_in_cache->foreign_table_name); - dict_print_info_on_foreign_key_in_create_format( - for_in_cache, buf + strlen(buf)); - if (for_in_cache->foreign_index) { - sprintf(buf + strlen(buf), -"\nThe index in the foreign key in table is %.500s\n" -"See http://www.innodb.com/ibman.html about correct foreign key definition.\n", - for_in_cache->foreign_index->name); - } - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); - mutex_exit(&dict_foreign_err_mutex); - +"referenced table do not match to the ones in table."); + if (for_in_cache == foreign) { mem_heap_free(foreign->heap); } @@ -2198,29 +2177,15 @@ dict_foreign_add_to_cache( if (for_in_cache->foreign_table == NULL && for_table) { index = dict_foreign_find_index(for_table, - for_in_cache->foreign_col_names, - for_in_cache->n_fields, - for_in_cache->referenced_index); + (const char**) for_in_cache->foreign_col_names, + for_in_cache->n_fields, + for_in_cache->referenced_index); if (index == NULL) { - mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s:\n" + dict_foreign_error_report(ef, for_in_cache, "there is no index in the table which would contain\n" "the columns as the first columns, or the data types in the\n" -"table do not match to the ones in the referenced table. Constraint:\n", - for_in_cache->foreign_table_name); - dict_print_info_on_foreign_key_in_create_format( - for_in_cache, buf + strlen(buf)); - if (for_in_cache->foreign_index) { - sprintf(buf + strlen(buf), -"\nIndex of the foreign key in the referenced table is %.500s\n" -"See http://www.innodb.com/ibman.html about correct foreign key definition.\n", - for_in_cache->referenced_index->name); - } - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); - mutex_exit(&dict_foreign_err_mutex); +"table do not match to the ones in the referenced table."); if (for_in_cache == foreign) { if (added_to_referenced_list) { @@ -2250,12 +2215,12 @@ Scans from pointer onwards. Stops if is at the start of a copy of 'string' where characters are compared without case sensitivity. Stops also at '\0'. */ static -char* +const char* dict_scan_to( /*=========*/ /* out: scanned up to this */ - char* ptr, /* in: scan from */ - const char *string) /* in: look for this */ + const char* ptr, /* in: scan from */ + const char* string) /* in: look for this */ { ibool success; ulint i; @@ -2287,18 +2252,18 @@ loop: /************************************************************************* Accepts a specified string. Comparisons are case-insensitive. */ -char* +const char* dict_accept( /*========*/ - /* out: if string was accepted, the pointer - is moved after that, else ptr is returned */ - char* ptr, /* in: scan from this */ - const char* string,/* in: accept only this string as the next - non-whitespace string */ - ibool* success)/* out: TRUE if accepted */ + /* out: if string was accepted, the pointer + is moved after that, else ptr is returned */ + const char* ptr, /* in: scan from this */ + const char* string, /* in: accept only this string as the next + non-whitespace string */ + ibool* success)/* out: TRUE if accepted */ { - char* old_ptr = ptr; - char* old_ptr2; + const char* old_ptr = ptr; + const char* old_ptr2; *success = FALSE; @@ -2323,21 +2288,27 @@ dict_accept( Scans an id. For the lexical definition of an 'id', see the code below. Strips backquotes or double quotes from around the id. */ static -char* +const char* dict_scan_id( /*=========*/ /* out: scanned to */ - char* ptr, /* in: scanned to */ - char** start, /* out: start of the id; NULL if no id was + const char* ptr, /* in: scanned to */ + mem_heap_t* heap, /* in: heap where to allocate the id + (NULL=id will not be allocated, but it + will point to string near ptr) */ + const char** id, /* out,own: the id; NULL if no id was scannable */ - ulint* len, /* out: length of the id */ - ibool accept_also_dot)/* in: TRUE if also a dot can appear in a + ibool accept_also_dot) + /* in: TRUE if also a dot can appear in a non-quoted id; in a quoted id it can appear always */ { - char quote = '\0'; + char quote = '\0'; + ulint len = 0; + const char* s; + char* d; - *start = NULL; + *id = NULL; while (isspace(*ptr)) { ptr++; @@ -2351,12 +2322,23 @@ dict_scan_id( if (*ptr == '`' || *ptr == '"') { quote = *ptr++; } - - *start = ptr; + + s = ptr; if (quote) { - while (*ptr != quote && *ptr != '\0') { + for (;;) { + if (!*ptr) { + /* Syntax error */ + return(ptr); + } + if (*ptr == quote) { + ptr++; + if (*ptr != quote) { + break; + } + } ptr++; + len++; } } else { while (!isspace(*ptr) && *ptr != '(' && *ptr != ')' @@ -2365,17 +2347,25 @@ dict_scan_id( ptr++; } + + len = ptr - s; } - *len = (ulint) (ptr - *start); - - if (quote) { - if (*ptr == quote) { - ptr++; - } else { - /* Syntax error */ - *start = NULL; + if (quote && heap) { + *id = d = mem_heap_alloc(heap, len + 1); + while (len--) { + if ((*d++ = *s++) == quote) { + s++; + } } + *d++ = 0; + ut_a(*s == quote); + ut_a(s + 1 == ptr); + } else if (heap) { + *id = mem_heap_strdupl(heap, s, len); + } else { + /* no heap given: id will point to source string */ + *id = (char*) s; } return(ptr); @@ -2384,26 +2374,26 @@ dict_scan_id( /************************************************************************* Tries to scan a column name. */ static -char* +const char* dict_scan_col( /*==========*/ /* out: scanned to */ - char* ptr, /* in: scanned to */ + const char* ptr, /* in: scanned to */ ibool* success,/* out: TRUE if success */ dict_table_t* table, /* in: table in which the column is */ dict_col_t** column, /* out: pointer to column if success */ - char** column_name,/* out: pointer to column->name if - success */ - ulint* column_name_len)/* out: column name length */ + mem_heap_t* heap, /* in: heap where to allocate the name */ + const char** name) /* out,own: the column name; NULL if no name + was scannable */ { dict_col_t* col; ulint i; - + *success = FALSE; - ptr = dict_scan_id(ptr, column_name, column_name_len, TRUE); + ptr = dict_scan_id(ptr, heap, name, TRUE); - if (column_name == NULL) { + if (*name == NULL) { return(ptr); /* Syntax error */ } @@ -2416,15 +2406,12 @@ dict_scan_col( col = dict_table_get_nth_col(table, i); - if (ut_strlen(col->name) == *column_name_len - && 0 == ut_cmp_in_lower_case(col->name, - *column_name, - *column_name_len)) { + if (0 == ut_cmp_in_lower_case(col->name, *name)) { /* Found */ *success = TRUE; *column = col; - *column_name = col->name; + strcpy((char*) *name, col->name); break; } @@ -2437,33 +2424,31 @@ dict_scan_col( /************************************************************************* Scans the referenced table name from an SQL string. */ static -char* +const char* dict_scan_table_name( /*=================*/ /* out: scanned to */ - char* ptr, /* in: scanned to */ + const char* ptr, /* in: scanned to */ dict_table_t** table, /* out: table object or NULL */ - char* name, /* in: foreign key table name */ + const char* name, /* in: foreign key table name */ ibool* success,/* out: TRUE if ok name found */ - char* second_table_name)/* in/out: buffer where to store - the referenced table name; must be at least - 2500 bytes */ + mem_heap_t* heap, /* in: heap where to allocate the id */ + const char** ref_name)/* out,own: the referenced table name; + NULL if no name was scannable */ { - char* database_name = NULL; - ulint database_name_len = 999999999; /* init to a dummy value to - suppress a compiler warning */ - char* table_name = NULL; - ulint table_name_len; - char* scanned_id; - ulint scanned_id_len; - ulint i; - + const char* database_name = NULL; + ulint database_name_len = 0; + const char* table_name = NULL; + ulint table_name_len; + const char* scan_name; + char* ref; + *success = FALSE; *table = NULL; - ptr = dict_scan_id(ptr, &scanned_id, &scanned_id_len, FALSE); + ptr = dict_scan_id(ptr, heap, &scan_name, FALSE); - if (scanned_id == NULL) { + if (scan_name == NULL) { return(ptr); /* Syntax error */ } @@ -2473,10 +2458,10 @@ dict_scan_table_name( ptr++; - database_name = scanned_id; - database_name_len = scanned_id_len; + database_name = scan_name; + database_name_len = strlen(database_name); - ptr = dict_scan_id(ptr, &table_name, &table_name_len, FALSE); + ptr = dict_scan_id(ptr, heap, &table_name, FALSE); if (table_name == NULL) { @@ -2490,65 +2475,57 @@ dict_scan_table_name( ... REFERENCES `databasename.tablename` ... starting from 4.0.18 it is ... REFERENCES `databasename`.`tablename` ... */ - - for (i = 0; i < scanned_id_len; i++) { - if (scanned_id[i] == '.') { - database_name = scanned_id; - database_name_len = i; - - scanned_id = scanned_id + i + 1; - scanned_id_len -= i + 1; + const char* s; + + for (s = scan_name; *s; s++) { + if (*s == '.') { + database_name = scan_name; + database_name_len = s - scan_name; + scan_name = ++s; + break;/* to do: multiple dots? */ } } - table_name = scanned_id; - table_name_len = scanned_id_len; + table_name = scan_name; } if (database_name == NULL) { /* Use the database name of the foreign key table */ database_name = name; - database_name_len = dict_get_db_name_len(name); } - if (table_name_len + database_name_len > 2000) { + table_name_len = strlen(table_name); + + ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2); - return(ptr); /* Too long name */ - } - #ifdef __WIN__ - ut_cpy_in_lower_case(second_table_name, database_name, - database_name_len); + ut_cpy_in_lower_case(ref, database_name, database_name_len); #else if (srv_lower_case_table_names) { - ut_cpy_in_lower_case(second_table_name, database_name, - database_name_len); + ut_cpy_in_lower_case(ref, database_name, database_name_len); } else { - ut_memcpy(second_table_name, database_name, - database_name_len); + memcpy(ref, database_name, database_name_len); } #endif - second_table_name[database_name_len] = '/'; + (ref)[database_name_len] = '/'; #ifdef __WIN__ - ut_cpy_in_lower_case(second_table_name + database_name_len + 1, - table_name, table_name_len); + ut_cpy_in_lower_case(ref + database_name_len + 1, + table_name, table_name_len + 1); #else if (srv_lower_case_table_names) { - ut_cpy_in_lower_case(second_table_name + database_name_len + 1, - table_name, table_name_len); + ut_cpy_in_lower_case(ref + database_name_len + 1, + table_name, table_name_len + 1); } else { - ut_memcpy(second_table_name + database_name_len + 1, - table_name, table_name_len); + strcpy(ref + database_name_len + 1, table_name); } #endif - second_table_name[database_name_len + 1 + table_name_len] = '\0'; *success = TRUE; - - *table = dict_table_get_low(second_table_name); + *ref_name = ref; + *table = dict_table_get_low(ref); return(ptr); } @@ -2556,20 +2533,19 @@ dict_scan_table_name( /************************************************************************* Skips one id. The id is allowed to contain also '.'. */ static -char* +const char* dict_skip_word( /*===========*/ - /* out: scanned to */ - char* ptr, /* in: scanned to */ - ibool* success)/* out: TRUE if success, FALSE if just spaces left in - string or a syntax error */ + /* out: scanned to */ + const char* ptr, /* in: scanned to */ + ibool* success)/* out: TRUE if success, FALSE if just spaces + left in string or a syntax error */ { - char* start; - ulint len; + const char* start; *success = FALSE; - ptr = dict_scan_id(ptr, &start, &len, TRUE); + ptr = dict_scan_id(ptr, NULL, &start, TRUE); if (start) { *success = TRUE; @@ -2578,35 +2554,6 @@ dict_skip_word( return(ptr); } -#ifdef currentlynotused -/************************************************************************* -Returns the number of opening brackets '(' subtracted by the number -of closing brackets ')' between string and ptr. */ -static -int -dict_bracket_count( -/*===============*/ - /* out: bracket count */ - char* string, /* in: start of string */ - char* ptr) /* in: end of string */ -{ - int count = 0; - - while (string != ptr) { - if (*string == '(') { - count++; - } - if (*string == ')') { - count--; - } - - string++; - } - - return(count); -} -#endif - /************************************************************************* Removes MySQL comments from an SQL string. A comment is either (a) '#' to the end of the line, @@ -2642,10 +2589,10 @@ scan_more: } if (*sptr == '#' - || (strlen(sptr) >= 3 && 0 == memcmp("-- ", sptr, 3))) { + || (0 == memcmp("-- ", sptr, 3))) { for (;;) { - /* In Unix a newline is 0x0D while in Windows - it is 0x0A followed by 0x0D */ + /* In Unix a newline is 0x0A while in Windows + it is 0x0D followed by 0x0A */ if (*sptr == (char)0x0A || *sptr == (char)0x0D @@ -2658,10 +2605,9 @@ scan_more: } } - if (strlen(sptr) >= 2 && *sptr == '/' && *(sptr + 1) == '*') { + if (*sptr == '/' && *(sptr + 1) == '*') { for (;;) { - if (strlen(sptr) >= 2 - && *sptr == '*' && *(sptr + 1) == '/') { + if (*sptr == '*' && *(sptr + 1) == '/') { sptr += 2; @@ -2700,27 +2646,28 @@ dict_table_get_highest_foreign_id( char* endp; ulint biggest_id = 0; ulint id; + ulint len; ut_a(table); + len = ut_strlen(table->name); foreign = UT_LIST_GET_FIRST(table->foreign_list); while (foreign) { - if (ut_strlen(foreign->id) > ut_strlen("_ibfk_") - + ut_strlen(table->name) - && 0 == ut_memcmp(foreign->id, table->name, - ut_strlen(table->name)) - && 0 == ut_memcmp(foreign->id + ut_strlen(table->name), - (char*)"_ibfk_", ut_strlen("_ibfk_"))) { + if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len + && 0 == ut_memcmp(foreign->id, table->name, len) + && 0 == ut_memcmp(foreign->id + len, + dict_ibfk, (sizeof dict_ibfk) - 1)) { /* It is of the >= 4.0.18 format */ - id = strtoul(foreign->id + ut_strlen(table->name) - + ut_strlen("_ibfk_"), + id = strtoul(foreign->id + len + ((sizeof dict_ibfk) - 1), &endp, 10); - ut_a(id != biggest_id); + if (*endp == '\0') { + ut_a(id != biggest_id); - if (id > biggest_id) { - biggest_id = id; + if (id > biggest_id) { + biggest_id = id; + } } } @@ -2736,22 +2683,18 @@ static void dict_foreign_report_syntax_err( /*===========================*/ - char* name, /* in: table name */ - char* start_of_latest_foreign,/* in: start of the foreign key clause + const char* name, /* in: table name */ + const char* start_of_latest_foreign, + /* in: start of the foreign key clause in the SQL string */ - char* ptr) /* in: place of the syntax error */ + const char* ptr) /* in: place of the syntax error */ { - char* buf = dict_foreign_err_buf; + FILE* ef = dict_foreign_err_file; mutex_enter(&dict_foreign_err_mutex); - - ut_sprintf_timestamp(buf); - - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s,\n%.500s.\n" -"Syntax error close to:\n%.500s\n", name, start_of_latest_foreign, ptr); - - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + dict_foreign_error_report_low(ef, name); + fprintf(ef, "%s:\nSyntax error close to:\n%s\n", + start_of_latest_foreign, ptr); mutex_exit(&dict_foreign_err_mutex); } @@ -2766,14 +2709,16 @@ ulint dict_create_foreign_constraints_low( /*================================*/ /* out: error code or DB_SUCCESS */ - trx_t* trx, /* in: transaction */ - char* sql_string, /* in: table create or ALTER TABLE - statement where foreign keys are declared like: + trx_t* trx, /* in: transaction */ + mem_heap_t* heap, /* in: memory heap */ + const char* sql_string, + /* in: CREATE TABLE or ALTER TABLE statement + where foreign keys are declared like: FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2; the default database is the database of parameter name */ - char* name) /* in: table full name in the normalized form + const char* name) /* in: table full name in the normalized form database_name/table_name */ { dict_table_t* table; @@ -2782,40 +2727,35 @@ dict_create_foreign_constraints_low( ulint highest_id_so_far = 0; dict_index_t* index; dict_foreign_t* foreign; - char* ptr = sql_string; - char* start_of_latest_foreign = sql_string; - char* buf = dict_foreign_err_buf; - char* constraint_name; /* this is NOT a null- - terminated string */ - ulint constraint_name_len; + const char* ptr = sql_string; + const char* start_of_latest_foreign = sql_string; + FILE* ef = dict_foreign_err_file; + const char* constraint_name; ibool success; ulint error; - char* ptr1; - char* ptr2; + const char* ptr1; + const char* ptr2; ulint i; ulint j; ibool is_on_delete; ulint n_on_deletes; ulint n_on_updates; dict_col_t* columns[500]; - char* column_names[500]; - ulint column_name_lens[500]; - char referenced_table_name[2500]; + const char* column_names[500]; + const char* referenced_table_name; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ - table = dict_table_get_low(name); + table = dict_table_get_low((char*) name); if (table == NULL) { mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s.\n" -"Cannot find the table from the internal data dictionary of InnoDB.\n" -"Create table statement:\n%.2000s\n", name, sql_string); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + dict_foreign_error_report_low(ef, name); + fprintf(ef, +"Cannot find the table in the internal data dictionary of InnoDB.\n" +"Create table statement:\n%s\n", sql_string); mutex_exit(&dict_foreign_err_mutex); return(DB_ERROR); @@ -2824,26 +2764,24 @@ dict_create_foreign_constraints_low( /* First check if we are actually doing an ALTER TABLE, and in that case look for the table being altered */ - ptr = dict_accept(ptr, (char*) "ALTER", &success); + ptr = dict_accept(ptr, "ALTER", &success); if (!success) { goto loop; } - ptr = dict_accept(ptr, (char*) "TABLE", &success); + ptr = dict_accept(ptr, "TABLE", &success); if (!success) { goto loop; } - /* We are doing an ALTER TABLE: scan the table name we are altering; - in the call below we use the buffer 'referenced_table_name' as a dummy - buffer */ + /* We are doing an ALTER TABLE: scan the table name we are altering */ ptr = dict_scan_table_name(ptr, &table_to_alter, name, - &success, referenced_table_name); + &success, heap, &referenced_table_name); if (!success) { fprintf(stderr, "InnoDB: Error: could not find the table being ALTERED in:\n%s\n", sql_string); @@ -2871,8 +2809,8 @@ dict_create_foreign_constraints_low( loop: /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */ - ptr1 = dict_scan_to(ptr, (char *) "CONSTRAINT"); - ptr2 = dict_scan_to(ptr, (char *) "FOREIGN"); + ptr1 = dict_scan_to(ptr, "CONSTRAINT"); + ptr2 = dict_scan_to(ptr, "FOREIGN"); constraint_name = NULL; @@ -2882,7 +2820,7 @@ loop: the id of the constraint to system tables. */ ptr = ptr1; - ptr = dict_accept(ptr, (char *) "CONSTRAINT", &success); + ptr = dict_accept(ptr, "CONSTRAINT", &success); ut_a(success); @@ -2890,8 +2828,14 @@ loop: goto loop; } - ptr = dict_scan_id(ptr, &constraint_name, &constraint_name_len, - FALSE); + do { + ptr++; + } while (isspace(*ptr)); + + /* read constraint name unless got "CONSTRAINT FOREIGN" */ + if (ptr != ptr2) { + ptr = dict_scan_id(ptr, heap, &constraint_name, FALSE); + } } else { ptr = ptr2; } @@ -2908,19 +2852,19 @@ loop: start_of_latest_foreign = ptr; - ptr = dict_accept(ptr, (char *) "FOREIGN", &success); + ptr = dict_accept(ptr, "FOREIGN", &success); if (!isspace(*ptr)) { goto loop; } - ptr = dict_accept(ptr, (char *) "KEY", &success); + ptr = dict_accept(ptr, "KEY", &success); if (!success) { goto loop; } - ptr = dict_accept(ptr, (char *) "(", &success); + ptr = dict_accept(ptr, "(", &success); if (!success) { /* MySQL allows also an index id before the '('; we @@ -2934,7 +2878,7 @@ loop: return(DB_CANNOT_ADD_CONSTRAINT); } - ptr = dict_accept(ptr, (char *) "(", &success); + ptr = dict_accept(ptr, "(", &success); if (!success) { /* We do not flag a syntax error here because in an @@ -2948,16 +2892,14 @@ loop: /* Scan the columns in the first list */ col_loop1: + ut_a(i < (sizeof column_names) / sizeof *column_names); ptr = dict_scan_col(ptr, &success, table, columns + i, - column_names + i, column_name_lens + i); + heap, column_names + i); if (!success) { mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s,\n%.500s.\n" -"Cannot resolve column name close to:\n%.500s\n", name, + dict_foreign_error_report_low(ef, name); + fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", start_of_latest_foreign, ptr); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); @@ -2965,13 +2907,13 @@ col_loop1: i++; - ptr = dict_accept(ptr, (char *) ",", &success); + ptr = dict_accept(ptr, ",", &success); if (success) { goto col_loop1; } - ptr = dict_accept(ptr, (char *) ")", &success); + ptr = dict_accept(ptr, ")", &success); if (!success) { dict_foreign_report_syntax_err(name, start_of_latest_foreign, @@ -2986,19 +2928,18 @@ col_loop1: if (!index) { mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s:\n" -"There is no index in the table %.500s where the columns appear\n" -"as the first columns. Constraint:\n%.500s\n" -"See http://www.innodb.com/ibman.html for correct foreign key definition.\n", - name, name, start_of_latest_foreign); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + dict_foreign_error_report_low(ef, name); + fputs("There is no index in table ", ef); + ut_print_name(ef, name); + fprintf(ef, " where the columns appear\n" +"as the first columns. Constraint:\n%s\n" +"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", + start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } - ptr = dict_accept(ptr, (char *) "REFERENCES", &success); + ptr = dict_accept(ptr, "REFERENCES", &success); if (!success || !isspace(*ptr)) { dict_foreign_report_syntax_err(name, start_of_latest_foreign, @@ -3021,15 +2962,11 @@ col_loop1: db_len = dict_get_db_name_len(table->name); foreign->id = mem_heap_alloc(foreign->heap, - db_len + 1 + constraint_name_len + 1); - - ut_memcpy(foreign->id, table->name, db_len); + db_len + strlen(constraint_name) + 2); + ut_memcpy(foreign->id, table->name, db_len); foreign->id[db_len] = '/'; - - ut_memcpy(foreign->id + db_len + 1, constraint_name, - constraint_name_len); - foreign->id[db_len + 1 + constraint_name_len] = '\0'; + strcpy(foreign->id + db_len + 1, constraint_name); } foreign->foreign_table = table; @@ -3039,14 +2976,12 @@ col_loop1: foreign->foreign_col_names = mem_heap_alloc(foreign->heap, i * sizeof(void*)); for (i = 0; i < foreign->n_fields; i++) { - foreign->foreign_col_names[i] = mem_heap_alloc(foreign->heap, - 1 + ut_strlen(columns[i]->name)); - ut_memcpy(foreign->foreign_col_names[i], columns[i]->name, - 1 + ut_strlen(columns[i]->name)); + foreign->foreign_col_names[i] = + mem_heap_strdup(foreign->heap, columns[i]->name); } ptr = dict_scan_table_name(ptr, &referenced_table, name, - &success, referenced_table_name); + &success, heap, &referenced_table_name); /* Note that referenced_table can be NULL if the user has suppressed checking of foreign key constraints! */ @@ -3055,18 +2990,16 @@ col_loop1: dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s,\n%.500s.\n" -"Cannot resolve table name close to:\n" -"%.500s\n", name, start_of_latest_foreign, ptr); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + dict_foreign_error_report_low(ef, name); + fprintf(ef, "%s:\nCannot resolve table name close to:\n" + "%s\n", + start_of_latest_foreign, ptr); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } - ptr = dict_accept(ptr, (char *) "(", &success); + ptr = dict_accept(ptr, "(", &success); if (!success) { dict_foreign_free(foreign); @@ -3080,31 +3013,29 @@ col_loop1: col_loop2: ptr = dict_scan_col(ptr, &success, referenced_table, columns + i, - column_names + i, column_name_lens + i); + heap, column_names + i); i++; if (!success) { dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s,\n%.500s\n" -"Cannot resolve column name close to:\n" -"%.500s\n", name, start_of_latest_foreign, ptr); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + dict_foreign_error_report_low(ef, name); + fprintf(ef, "%s:\nCannot resolve column name close to:\n" + "%s\n", + start_of_latest_foreign, ptr); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } - ptr = dict_accept(ptr, (char *) ",", &success); + ptr = dict_accept(ptr, ",", &success); if (success) { goto col_loop2; } - ptr = dict_accept(ptr, (char *) ")", &success); + ptr = dict_accept(ptr, ")", &success); if (!success || foreign->n_fields != i) { dict_foreign_free(foreign); @@ -3216,12 +3147,10 @@ scan_on_conditions: dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s,\n%.500s.\n" -"You have defined a SET NULL condition though some of the\n" -"columns is defined as NOT NULL.\n", name, start_of_latest_foreign); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + dict_foreign_error_report_low(ef, name); + fprintf(ef, "%s:\n" + "You have defined a SET NULL condition though some of the\n" + "columns are defined as NOT NULL.\n", start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); @@ -3243,12 +3172,10 @@ try_find_index: dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s,\n%.500s.\n" + dict_foreign_error_report_low(ef, name); + fprintf(ef, "%s:\n" "You have twice an ON DELETE clause or twice an ON UPDATE clause.\n", - name, start_of_latest_foreign); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); @@ -3265,15 +3192,13 @@ try_find_index: if (!index) { dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in foreign key constraint of table %.500s:\n" + dict_foreign_error_report_low(ef, name); + fprintf(ef, "%s:\n" "Cannot find an index in the referenced table where the\n" "referenced columns appear as the first columns, or column types\n" -"in the table and the referenced table do not match for constraint:\n%.500s\n" -"See http://www.innodb.com/ibman.html for correct foreign key definition.\n", - name, start_of_latest_foreign); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); +"in the table and the referenced table do not match for constraint.\n" +"See http://www.innodb.com/ibman.php for correct foreign key definition.\n", + start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); @@ -3286,21 +3211,14 @@ try_find_index: foreign->referenced_index = index; foreign->referenced_table = referenced_table; - foreign->referenced_table_name = mem_heap_alloc(foreign->heap, - 1 + ut_strlen(referenced_table_name)); - - ut_memcpy(foreign->referenced_table_name, referenced_table_name, - 1 + ut_strlen(referenced_table_name)); + foreign->referenced_table_name = mem_heap_strdup(foreign->heap, + referenced_table_name); foreign->referenced_col_names = mem_heap_alloc(foreign->heap, i * sizeof(void*)); for (i = 0; i < foreign->n_fields; i++) { foreign->referenced_col_names[i] - = mem_heap_alloc(foreign->heap, - 1 + column_name_lens[i]); - ut_memcpy(foreign->referenced_col_names[i], column_names[i], - column_name_lens[i]); - (foreign->referenced_col_names[i])[column_name_lens[i]] = '\0'; + = mem_heap_strdup(foreign->heap, column_names[i]); } /* We found an ok constraint definition: add to the lists */ @@ -3337,15 +3255,18 @@ dict_create_foreign_constraints( char* name) /* in: table full name in the normalized form database_name/table_name */ { - char* str; - ulint err; + char* str; + ulint err; + mem_heap_t* heap; str = dict_strip_comments(sql_string); + heap = mem_heap_create(10000); - err = dict_create_foreign_constraints_low(trx, str, name); + err = dict_create_foreign_constraints_low(trx, heap, str, name); + + mem_heap_free(heap); + mem_free(str); - mem_free(str); - return(err); } @@ -3365,17 +3286,15 @@ dict_foreign_parse_drop_constraints( dict_table_t* table, /* in: table */ ulint* n, /* out: number of constraints to drop */ - char*** constraints_to_drop) /* out: id's of the + const char*** constraints_to_drop) /* out: id's of the constraints to drop */ { - dict_foreign_t* foreign; - ibool success; - char* str; - char* ptr; - char* buf = dict_foreign_err_buf; - char* start; - char* id; - ulint len; + dict_foreign_t* foreign; + ibool success; + char* str; + const char* ptr; + const char* id; + FILE* ef = dict_foreign_err_file; *n = 0; @@ -3388,47 +3307,43 @@ dict_foreign_parse_drop_constraints( ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ loop: - ptr = dict_scan_to(ptr, (char *) "DROP"); + ptr = dict_scan_to(ptr, "DROP"); if (*ptr == '\0') { - ut_a(*n < 1000); - mem_free(str); return(DB_SUCCESS); } - ptr = dict_accept(ptr, (char *) "DROP", &success); + ptr = dict_accept(ptr, "DROP", &success); if (!isspace(*ptr)) { goto loop; } - ptr = dict_accept(ptr, (char *) "FOREIGN", &success); + ptr = dict_accept(ptr, "FOREIGN", &success); if (!success) { goto loop; } - ptr = dict_accept(ptr, (char *) "KEY", &success); + ptr = dict_accept(ptr, "KEY", &success); if (!success) { goto syntax_error; } - ptr = dict_scan_id(ptr, &start, &len, TRUE); + ptr = dict_scan_id(ptr, heap, &id, TRUE); - if (start == NULL) { + if (id == NULL) { goto syntax_error; } - id = mem_heap_alloc(heap, len + 1); - ut_memcpy(id, start, len); - id[len] = '\0'; + ut_a(*n < 1000); (*constraints_to_drop)[*n] = id; (*n)++; @@ -3437,9 +3352,9 @@ loop: foreign = UT_LIST_GET_FIRST(table->foreign_list); while (foreign != NULL) { - if (0 == ut_strcmp(foreign->id, id) - || (ut_str_contains(foreign->id, '/') - && 0 == ut_strcmp(id, + if (0 == strcmp(foreign->id, id) + || (strchr(foreign->id, '/') + && 0 == strcmp(id, dict_remove_db_name(foreign->id)))) { /* Found */ break; @@ -3450,12 +3365,17 @@ loop: if (foreign == NULL) { mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Error in dropping of a foreign key constraint of table %.500s,\n" -"in SQL command\n%s\nCannot find a constraint with the\n" -"given id %s.\n", table->name, str, id); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + rewind(ef); + ut_print_timestamp(ef); + fputs( + " Error in dropping of a foreign key constraint of table ", ef); + ut_print_name(ef, table->name); + fputs(",\n" + "in SQL command\n", ef); + fputs(str, ef); + fputs("\nCannot find a constraint with the given id ", ef); + ut_print_name(ef, id); + fputs(".\n", ef); mutex_exit(&dict_foreign_err_mutex); mem_free(str); @@ -3467,11 +3387,13 @@ loop: syntax_error: mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), -" Syntax error in dropping of a foreign key constraint of table %.500s,\n" -"close to:\n%s\n in SQL command\n%s\n", table->name, ptr, str); - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + rewind(ef); + ut_print_timestamp(ef); + fputs( + " Syntax error in dropping of a foreign key constraint of table ", ef); + ut_print_name(ef, table->name); + fprintf(ef, ",\n" + "close to:\n%s\n in SQL command\n%s\n", ptr, str); mutex_exit(&dict_foreign_err_mutex); mem_free(str); @@ -3482,114 +3404,6 @@ syntax_error: /*==================== END OF FOREIGN KEY PROCESSING ====================*/ /************************************************************************** -Adds a stored procedure object to the dictionary cache. */ - -void -dict_procedure_add_to_cache( -/*========================*/ - dict_proc_t* proc) /* in: procedure */ -{ - ulint fold; - - mutex_enter(&(dict_sys->mutex)); - - fold = ut_fold_string(proc->name); - - /* Look for a procedure with the same name: error if such exists */ - { - dict_proc_t* proc2; - - HASH_SEARCH(name_hash, dict_sys->procedure_hash, fold, proc2, - (ut_strcmp(proc2->name, proc->name) == 0)); - ut_a(proc2 == NULL); - } - - /* Add the procedure to the hash table */ - - HASH_INSERT(dict_proc_t, name_hash, dict_sys->procedure_hash, fold, - proc); - mutex_exit(&(dict_sys->mutex)); -} - -/************************************************************************** -Reserves a parsed copy of a stored procedure to execute. If there are no -free parsed copies left at the moment, parses a new copy. Takes the copy off -the list of copies: the copy must be returned there with -dict_procedure_release_parsed_copy. */ - -que_t* -dict_procedure_reserve_parsed_copy( -/*===============================*/ - /* out: the query graph */ - dict_proc_t* proc) /* in: dictionary procedure node */ -{ - que_t* graph; - proc_node_t* proc_node; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(!mutex_own(&kernel_mutex)); -#endif /* UNIV_SYNC_DEBUG */ - - mutex_enter(&(dict_sys->mutex)); - -#ifdef UNIV_DEBUG - UT_LIST_VALIDATE(graphs, que_t, proc->graphs); -#endif - graph = UT_LIST_GET_FIRST(proc->graphs); - - if (graph) { - UT_LIST_REMOVE(graphs, proc->graphs, graph); - -/* printf("Graph removed, list length %lu\n", - UT_LIST_GET_LEN(proc->graphs)); */ -#ifdef UNIV_DEBUG - UT_LIST_VALIDATE(graphs, que_t, proc->graphs); -#endif - } - - mutex_exit(&(dict_sys->mutex)); - - if (graph == NULL) { - graph = pars_sql(proc->sql_string); - - proc_node = que_fork_get_child(graph); - - proc_node->dict_proc = proc; - - printf("Parsed a new copy of graph %s\n", - proc_node->proc_id->name); - } - -/* printf("Returning graph %lu\n", (ulint)graph); */ - - return(graph); -} - -/************************************************************************** -Releases a parsed copy of an executed stored procedure. Puts the copy to the -list of copies. */ - -void -dict_procedure_release_parsed_copy( -/*===============================*/ - que_t* graph) /* in: query graph of a stored procedure */ -{ - proc_node_t* proc_node; - -#ifdef UNIV_SYNC_DEBUG - ut_ad(!mutex_own(&kernel_mutex)); -#endif /* UNIV_SYNC_DEBUG */ - - mutex_enter(&(dict_sys->mutex)); - - proc_node = que_fork_get_child(graph); - - UT_LIST_ADD_FIRST(graphs, (proc_node->dict_proc)->graphs, graph); - - mutex_exit(&(dict_sys->mutex)); -} - -/************************************************************************** Returns an index object if it is found in the dictionary cache. */ dict_index_t* @@ -4072,24 +3886,31 @@ dict_foreign_print_low( ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ - printf(" FOREIGN KEY CONSTRAINT %s: %s (", foreign->id, - foreign->foreign_table_name); - + fputs(" FOREIGN KEY CONSTRAINT ", stderr); + ut_print_name(stderr, foreign->id); + fputs(": ", stderr); + ut_print_name(stderr, foreign->foreign_table_name); + fputs(" (", stderr); + for (i = 0; i < foreign->n_fields; i++) { - printf(" %s", foreign->foreign_col_names[i]); + putc(' ', stderr); + ut_print_name(stderr, foreign->foreign_col_names[i]); } - printf(" )\n"); - - printf(" REFERENCES %s (", foreign->referenced_table_name); + fputs(" )\n" + " REFERENCES ", stderr); + ut_print_name(stderr, foreign->referenced_table_name); + fputs(" (", stderr); for (i = 0; i < foreign->n_fields; i++) { - printf(" %s", foreign->referenced_col_names[i]); + putc(' ', stderr); + ut_print_name(stderr, foreign->referenced_col_names[i]); } - printf(" )\n"); + fputs(" )\n", stderr); } +#ifdef UNIV_DEBUG /************************************************************************** Prints a table data. */ @@ -4122,6 +3943,7 @@ dict_table_print_by_name( dict_table_print_low(table); mutex_exit(&(dict_sys->mutex)); } +#endif /* UNIV_DEBUG */ /************************************************************************** Prints a table data. */ @@ -4141,23 +3963,24 @@ dict_table_print_low( dict_update_statistics_low(table, TRUE); - printf("--------------------------------------\n"); - printf( - "TABLE: name %s, id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n", - table->name, + fputs("--------------------------------------\n" + "TABLE: name ", stderr); + ut_print_name(stderr, table->name); + fprintf(stderr, + ", id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n" + " COLUMNS: ", (ulong) ut_dulint_get_high(table->id), (ulong) ut_dulint_get_low(table->id), (ulong) table->n_cols, (ulong) UT_LIST_GET_LEN(table->indexes), (ulong) table->stat_n_rows); - printf(" COLUMNS: "); for (i = 0; i < table->n_cols - 1; i++) { dict_col_print_low(dict_table_get_nth_col(table, i)); - printf("; "); + fputs("; ", stderr); } - printf("\n"); + putc('\n', stderr); index = UT_LIST_GET_FIRST(table->indexes); @@ -4196,7 +4019,8 @@ dict_col_print_low( #endif /* UNIV_SYNC_DEBUG */ type = dict_col_get_type(col); - printf("%s: ", col->name); + ut_print_name(stderr, col->name); + fputs(": ", stderr); dtype_print(type); } @@ -4226,27 +4050,27 @@ dict_index_print_low( n_vals = index->stat_n_diff_key_vals[1]; } - printf( - " INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n", - index->name, index->table_name, - (ulong) ut_dulint_get_high(tree->id), - (ulong) ut_dulint_get_low(tree->id), - (ulong) index->n_user_defined_cols, - (ulong) index->n_fields, (ulong) index->type); - printf( - " root page %lu, appr.key vals %lu, leaf pages %lu, size pages %lu\n", + fputs(" INDEX: ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, + ", id %lu %lu, fields %lu/%lu, type %lu\n" + " root page %lu, appr.key vals %lu," + " leaf pages %lu, size pages %lu\n" + " FIELDS: ", + (ulong) ut_dulint_get_high(tree->id), + (ulong) ut_dulint_get_low(tree->id), + (ulong) index->n_user_defined_cols, + (ulong) index->n_fields, (ulong) index->type, (ulong) tree->page, (ulong) n_vals, (ulong) index->stat_n_leaf_pages, (ulong) index->stat_index_size); - printf(" FIELDS: "); - for (i = 0; i < index->n_fields; i++) { dict_field_print_low(dict_index_get_nth_field(index, i)); } - printf("\n"); + putc('\n', stderr); /* btr_print_size(tree); */ @@ -4264,31 +4088,28 @@ dict_field_print_low( #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ - - printf(" %s", field->name); + putc(' ', stderr); + ut_print_name(stderr, field->name); if (field->prefix_len != 0) { - printf("(%lu)", (ulong) field->prefix_len); + fprintf(stderr, "(%lu)", (ulong) field->prefix_len); } } /************************************************************************** -Sprintfs to a string info on a foreign key of a table in a format suitable -for CREATE TABLE. */ +Outputs info on a foreign key of a table in a format suitable for +CREATE TABLE. */ -char* +void dict_print_info_on_foreign_key_in_create_format( /*============================================*/ - /* out: how far in buf we printed */ - dict_foreign_t* foreign,/* in: foreign key constraint */ - char* buf) /* in: buffer of at least 5000 bytes */ + FILE* file, /* in: file where to print */ + dict_foreign_t* foreign)/* in: foreign key constraint */ { - char* buf2 = buf; - char* stripped_id; - ulint cpy_len; + const char* stripped_id; ulint i; - if (ut_str_contains(foreign->id, '/')) { + if (strchr(foreign->id, '/')) { /* Strip the preceding database name from the constraint id */ stripped_id = foreign->id + 1 + dict_get_db_name_len(foreign->id); @@ -4296,140 +4117,80 @@ dict_print_info_on_foreign_key_in_create_format( stripped_id = foreign->id; } - buf2 += sprintf(buf2, ",\n CONSTRAINT `%s` FOREIGN KEY (", - stripped_id); - for (i = 0; i < foreign->n_fields; i++) { - if ((ulint)(buf2 - buf) >= 4000) { + fputs(",\n CONSTRAINT ", file); + ut_print_name(file, stripped_id); + fputs(" FOREIGN KEY (", file); - goto no_space; - } - buf2 += sprintf(buf2, "`%.250s`", - foreign->foreign_col_names[i]); - - if (i + 1 < foreign->n_fields) { - buf2 += sprintf(buf2, ", "); + for (i = 0;;) { + ut_print_name(file, foreign->foreign_col_names[i]); + if (++i < foreign->n_fields) { + fputs(", ", file); + } else { + break; } } + fputs(") REFERENCES ", file); + if (dict_tables_have_same_db(foreign->foreign_table_name, foreign->referenced_table_name)) { /* Do not print the database name of the referenced table */ - buf2 += sprintf(buf2, ") REFERENCES `%.500s` (", - dict_remove_db_name( + ut_print_name(file, dict_remove_db_name( foreign->referenced_table_name)); } else { - buf2 += sprintf(buf2, ") REFERENCES `"); - /* Look for the '/' in the table name */ i = 0; while (foreign->referenced_table_name[i] != '/') { i++; } - - cpy_len = i; - - if (cpy_len > 500) { - cpy_len = 500; - } - memcpy(buf2, foreign->referenced_table_name, cpy_len); - buf2 += cpy_len; - - buf2 += sprintf(buf2, "`.`%.500s` (", - foreign->referenced_table_name + i + 1); + ut_print_namel(file, foreign->referenced_table_name, i); + putc('.', file); + ut_print_name(file, foreign->referenced_table_name + i + 1); } - - for (i = 0; i < foreign->n_fields; i++) { - if ((ulint)(buf2 - buf) >= 4000) { - goto no_space; - } - buf2 += sprintf(buf2, "`%.250s`", - foreign->referenced_col_names[i]); - if (i + 1 < foreign->n_fields) { - buf2 += sprintf(buf2, ", "); + putc(' ', file); + putc('(', file); + + for (i = 0;;) { + ut_print_name(file, foreign->referenced_col_names[i]); + if (++i < foreign->n_fields) { + fputs(", ", file); + } else { + break; } } - buf2 += sprintf(buf2, ")"); + putc(')', file); if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) { - buf2 += sprintf(buf2, " ON DELETE CASCADE"); + fputs(" ON DELETE CASCADE", file); } if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) { - buf2 += sprintf(buf2, " ON DELETE SET NULL"); + fputs(" ON DELETE SET NULL", file); } if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { - buf2 += sprintf(buf2, " ON DELETE NO ACTION"); + fputs(" ON DELETE NO ACTION", file); } if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) { - buf2 += sprintf(buf2, " ON UPDATE CASCADE"); + fputs(" ON UPDATE CASCADE", file); } if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) { - buf2 += sprintf(buf2, " ON UPDATE SET NULL"); + fputs(" ON UPDATE SET NULL", file); } if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { - buf2 += sprintf(buf2, " ON UPDATE NO ACTION"); + fputs(" ON UPDATE NO ACTION", file); } - -no_space: - return(buf2); } /************************************************************************** -Sprintfs to a string info on foreign keys of a table in a format suitable -for CREATE TABLE. */ -static -void -dict_print_info_on_foreign_keys_in_create_format( -/*=============================================*/ - char* buf, /* in: auxiliary buffer */ - char* str, /* in/out: pointer to a string */ - ulint len, /* in: buf has to be a buffer of at least - len + 5000 bytes; str must have at least - len + 1 bytes */ - dict_table_t* table) /* in: table */ -{ - dict_foreign_t* foreign; - char* buf2; - - buf2 = buf; - - mutex_enter(&(dict_sys->mutex)); - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - if (foreign == NULL) { - mutex_exit(&(dict_sys->mutex)); - - return; - } - - while (foreign != NULL) { - if ((ulint)(buf2 - buf) >= len) { - goto no_space; - } - - buf2 = dict_print_info_on_foreign_key_in_create_format( - foreign, buf2); - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } -no_space: - mutex_exit(&(dict_sys->mutex)); - - buf[len - 1] = '\0'; - ut_memcpy(str, buf, len); -} - -/************************************************************************** -Sprintfs to a string info on foreign keys of a table. */ +Outputs info on foreign keys of a table. */ void dict_print_info_on_foreign_keys( @@ -4438,23 +4199,10 @@ dict_print_info_on_foreign_keys( a format suitable to be inserted into a CREATE TABLE, otherwise in the format of SHOW TABLE STATUS */ - char* str, /* in/out: pointer to a string */ - ulint len, /* in: space in str available for info */ + FILE* file, /* in: file where to print */ dict_table_t* table) /* in: table */ { dict_foreign_t* foreign; - ulint i; - char* buf2; - char* buf; - - buf = mem_alloc(len + 5000); - - if (create_table_format) { - dict_print_info_on_foreign_keys_in_create_format( - buf, str, len, table); - mem_free(buf); - return; - } mutex_enter(&(dict_sys->mutex)); @@ -4463,76 +4211,81 @@ dict_print_info_on_foreign_keys( if (foreign == NULL) { mutex_exit(&(dict_sys->mutex)); - mem_free(buf); return; } - buf2 = buf; - while (foreign != NULL) { + if (create_table_format) { + dict_print_info_on_foreign_key_in_create_format( + file, foreign); + } else { + ulint i; + fputs("; (", file); - buf2 += sprintf(buf2, "; ("); - - for (i = 0; i < foreign->n_fields; i++) { - if ((ulint)(buf2 - buf) >= len) { - goto no_space; - } + for (i = 0; i < foreign->n_fields; i++) { + if (i) { + putc(' ', file); + } - buf2 += sprintf(buf2, "%.500s", + ut_print_name(file, foreign->foreign_col_names[i]); - - if (i + 1 < foreign->n_fields) { - buf2 += sprintf(buf2, " "); } - } - buf2 += sprintf(buf2, ") REFER %.500s(", - foreign->referenced_table_name); - - for (i = 0; i < foreign->n_fields; i++) { - if ((ulint)(buf2 - buf) >= len) { - goto no_space; - } - buf2 += sprintf(buf2, "%.500s", + fputs(") REFER ", file); + ut_print_name(file, foreign->referenced_table_name); + putc('(', file); + + for (i = 0; i < foreign->n_fields; i++) { + if (i) { + putc(' ', file); + } + ut_print_name(file, foreign->referenced_col_names[i]); - if (i + 1 < foreign->n_fields) { - buf2 += sprintf(buf2, " "); } - } - buf2 += sprintf(buf2, ")"); + putc(')', file); - if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) { - buf2 += sprintf(buf2, " ON DELETE CASCADE"); - } + if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) { + fputs(" ON DELETE CASCADE", file); + } - if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) { - buf2 += sprintf(buf2, " ON DELETE SET NULL"); - } + if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) { + fputs(" ON DELETE SET NULL", file); + } - if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { - buf2 += sprintf(buf2, " ON DELETE NO ACTION"); - } + if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { + fputs(" ON DELETE NO ACTION", file); + } - if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) { - buf2 += sprintf(buf2, " ON UPDATE CASCADE"); - } + if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) { + fputs(" ON UPDATE CASCADE", file); + } - if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) { - buf2 += sprintf(buf2, " ON UPDATE SET NULL"); - } + if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) { + fputs(" ON UPDATE SET NULL", file); + } - if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { - buf2 += sprintf(buf2, " ON UPDATE NO ACTION"); + if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { + fputs(" ON UPDATE NO ACTION", file); + } } foreign = UT_LIST_GET_NEXT(foreign_list, foreign); } -no_space: - mutex_exit(&(dict_sys->mutex)); - buf[len - 1] = '\0'; - ut_memcpy(str, buf, len); + mutex_exit(&(dict_sys->mutex)); +} - mem_free(buf); +/************************************************************************ +Displays the names of the index and the table. */ +void +dict_index_name_print( +/*==================*/ + FILE* file, /* in: output stream */ + const dict_index_t* index) /* in: index to print */ +{ + fputs("index ", file); + ut_print_name(file, index->name); + fputs(" of table ", file); + ut_print_name(stderr, index->table_name); } diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index c6a8ebc4b55..abb06b15ea7 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -40,7 +40,6 @@ dict_get_first_table_name_in_db( rec_t* rec; byte* field; ulint len; - char* table_name; mtr_t mtr; #ifdef UNIV_SYNC_DEBUG @@ -92,9 +91,7 @@ loop: /* We found one */ - table_name = mem_alloc(len + 1); - ut_memcpy(table_name, field, len); - table_name[len] = '\0'; + char* table_name = mem_strdupl(field, len); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -124,7 +121,6 @@ dict_print(void) byte* field; ulint len; mtr_t mtr; - char table_name[10000]; mutex_enter(&(dict_sys->mutex)); @@ -157,18 +153,19 @@ loop: /* We found one */ - ut_memcpy(table_name, field, len); - table_name[len] = '\0'; - + char* table_name = mem_strdupl(field, len); + btr_pcur_store_position(&pcur, &mtr); mtr_commit(&mtr); - + table = dict_table_get_low(table_name); + mem_free(table_name); if (table == NULL) { - fprintf(stderr, "InnoDB: Failed to load table %s\n", - table_name); + fputs("InnoDB: Failed to load table ", stderr); + ut_print_namel(stderr, field, len); + putc('\n', stderr); } else { /* The table definition was corrupt if there is no index */ @@ -300,7 +297,6 @@ dict_load_columns( byte* field; ulint len; byte* buf; - char* name_buf; char* name; ulint mtype; ulint prtype; @@ -351,12 +347,7 @@ dict_load_columns( dict_table_get_first_index(sys_columns), 4))->name)); field = rec_get_nth_field(rec, 4, &len); - - name_buf = mem_heap_alloc(heap, len + 1); - ut_memcpy(name_buf, field, len); - name_buf[len] = '\0'; - - name = name_buf; + name = mem_heap_strdupl(heap, field, len); field = rec_get_nth_field(rec, 5, &len); mtype = mach_read_from_4(field); @@ -394,6 +385,27 @@ dict_load_columns( } /************************************************************************ +Report that an index field or index for a table has been delete marked. */ +static +void +dict_load_report_deleted_index( + char* name, /* in: table name */ + ulint field) /* in: index field, or ULINT_UNDEFINED */ +{ + fputs("InnoDB: Error: data dictionary entry" + " for table ", stderr); + ut_print_name(stderr, name); + fputs(" is corrupt!\n", stderr); + if (field != ULINT_UNDEFINED) { + fprintf(stderr, + "InnoDB: Index field %lu is delete marked.\n", field); + } + else { + fputs("InnoDB: An index is delete marked.\n", stderr); + } +} + +/************************************************************************ Loads definitions for index fields. */ static void @@ -408,7 +420,6 @@ dict_load_fields( btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; - char* col_name; ulint pos_and_prefix_len; ulint prefix_len; rec_t* rec; @@ -446,10 +457,7 @@ dict_load_fields( ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); if (rec_get_deleted_flag(rec)) { - fprintf(stderr, -"InnoDB: Error: data dictionary entry for table %s is corrupt!\n" -"InnoDB: An index field is delete marked.\n", - table->name); + dict_load_report_deleted_index(table->name, i); } field = rec_get_nth_field(rec, 0, &len); @@ -487,11 +495,8 @@ dict_load_fields( field = rec_get_nth_field(rec, 4, &len); - col_name = mem_heap_alloc(heap, len + 1); - ut_memcpy(col_name, field, len); - col_name[len] = '\0'; - - dict_mem_index_add_field(index, col_name, 0, prefix_len); + dict_mem_index_add_field(index, + mem_heap_strdupl(heap, field, len), 0, prefix_len); btr_pcur_move_to_next_user_rec(&pcur, &mtr); } @@ -575,10 +580,8 @@ dict_load_indexes( } if (rec_get_deleted_flag(rec)) { - fprintf(stderr, -"InnoDB: Error: data dictionary entry for table %s is corrupt!\n" -"InnoDB: An index is delete marked.\n", - table->name); + dict_load_report_deleted_index(table->name, + ULINT_UNDEFINED); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -596,10 +599,7 @@ dict_load_indexes( dict_table_get_first_index(sys_indexes), 4))->name)); field = rec_get_nth_field(rec, 4, &name_len); - - name_buf = mem_heap_alloc(heap, name_len + 1); - ut_memcpy(name_buf, field, name_len); - name_buf[name_len] = '\0'; + name_buf = mem_heap_strdupl(heap, field, name_len); field = rec_get_nth_field(rec, 5, &len); n_fields = mach_read_from_4(field); @@ -620,11 +620,13 @@ dict_load_indexes( if (page_no == FIL_NULL) { - fprintf(stderr, - "InnoDB: Error: trying to load index %s for table %s\n" - "InnoDB: but the index tree has been freed!\n", - name_buf, table->name); - + fputs("InnoDB: Error: trying to load index ", stderr); + ut_print_name(stderr, name_buf); + fputs(" for table ", stderr); + ut_print_name(stderr, table->name); + fputs("\n" + "InnoDB: but the index tree has been freed!\n", stderr); + btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -634,10 +636,12 @@ dict_load_indexes( if ((type & DICT_CLUSTERED) == 0 && NULL == dict_table_get_first_index(table)) { - fprintf(stderr, - "InnoDB: Error: trying to load index %s for table %s\n" - "InnoDB: but the first index was not clustered!\n", - name_buf, table->name); + fputs("InnoDB: Error: trying to load index ", stderr); + ut_print_namel(stderr, name_buf, name_len); + fputs(" for table ", stderr); + ut_print_name(stderr, table->name); + fputs("\n" + "InnoDB: but the first index is not clustered!\n", stderr); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -648,7 +652,7 @@ dict_load_indexes( if (is_sys_table && ((type & DICT_CLUSTERED) || ((table == dict_sys->sys_tables) - && (name_len == ut_strlen("ID_IND")) + && (name_len == (sizeof "ID_IND") - 1) && (0 == ut_memcmp(name_buf, (char*) "ID_IND", name_len))))) { @@ -702,7 +706,6 @@ dict_load_table( rec_t* rec; byte* field; ulint len; - char* buf; ulint space; ulint n_cols; ulint err; @@ -802,15 +805,13 @@ dict_load_table( if (table->type == DICT_TABLE_CLUSTER_MEMBER) { ut_error; - +#if 0 /* clustered tables have not been implemented yet */ field = rec_get_nth_field(rec, 6, &len); table->mix_id = mach_read_from_8(field); field = rec_get_nth_field(rec, 8, &len); - buf = mem_heap_alloc(heap, len); - ut_memcpy(buf, field, len); - - table->cluster_name = buf; + table->cluster_name = mem_heap_strdupl(heap, field, len); +#endif } if ((table->type == DICT_TABLE_CLUSTER) @@ -879,7 +880,6 @@ dict_load_table_on_id( byte* field; ulint len; dict_table_t* table; - char* name; mtr_t mtr; #ifdef UNIV_SYNC_DEBUG @@ -942,13 +942,8 @@ dict_load_table_on_id( /* Now we get the table name from the record */ field = rec_get_nth_field(rec, 1, &len); - - name = mem_heap_alloc(heap, len + 1); - ut_memcpy(name, field, len); - name[len] = '\0'; - /* Load the table definition to memory */ - table = dict_load_table(name); + table = dict_load_table(mem_heap_strdupl(heap, field, len)); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -995,7 +990,6 @@ dict_load_foreign_cols( btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; - char* col_name; rec_t* rec; byte* field; ulint len; @@ -1040,21 +1034,13 @@ dict_load_foreign_cols( ut_a(i == mach_read_from_4(field)); field = rec_get_nth_field(rec, 4, &len); - - col_name = mem_heap_alloc(foreign->heap, len + 1); - ut_memcpy(col_name, field, len); - col_name[len] = '\0'; - - foreign->foreign_col_names[i] = col_name; + foreign->foreign_col_names[i] = + mem_heap_strdupl(foreign->heap, field, len); field = rec_get_nth_field(rec, 5, &len); + foreign->referenced_col_names[i] = + mem_heap_strdupl(foreign->heap, field, len); - col_name = mem_heap_alloc(foreign->heap, len + 1); - ut_memcpy(col_name, field, len); - col_name[len] = '\0'; - - foreign->referenced_col_names[i] = col_name; - btr_pcur_move_to_next_user_rec(&pcur, &mtr); } @@ -1110,8 +1096,10 @@ dict_load_foreign( || rec_get_deleted_flag(rec)) { /* Not found */ - fprintf(stderr, - "InnoDB: Error A: cannot load foreign constraint %s\n", id); + fputs("InnoDB: Error A: cannot load foreign constraint ", + stderr); + ut_print_name(stderr, id); + putc('\n', stderr); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -1125,8 +1113,10 @@ dict_load_foreign( /* Check if the id in record is the searched one */ if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) { - fprintf(stderr, - "InnoDB: Error B: cannot load foreign constraint %s\n", id); + fputs("InnoDB: Error B: cannot load foreign constraint ", + stderr); + ut_print_name(stderr, id); + putc('\n', stderr); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -1151,23 +1141,15 @@ dict_load_foreign( foreign->type = foreign->n_fields >> 24; foreign->n_fields = foreign->n_fields & 0xFFFFFFUL; - foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1); - - ut_memcpy(foreign->id, id, ut_strlen(id) + 1); + foreign->id = mem_heap_strdup(foreign->heap, id); field = rec_get_nth_field(rec, 3, &len); - - foreign->foreign_table_name = mem_heap_alloc(foreign->heap, 1 + len); - - ut_memcpy(foreign->foreign_table_name, field, len); - foreign->foreign_table_name[len] = '\0'; + foreign->foreign_table_name = + mem_heap_strdupl(foreign->heap, field, len); field = rec_get_nth_field(rec, 4, &len); - - foreign->referenced_table_name = mem_heap_alloc(foreign->heap, - 1 + len); - ut_memcpy(foreign->referenced_table_name, field, len); - foreign->referenced_table_name[len] = '\0'; + foreign->referenced_table_name = + mem_heap_strdupl(foreign->heap, field, len); btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -1281,10 +1263,7 @@ loop: /* Now we get a foreign key constraint id */ field = rec_get_nth_field(rec, 1, &len); - - id = mem_heap_alloc(heap, len + 1); - ut_memcpy(id, field, len); - id[len] = '\0'; + id = mem_heap_strdupl(heap, field, len); btr_pcur_store_position(&pcur, &mtr); diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c index c49738a0960..a4f83ddd657 100644 --- a/innobase/dict/dict0mem.c +++ b/innobase/dict/dict0mem.c @@ -49,9 +49,7 @@ dict_mem_table_create( table->heap = heap; - str = mem_heap_alloc(heap, 1 + ut_strlen(name)); - - ut_strcpy(str, name); + str = mem_heap_strdup(heap, name); table->type = DICT_TABLE_ORDINARY; table->name = str; @@ -148,7 +146,6 @@ dict_mem_table_add_col( ulint len, /* in: length */ ulint prec) /* in: precision */ { - char* str; dict_col_t* col; dtype_t* type; @@ -156,15 +153,11 @@ dict_mem_table_add_col( ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); table->n_def++; - - col = dict_table_get_nth_col(table, table->n_def - 1); - - str = mem_heap_alloc(table->heap, 1 + ut_strlen(name)); - ut_strcpy(str, name); + col = dict_table_get_nth_col(table, table->n_def - 1); col->ind = table->n_def - 1; - col->name = str; + col->name = mem_heap_strdup(table->heap, name); col->table = table; col->ord_part = 0; @@ -190,7 +183,6 @@ dict_mem_index_create( ulint type, /* in: DICT_UNIQUE, DICT_CLUSTERED, ... ORed */ ulint n_fields) /* in: number of fields */ { - char* str; dict_index_t* index; mem_heap_t* heap; @@ -201,13 +193,9 @@ dict_mem_index_create( index->heap = heap; - str = mem_heap_alloc(heap, 1 + ut_strlen(index_name)); - - ut_strcpy(str, index_name); - index->type = type; index->space = space; - index->name = str; + index->name = mem_heap_strdup(heap, index_name); index->table_name = table_name; index->table = NULL; index->n_def = 0; @@ -303,56 +291,3 @@ dict_mem_index_free( { mem_heap_free(index->heap); } - -/************************************************************************** -Creates a procedure memory object. */ - -dict_proc_t* -dict_mem_procedure_create( -/*======================*/ - /* out, own: procedure object */ - char* name, /* in: procedure name */ - char* sql_string, /* in: procedure definition as an SQL - string */ - que_fork_t* graph) /* in: parsed procedure graph */ -{ - dict_proc_t* proc; - proc_node_t* proc_node; - mem_heap_t* heap; - char* str; - - ut_ad(name); - - heap = mem_heap_create(128); - - proc = mem_heap_alloc(heap, sizeof(dict_proc_t)); - - proc->heap = heap; - - str = mem_heap_alloc(heap, 1 + ut_strlen(name)); - - ut_strcpy(str, name); - - proc->name = str; - - str = mem_heap_alloc(heap, 1 + ut_strlen(sql_string)); - - ut_strcpy(str, sql_string); - - proc->sql_string = str; - - UT_LIST_INIT(proc->graphs); - -/* UT_LIST_ADD_LAST(graphs, proc->graphs, graph); */ - -#ifdef UNIV_DEBUG - UT_LIST_VALIDATE(graphs, que_t, proc->graphs); -#endif - proc->mem_fix = 0; - - proc_node = que_fork_get_child(graph); - - proc_node->dict_proc = proc; - - return(proc); -} diff --git a/innobase/eval/eval0eval.c b/innobase/eval/eval0eval.c index 157d4e4f98d..053a10b3c23 100644 --- a/innobase/eval/eval0eval.c +++ b/innobase/eval/eval0eval.c @@ -311,12 +311,13 @@ eval_predefined_2( arg = que_node_get_next(arg); } - printf("\n"); + putc('\n', stderr); } else if (func == PARS_ASSERT_TOKEN) { if (!eval_node_get_ibool_val(arg1)) { - printf("SQL assertion fails in a stored procedure!\n"); + fputs("SQL assertion fails in a stored procedure!\n", + stderr); } ut_a(eval_node_get_ibool_val(arg1)); @@ -667,7 +668,6 @@ eval_predefined( { que_node_t* arg1; lint int_val; - byte* str1; byte* data; int func; @@ -681,21 +681,63 @@ eval_predefined( } else if (func == PARS_TO_CHAR_TOKEN) { + /* Convert number to character string as a + signed decimal integer. */ + + ulint uint_val; + int int_len; + int_val = eval_node_get_int_val(arg1); - - data = eval_node_ensure_val_buf(func_node, 11); - sprintf((char*)data, "%10li", int_val); + /* Determine the length of the string. */ + + if (int_val == 0) { + int_len = 1; /* the number 0 occupies 1 byte */ + } else { + int_len = 0; + if (int_val < 0) { + uint_val = ((ulint) -int_val - 1) + 1; + int_len++; /* reserve space for minus sign */ + } else { + uint_val = (ulint) int_val; + } + for (; uint_val > 0; int_len++) { + uint_val /= 10; + } + } + + /* allocate the string */ + data = eval_node_ensure_val_buf(func_node, int_len + 1); - dfield_set_len(que_node_get_val(func_node), 10); + /* add terminating NUL character */ + data[int_len] = 0; + + /* convert the number */ + + if (int_val == 0) { + data[0] = '0'; + } else { + int tmp; + if (int_val < 0) { + data[0] = '-'; /* preceding minus sign */ + uint_val = ((ulint) -int_val - 1) + 1; + } else { + uint_val = (ulint) int_val; + } + for (tmp = int_len; uint_val > 0; uint_val /= 10) { + data[--tmp] = '0' + (uint_val % 10); + } + } + + dfield_set_len((dfield_t*) que_node_get_val(func_node), + int_len); return; } else if (func == PARS_TO_NUMBER_TOKEN) { - str1 = dfield_get_data(que_node_get_val(arg1)); - - int_val = atoi((char*)str1); + int_val = atoi((char*) + dfield_get_data(que_node_get_val(arg1))); } else if (func == PARS_SYSDATE_TOKEN) { int_val = (lint)ut_time(); diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 768dda4eedc..b9aff246802 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -86,7 +86,7 @@ the count drops to zero. */ /* When mysqld is run, the default directory "." is the mysqld datadir, but in the MySQL Embedded Server Library and ibbackup it is not the default directory, and we must set the base file path explicitly */ -char* fil_path_to_mysql_datadir = (char*)"."; +const char* fil_path_to_mysql_datadir = "."; ulint fil_n_pending_log_flushes = 0; ulint fil_n_pending_tablespace_flushes = 0; @@ -399,7 +399,6 @@ fil_node_create( fil_system_t* system = fil_system; fil_node_t* node; fil_space_t* space; - char* name2; ut_a(system); ut_a(name); @@ -408,11 +407,7 @@ fil_node_create( node = mem_alloc(sizeof(fil_node_t)); - name2 = mem_alloc(ut_strlen(name) + 1); - - ut_strcpy(name2, name); - - node->name = name2; + node->name = mem_strdup(name); node->open = FALSE; ut_a(!is_raw || srv_start_raw_disk_in_use); @@ -433,7 +428,7 @@ fil_node_create( fprintf(stderr, " InnoDB: Error: Could not find tablespace %lu for\n" "InnoDB: file %s from the tablespace memory cache.\n", (ulong) id, name); - mem_free(name2); + mem_free(node->name); mem_free(node); @@ -816,7 +811,6 @@ fil_space_create( { fil_system_t* system = fil_system; fil_space_t* space; - char* name2; ulint namesake_id; try_again: /*printf( @@ -881,11 +875,7 @@ try_again: space = mem_alloc(sizeof(fil_space_t)); - name2 = mem_alloc(ut_strlen(name) + 1); - - ut_strcpy(name2, name); - - space->name = name2; + space->name = mem_strdup(name); space->id = id; system->tablespace_version++; @@ -2737,7 +2727,7 @@ fil_load_single_table_tablespaces(void) /* The datadir of MySQL is always the default directory of mysqld */ - dir = os_file_opendir(fil_path_to_mysql_datadir, TRUE); + dir = os_file_opendir((char*) fil_path_to_mysql_datadir, TRUE); if (dir == NULL) { @@ -2749,7 +2739,7 @@ fil_load_single_table_tablespaces(void) /* Scan all directories under the datadir. They are the database directories of MySQL. */ - ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, dir, + ret = os_file_readdir_next_file((char*) fil_path_to_mysql_datadir, dir, &dbinfo); while (ret == 0) { /* printf("Looking at %s in datadir\n", dbinfo.name); */ @@ -2810,7 +2800,7 @@ next_file_item: } next_datadir_item: - ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, + ret = os_file_readdir_next_file((char*) fil_path_to_mysql_datadir, dir, &dbinfo); } @@ -3726,7 +3716,7 @@ fil_aio_wait( ut_ad(fil_validate()); if (os_aio_use_native_aio) { - srv_io_thread_op_info[segment] = (char *) "handle native aio"; + srv_set_io_thread_op_info(segment, "native aio handle"); #ifdef WIN_ASYNC_IO ret = os_aio_windows_handle(segment, 0, (void**) &fil_node, &message, &type); @@ -3737,7 +3727,7 @@ fil_aio_wait( ut_error; #endif } else { - srv_io_thread_op_info[segment] =(char *)"handle simulated aio"; + srv_set_io_thread_op_info(segment, "simulated aio handle"); ret = os_aio_simulated_handle(segment, (void**) &fil_node, &message, &type); @@ -3745,7 +3735,7 @@ fil_aio_wait( ut_a(ret); - srv_io_thread_op_info[segment] = (char *) "complete io for fil node"; + srv_set_io_thread_op_info(segment, "complete io for fil node"); mutex_enter(&(system->mutex)); @@ -3762,11 +3752,10 @@ fil_aio_wait( open, and use a special i/o thread to serve insert buffer requests. */ if (buf_pool_is_block(message)) { - srv_io_thread_op_info[segment] = - (char *) "complete io for buf page"; + srv_set_io_thread_op_info(segment, "complete io for buf page"); buf_page_io_complete(message); } else { - srv_io_thread_op_info[segment] =(char *) "complete io for log"; + srv_set_io_thread_op_info(segment, "complete io for log"); log_io_complete(message); } } @@ -3847,7 +3836,9 @@ retry: mutex_exit(&(system->mutex)); - /* printf("Flushing to file %s\n", node->name); */ + /* fprintf(stderr, "Flushing to file %s\n", + node->name); */ + os_file_flush(file); mutex_enter(&(system->mutex)); diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index 77535e4c524..e7b97e88f32 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -1426,7 +1426,7 @@ fsp_alloc_free_page( hint % FSP_EXTENT_SIZE, mtr); if (free == ULINT_UNDEFINED) { - ut_print_buf(((byte*)descr) - 500, 1000); + ut_print_buf(stderr, ((byte*)descr) - 500, 1000); ut_error; } @@ -1507,11 +1507,10 @@ fsp_free_page( xdes_t* descr; ulint state; ulint frag_n_used; - char buf[1000]; ut_ad(mtr); -/* printf("Freeing page %lu in space %lu\n", page, space); */ +/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */ header = fsp_get_space_header(space, mtr); @@ -1524,9 +1523,9 @@ fsp_free_page( "InnoDB: Error: File space extent descriptor of page %lu has state %lu\n", (ulong) page, (ulong) state); - ut_sprintf_buf(buf, ((byte*)descr) - 50, 200); - - fprintf(stderr, "InnoDB: Dump of descriptor: %s\n", buf); + fputs("InnoDB: Dump of descriptor: ", stderr); + ut_print_buf(stderr, ((byte*)descr) - 50, 200); + putc('\n', stderr); if (state == XDES_FREE) { /* We put here some fault tolerance: if the page @@ -1538,14 +1537,12 @@ fsp_free_page( ut_error; } - if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr) - == TRUE) { + if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) { fprintf(stderr, -"InnoDB: Error: File space extent descriptor of page %lu says it is free\n", - (ulong) page); - ut_sprintf_buf(buf, ((byte*)descr) - 50, 200); - - fprintf(stderr, "InnoDB: Dump of descriptor: %s\n", buf); +"InnoDB: Error: File space extent descriptor of page %lu says it is free\n" +"InnoDB: Dump of descriptor: ", (ulong) page); + ut_print_buf(stderr, ((byte*)descr) - 50, 200); + putc('\n', stderr); /* We put here some fault tolerance: if the page is already free, return without doing anything! */ @@ -1603,7 +1600,7 @@ fsp_free_extent( if (xdes_get_state(descr, mtr) == XDES_FREE) { - ut_print_buf(((byte*)descr) - 500, 1000); + ut_print_buf(stderr, (byte*)descr - 500, 1000); ut_error; } @@ -2949,7 +2946,6 @@ fseg_free_page_low( dulint descr_id; dulint seg_id; ulint i; - char errbuf[200]; ut_ad(seg_inode && mtr); ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == @@ -2963,22 +2959,22 @@ fseg_free_page_low( descr = xdes_get_descriptor(space, page, mtr); ut_a(descr); - if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr) - != FALSE) { - ut_sprintf_buf(errbuf, descr, 40); - fprintf(stderr, -"InnoDB: Dump of the tablespace extent descriptor: %s\n", errbuf); + if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) { + fputs("InnoDB: Dump of the tablespace extent descriptor: ", + stderr); + ut_print_buf(stderr, descr, 40); - fprintf(stderr, + fprintf(stderr, "\n" "InnoDB: Serious error! InnoDB is trying to free page %lu\n" "InnoDB: though it is already marked as free in the tablespace!\n" "InnoDB: The tablespace free space info is corrupt.\n" "InnoDB: You may need to dump your InnoDB tables and recreate the whole\n" "InnoDB: database!\n", (ulong) page); - - fprintf(stderr, + crash: + fputs( "InnoDB: If the InnoDB recovery crashes here, see section 6.1\n" -"InnoDB: of http://www.innodb.com/ibman.html about forcing recovery.\n"); +"InnoDB: of http://www.innodb.com/ibman.php about forcing recovery.\n", + stderr); ut_error; } @@ -3018,12 +3014,12 @@ fseg_free_page_low( ut_dulint_get_low(seg_id)); */ if (0 != ut_dulint_cmp(descr_id, seg_id)) { - ut_sprintf_buf(errbuf, descr, 40); - fprintf(stderr, -"InnoDB: Dump of the tablespace extent descriptor: %s\n", errbuf); - ut_sprintf_buf(errbuf, seg_inode, 40); - fprintf(stderr, -"InnoDB: Dump of the segment inode: %s\n", errbuf); + fputs("InnoDB: Dump of the tablespace extent descriptor: ", + stderr); + ut_print_buf(stderr, descr, 40); + fputs("\nInnoDB: Dump of the segment inode: ", stderr); + ut_print_buf(stderr, seg_inode, 40); + putc('\n', stderr); fprintf(stderr, "InnoDB: Serious error: InnoDB is trying to free space %lu page %lu,\n" @@ -3034,11 +3030,7 @@ fseg_free_page_low( (ulong) ut_dulint_get_low(descr_id), (ulong) ut_dulint_get_high(seg_id), (ulong) ut_dulint_get_low(seg_id)); - - fprintf(stderr, -"InnoDB: If the InnoDB recovery crashes here, see section 6.1\n" -"InnoDB: of http://www.innodb.com/ibman.html about forcing recovery.\n"); - ut_error; + goto crash; } not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED, @@ -3484,7 +3476,8 @@ fseg_validate_low( return(TRUE); } - + +#ifdef UNIV_DEBUG /*********************************************************************** Validates a segment. */ @@ -3509,6 +3502,7 @@ fseg_validate( return(ret); } +#endif /* UNIV_DEBUG */ /*********************************************************************** Writes info of a segment. */ @@ -3543,7 +3537,7 @@ fseg_print_low( seg_id_low = ut_dulint_get_low(d_var); seg_id_high = ut_dulint_get_high(d_var); - + n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr); n_frag = fseg_get_n_frag_pages(inode, mtr); @@ -3551,17 +3545,16 @@ fseg_print_low( n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr); n_full = flst_get_len(inode + FSEG_FULL, mtr); - printf( - "SEGMENT id %lu %lu space %lu; page %lu; res %lu used %lu; full ext %lu\n", - (ulong) seg_id_high, (ulong) seg_id_low, (ulong) space, - (ulong) page_no, (ulong) reserved, (ulong) used, - (ulong) n_full); - printf( - "fragm pages %lu; free extents %lu; not full extents %lu: pages %lu\n", + fprintf(stderr, +"SEGMENT id %lu %lu space %lu; page %lu; res %lu used %lu; full ext %lu\n" +"fragm pages %lu; free extents %lu; not full extents %lu: pages %lu\n", + (ulong) seg_id_high, (ulong) seg_id_low, (ulong) space, (ulong) page_no, + (ulong) reserved, (ulong) used, (ulong) n_full, (ulong) n_frag, (ulong) n_free, (ulong) n_not_full, (ulong) n_used); } +#ifdef UNIV_DEBUG /*********************************************************************** Writes info of a segment. */ @@ -3582,6 +3575,7 @@ fseg_print( fseg_print_low(inode, mtr); } +#endif /* UNIV_DEBUG */ /*********************************************************************** Validates the file space system and its segments. */ @@ -3862,16 +3856,15 @@ fsp_print( seg_id_low = ut_dulint_get_low(d_var); seg_id_high = ut_dulint_get_high(d_var); - printf("FILE SPACE INFO: id %lu\n", (ulong) space); - - printf("size %lu, free limit %lu, free extents %lu\n", - (ulong) size, (ulong) free_limit, (ulong) n_free); - printf( - "not full frag extents %lu: used pages %lu, full frag extents %lu\n", - (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag); - - printf("first seg id not used %lu %lu\n", (ulong) seg_id_high, - (ulong) seg_id_low); + fprintf(stderr, +"FILE SPACE INFO: id %lu\n" +"size %lu, free limit %lu, free extents %lu\n" +"not full frag extents %lu: used pages %lu, full frag extents %lu\n" +"first seg id not used %lu %lu\n", + (long) space, + (ulong) size, (ulong) free_limit, (ulong) n_free, + (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag, + (ulong) seg_id_high, (ulong) seg_id_low); mtr_commit(&mtr); @@ -3950,5 +3943,5 @@ fsp_print( mtr_commit(&mtr2); - printf("NUMBER of file segments: %lu\n", (ulong) n_segs); + fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs); } diff --git a/innobase/fut/fut0lst.c b/innobase/fut/fut0lst.c index 79830c36eb5..3d92aaba1ef 100644 --- a/innobase/fut/fut0lst.c +++ b/innobase/fut/fut0lst.c @@ -490,6 +490,7 @@ flst_validate( return(TRUE); } +#ifdef UNIV_DEBUG /************************************************************************ Prints info of a file-based list. */ @@ -509,9 +510,11 @@ flst_print( len = flst_get_len(base, mtr); - printf("FILE-BASED LIST:\n"); - printf("Base node in space %lu page %lu byte offset %lu; len %lu\n", + fprintf(stderr, + "FILE-BASED LIST:\n" + "Base node in space %lu page %lu byte offset %lu; len %lu\n", (ulong) buf_frame_get_space_id(frame), (ulong) buf_frame_get_page_no(frame), (ulong) (base - frame), (ulong) len); } +#endif /* UNIV_DEBUG */ diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c index 5e807406ce0..e8082f016b9 100644 --- a/innobase/ha/ha0ha.c +++ b/innobase/ha/ha0ha.c @@ -317,22 +317,13 @@ Prints info of a hash table. */ void ha_print_info( /*==========*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end,/* in: buffer end */ + FILE* file, /* in: file where to print */ hash_table_t* table) /* in: hash table */ { hash_cell_t* cell; -/* ha_node_t* node; - ulint nodes = 0; - ulint len = 0; - ulint max_len = 0; */ ulint cells = 0; ulint n_bufs; ulint i; - - if (buf_end - buf < 200) { - return; - } for (i = 0; i < hash_get_n_cells(table); i++) { @@ -341,33 +332,12 @@ ha_print_info( if (cell->node) { cells++; -/* - len = 0; - - node = cell->node; - - for (;;) { - len++; - nodes++; - - if (ha_chain_get_next(table, node) == NULL) { - - break; - } - - node = node->next; - } - - if (len > max_len) { - max_len = len; - } -*/ } } - buf += sprintf(buf, -"Hash table size %lu, used cells %lu", (ulong) hash_get_n_cells(table), - (ulong) cells); + fprintf(file, + "Hash table size %lu, used cells %lu", + (ulong) hash_get_n_cells(table), (ulong) cells); if (table->heaps == NULL && table->heap != NULL) { @@ -380,6 +350,6 @@ ha_print_info( n_bufs++; } - buf += sprintf(buf, ", node heap has %lu buffer(s)\n", (ulong) n_bufs); + fprintf(file, ", node heap has %lu buffer(s)\n", (ulong) n_bufs); } } diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c index 42ca34e7f10..ecdcf08e4c6 100644 --- a/innobase/ibuf/ibuf0ibuf.c +++ b/innobase/ibuf/ibuf0ibuf.c @@ -131,9 +131,10 @@ access order rules. */ #define IBUF_POOL_SIZE_PER_MAX_SIZE 2 /* The insert buffer control structure */ -ibuf_t* ibuf = NULL; +ibuf_t* ibuf = NULL; -ulint ibuf_rnd = 986058871; +static +ulint ibuf_rnd = 986058871; ulint ibuf_flush_count = 0; @@ -142,9 +143,9 @@ ulint ibuf_flush_count = 0; #define IBUF_COUNT_N_PAGES 2000 /* Buffered entry counts for file pages, used in debugging */ -ulint* ibuf_counts[IBUF_COUNT_N_SPACES]; +static ulint* ibuf_counts[IBUF_COUNT_N_SPACES]; -ibool ibuf_counts_inited = FALSE; +static ibool ibuf_counts_inited = FALSE; /* The start address for an insert buffer bitmap page bitmap */ #define IBUF_BITMAP PAGE_DATA @@ -158,15 +159,18 @@ ibool ibuf_counts_inited = FALSE; /* Number of bits describing a single page */ #define IBUF_BITS_PER_PAGE 4 +#if IBUF_BITS_PER_PAGE % 2 +# error "IBUF_BITS_PER_PAGE must be an even number!" +#endif /* The mutex used to block pessimistic inserts to ibuf trees */ -mutex_t ibuf_pessimistic_insert_mutex; +static mutex_t ibuf_pessimistic_insert_mutex; /* The mutex protecting the insert buffer structs */ -mutex_t ibuf_mutex; +static mutex_t ibuf_mutex; /* The mutex protecting the insert buffer bitmaps */ -mutex_t ibuf_bitmap_mutex; +static mutex_t ibuf_bitmap_mutex; /* The area in pages from which contract looks for page numbers for merge */ #define IBUF_MERGE_AREA 8 @@ -197,13 +201,15 @@ because ibuf merge is done to a page when it is read in, and it is still physically like the index page even if the index would have been dropped! So, there seems to be no problem. */ +#ifdef UNIV_DEBUG /********************************************************************** Validates the ibuf data structures when the caller owns ibuf_mutex. */ - +static ibool ibuf_validate_low(void); /*===================*/ /* out: TRUE if ok */ +#endif /* UNIV_DEBUG */ /********************************************************************** Sets the flag in the current OS thread local storage denoting that it is @@ -326,9 +332,9 @@ ibuf_count_get( return(*(ibuf_counts[space] + page_no)); } -#ifdef UNIV_IBUF_DEBUG /********************************************************************** Sets the ibuf count for a given page. */ +#ifdef UNIV_IBUF_DEBUG static void ibuf_count_set( @@ -437,7 +443,7 @@ ibuf_data_sizes_update( ibuf->size = ibuf->size + data->size - old_size; -/* printf("ibuf size %lu, space ibuf size %lu\n", ibuf->size, +/* fprintf(stderr, "ibuf size %lu, space ibuf size %lu\n", ibuf->size, data->size); */ } @@ -468,7 +474,7 @@ ibuf_data_init_for_space( #ifdef UNIV_LOG_DEBUG if (space % 2 == 1) { - printf("No ibuf op in replicate space\n"); + fputs("No ibuf op in replicate space\n", stderr); return(NULL); } @@ -766,7 +772,8 @@ ibuf_set_free_bits_low( bitmap_page = ibuf_bitmap_get_map_page(buf_frame_get_space_id(page), buf_frame_get_page_no(page), mtr); #ifdef UNIV_IBUF_DEBUG - /* printf("Setting page no %lu free bits to %lu should be %lu\n", + /* fprintf(stderr, + "Setting page no %lu free bits to %lu should be %lu\n", buf_frame_get_page_no(page), val, ibuf_index_page_calc_free(page)); */ @@ -820,7 +827,7 @@ ibuf_set_free_bits( buf_frame_get_page_no(page), IBUF_BITMAP_FREE, &mtr); if (old_val != max_val) { - /* printf( + /* fprintf(stderr, "Ibuf: page %lu old val %lu max val %lu\n", buf_frame_get_page_no(page), old_val, max_val); */ } @@ -829,7 +836,7 @@ ibuf_set_free_bits( #endif } #ifdef UNIV_IBUF_DEBUG -/* printf("Setting page no %lu free bits to %lu should be %lu\n", +/* fprintf(stderr, "Setting page no %lu free bits to %lu should be %lu\n", buf_frame_get_page_no(page), val, ibuf_index_page_calc_free(page)); */ @@ -1014,7 +1021,7 @@ ibuf_page_low( #ifdef UNIV_LOG_DEBUG if (space % 2 != 0) { - printf("No ibuf in a replicate space\n"); + fputs("No ibuf in a replicate space\n", stderr); return(FALSE); } @@ -1735,7 +1742,8 @@ ibuf_free_excess_pages( /* Not yet initialized */ #ifdef UNIV_DEBUG - /*printf("Ibuf for space %lu not yet initialized\n", space); */ + /*fprintf(stderr, + "Ibuf for space %lu not yet initialized\n", space); */ #endif return; @@ -1933,7 +1941,7 @@ ibuf_get_merge_page_nos( #ifdef UNIV_IBUF_DEBUG ut_a(*n_stored <= IBUF_MAX_N_PAGES_MERGED); #endif -/* printf("Ibuf merge batch %lu pages %lu volume\n", *n_stored, +/* fprintf(stderr, "Ibuf merge batch %lu pages %lu volume\n", *n_stored, sum_volumes); */ return(sum_volumes); } @@ -2044,8 +2052,8 @@ loop: space_ids, space_versions, page_nos, &n_stored); #ifdef UNIV_IBUF_DEBUG - /* printf("Ibuf contract sync %lu pages %lu volume %lu\n", sync, - n_stored, sum_sizes); */ + /* fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n", + sync, n_stored, sum_sizes); */ #endif ibuf_exit(); @@ -2431,7 +2439,7 @@ ibuf_insert_low( mutex_exit(&ibuf_mutex); #ifdef UNIV_IBUF_DEBUG - printf("Ibuf too big\n"); + fputs("Ibuf too big\n", stderr); #endif /* Use synchronous contract (== TRUE) */ ibuf_contract(TRUE); @@ -2664,8 +2672,8 @@ ibuf_insert( if (err == DB_SUCCESS) { #ifdef UNIV_IBUF_DEBUG - /* printf("Ibuf insert for page no %lu of index %s\n", page_no, - index->name); */ + /* fprintf(stderr, "Ibuf insert for page no %lu of index %s\n", + page_no, index->name); */ #endif return(TRUE); @@ -2693,7 +2701,6 @@ ibuf_insert_to_index_page( rec_t* rec; page_t* bitmap_page; ulint old_bits; - char errbuf[1000]; ut_ad(ibuf_inside()); ut_ad(dtuple_check_typed(entry)); @@ -2703,17 +2710,17 @@ ibuf_insert_to_index_page( fprintf(stderr, "InnoDB: Trying to insert a record from the insert buffer to an index page\n" -"InnoDB: but the number of fields does not match!\n%s\n", errbuf); +"InnoDB: but the number of fields does not match!\n"); buf_page_print(page); - dtuple_sprintf(errbuf, 900, entry); + dtuple_print(stderr, entry); - fprintf(stderr, + fputs( "InnoDB: The table where where this index record belongs\n" "InnoDB: is now probably corrupt. Please run CHECK TABLE on\n" "InnoDB: your tables.\n" -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com!\n"); +"InnoDB: Send a detailed bug report to mysql@lists.mysql.com!\n", stderr); return; } @@ -2743,14 +2750,14 @@ ibuf_insert_to_index_page( "InnoDB: Error: Insert buffer insert fails; page free %lu, dtuple size %lu\n", (ulong) page_get_max_insert_size(page, 1), (ulong) rec_get_converted_size(entry)); - - dtuple_sprintf(errbuf, 900, entry); - - fprintf(stderr, -"InnoDB: Cannot insert index record %s\n" -"InnoDB: The table where where this index record belongs\n" + fputs("InnoDB: Cannot insert index record ", + stderr); + dtuple_print(stderr, entry); + fputs( +"\nInnoDB: The table where where this index record belongs\n" "InnoDB: is now probably corrupt. Please run CHECK TABLE on\n" -"InnoDB: that table.\n", errbuf); +"InnoDB: that table.\n", stderr); + bitmap_page = ibuf_bitmap_get_map_page( buf_frame_get_space_id(page), buf_frame_get_page_no(page), @@ -2762,8 +2769,8 @@ ibuf_insert_to_index_page( fprintf(stderr, "Bitmap bits %lu\n", (ulong) old_bits); - fprintf(stderr, -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com!\n"); + fputs( +"InnoDB: Send a detailed bug report to mysql@lists.mysql.com!\n", stderr); } } } @@ -2826,23 +2833,21 @@ ibuf_delete_rec( if (!success) { fprintf(stderr, -"InnoDB: ERROR: Send the output to mysql@lists.mysql.com\n" -"InnoDB: ibuf cursor restoration fails!\n" -"InnoDB: ibuf record inserted to space %lu page %lu\n", (ulong) space, - (ulong) page_no); + "InnoDB: ERROR: Send the output to mysql@lists.mysql.com\n" + "InnoDB: ibuf cursor restoration fails!\n" + "InnoDB: ibuf record inserted to page %lu\n", (ulong) page_no); fflush(stderr); - rec_print(btr_pcur_get_rec(pcur)); - rec_print(pcur->old_rec); - dtuple_print(search_tuple); + rec_print(stderr, btr_pcur_get_rec(pcur)); + rec_print(stderr, pcur->old_rec); + dtuple_print(stderr, search_tuple); - rec_print(page_rec_get_next(btr_pcur_get_rec(pcur))); - fflush(stdout); + rec_print(stderr, page_rec_get_next(btr_pcur_get_rec(pcur))); + fflush(stderr); btr_pcur_commit_specify_mtr(pcur, mtr); - fprintf(stderr, - "InnoDB: Validating insert buffer tree:\n"); + fputs("InnoDB: Validating insert buffer tree:\n", stderr); ut_a(btr_validate_tree(ibuf_data->index->tree)); fprintf(stderr, "InnoDB: ibuf tree ok\n"); @@ -2902,20 +2907,16 @@ ibuf_merge_or_delete_for_page( dtuple_t* entry; dtuple_t* search_tuple; rec_t* ibuf_rec; - ibool closed; buf_block_t* block; page_t* bitmap_page; ibuf_data_t* ibuf_data; - ibool success; ulint n_inserts; +#ifdef UNIV_IBUF_DEBUG ulint volume; - ulint old_bits; - ulint new_bits; - dulint max_trx_id; +#endif ibool tablespace_being_deleted = FALSE; ibool corruption_noticed = FALSE; mtr_t mtr; - char err_buf[500]; if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { @@ -2925,7 +2926,7 @@ ibuf_merge_or_delete_for_page( #ifdef UNIV_LOG_DEBUG if (space % 2 != 0) { - printf("No ibuf operation in a replicate space\n"); + fputs("No ibuf operation in a replicate space\n", stderr); return; } @@ -3004,8 +3005,8 @@ ibuf_merge_or_delete_for_page( mtr_start(&mtr); - fprintf(stderr, -" InnoDB: Dump of the ibuf bitmap page:\n"); + fputs(" InnoDB: Dump of the ibuf bitmap page:\n", + stderr); bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); @@ -3013,7 +3014,7 @@ ibuf_merge_or_delete_for_page( mtr_commit(&mtr); - fprintf(stderr, "\nInnoDB: Dump of the page:\n"); + fputs("\nInnoDB: Dump of the page:\n", stderr); buf_page_print(page); @@ -3032,12 +3033,14 @@ ibuf_merge_or_delete_for_page( } n_inserts = 0; +#ifdef UNIV_IBUF_DEBUG volume = 0; +#endif loop: mtr_start(&mtr); if (page) { - success = buf_page_get_known_nowait(RW_X_LATCH, page, + ibool success = buf_page_get_known_nowait(RW_X_LATCH, page, BUF_KEEP_OLD, IB__FILE__, __LINE__, &mtr); @@ -3072,9 +3075,9 @@ loop: } if (corruption_noticed) { - rec_sprintf(err_buf, 450, ibuf_rec); - fprintf(stderr, -"InnoDB: Discarding record\n %s\n from the insert buffer!\n\n", err_buf); + fputs("InnoDB: Discarding record\n ", stderr); + rec_print(stderr, ibuf_rec); + fputs("\n from the insert buffer!\n\n", stderr); } else if (page) { /* Now we have at pcur a record which should be inserted to the index page; NOTE that the call below @@ -3082,7 +3085,7 @@ loop: keep the latch to the ibuf_rec page until the insertion is finished! */ - max_trx_id = page_get_max_trx_id( + dulint max_trx_id = page_get_max_trx_id( buf_frame_align(ibuf_rec)); page_update_max_trx_id(page, max_trx_id); @@ -3099,9 +3102,8 @@ loop: n_inserts++; /* Delete the record from ibuf */ - closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple, - &mtr); - if (closed) { + if (ibuf_delete_rec(space, page_no, &pcur, search_tuple, + &mtr)) { /* Deletion was pessimistic and mtr was committed: we start from the beginning again */ @@ -3127,12 +3129,12 @@ reset_bit: bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_BUFFERED, FALSE, &mtr); - if (page) { - old_bits = ibuf_bitmap_page_get_bits(bitmap_page, - page_no, IBUF_BITMAP_FREE, &mtr); - new_bits = ibuf_index_page_calc_free(page); + if (page) { + ulint old_bits = ibuf_bitmap_page_get_bits(bitmap_page, + page_no, IBUF_BITMAP_FREE, &mtr); + ulint new_bits = ibuf_index_page_calc_free(page); #ifdef UNIV_IBUF_DEBUG - /* printf("Old bits %lu new bits %lu max size %lu\n", + /* fprintf(stderr, "Old bits %lu new bits %lu max size %lu\n", old_bits, new_bits, page_get_max_insert_size_after_reorganize(page, 1)); */ #endif @@ -3144,7 +3146,8 @@ reset_bit: } } #ifdef UNIV_IBUF_DEBUG - /* printf("Ibuf merge %lu records volume %lu to page no %lu\n", + /* fprintf(stderr, + "Ibuf merge %lu records volume %lu to page no %lu\n", n_inserts, volume, page_no); */ #endif mtr_commit(&mtr); @@ -3276,9 +3279,10 @@ leave_loop: mem_heap_free(heap); } +#ifdef UNIV_DEBUG /********************************************************************** Validates the ibuf data structures when the caller owns ibuf_mutex. */ - +static ibool ibuf_validate_low(void) /*===================*/ @@ -3305,6 +3309,7 @@ ibuf_validate_low(void) return(TRUE); } +#endif /* UNIV_DEBUG */ /********************************************************************** Looks if the insert buffer is empty. */ @@ -3362,36 +3367,36 @@ Prints info of ibuf. */ void ibuf_print( /*=======*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end)/* in: buffer end */ + FILE* file) /* in: file where to print */ { ibuf_data_t* data; #ifdef UNIV_IBUF_DEBUG ulint i; #endif - if (buf_end - buf < 500) { - return; - } mutex_enter(&ibuf_mutex); data = UT_LIST_GET_FIRST(ibuf->data_list); while (data) { - buf += sprintf(buf, + fprintf(file, "Ibuf for space %lu: size %lu, free list len %lu, seg size %lu,", (ulong) data->space, (ulong) data->size, (ulong) data->free_list_len, (ulong) data->seg_size); if (data->empty) { - buf += sprintf(buf, " is empty\n"); + fputs(" is empty\n", file); } else { - buf += sprintf(buf, " is not empty\n"); + fputs(" is not empty\n", file); } - - buf += sprintf(buf, + fprintf(file, + "Ibuf for space %lu: size %lu, free list len %lu, seg size %lu,\n" "%lu inserts, %lu merged recs, %lu merges\n", + (ulong) data->space, + (ulong) data->size, + (ulong) data->free_list_len, + (ulong) data->seg_size, (ulong) data->n_inserts, (ulong) data->n_merged_recs, (ulong) data->n_merges); @@ -3399,7 +3404,8 @@ ibuf_print( for (i = 0; i < IBUF_COUNT_N_PAGES; i++) { if (ibuf_count_get(data->space, i) > 0) { - printf("Ibuf count for page %lu is %lu\n", + fprintf(stderr, + "Ibuf count for page %lu is %lu\n", (ulong) i, (ulong) ibuf_count_get(data->space, i)); } diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h index 8606fcd2a5c..e904db3272f 100644 --- a/innobase/include/btr0btr.h +++ b/innobase/include/btr0btr.h @@ -392,6 +392,7 @@ btr_page_free_low( page_t* page, /* in: page to be freed, x-latched */ ulint level, /* in: page level */ mtr_t* mtr); /* in: mtr */ +#ifdef UNIV_DEBUG /***************************************************************** Prints size info of a B-tree. */ @@ -408,6 +409,7 @@ btr_print_tree( dict_tree_t* tree, /* in: tree */ ulint width); /* in: print this many entries from start and end */ +#endif /* UNIV_DEBUG */ /**************************************************************** Checks the size and number of fields in a record based on the definition of the index. */ diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index 3cab717546a..6b8da886045 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -54,9 +54,11 @@ Created 11/5/1995 Heikki Tuuri #define BUF_KEEP_OLD 52 extern buf_pool_t* buf_pool; /* The buffer pool of the database */ +#ifdef UNIV_DEBUG extern ibool buf_debug_prints;/* If this is set TRUE, the program prints info whenever read or flush occurs */ +#endif /* UNIV_DEBUG */ /************************************************************************ Creates the buffer pool. */ @@ -476,12 +478,14 @@ buf_pool_is_block( /*==============*/ /* out: TRUE if pointer to block */ void* ptr); /* in: pointer to memory */ +#ifdef UNIV_DEBUG /************************************************************************* Validates the buffer pool data structure. */ ibool buf_validate(void); /*==============*/ +#endif /* UNIV_DEBUG */ /************************************************************************ Prints a page to stderr. */ @@ -507,8 +511,7 @@ Prints info of the buffer i/o. */ void buf_print_io( /*=========*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end);/* in: buffer end */ + FILE* file); /* in: file where to print */ /************************************************************************* Returns the ratio in percents of modified pages in the buffer pool / database pages in the buffer pool. */ @@ -894,7 +897,7 @@ struct buf_pool_struct{ ulint n_pend_reads; /* number of pending read operations */ - time_t last_printout_time; /* when buf_print was last time + time_t last_printout_time; /* when buf_print_io was last time called */ ulint n_pages_read; /* number read operations */ ulint n_pages_written;/* number write operations */ @@ -909,10 +912,10 @@ struct buf_pool_struct{ ulint n_pages_awe_remapped; /* if AWE is enabled, the number of remaps of blocks to buffer frames */ - ulint n_page_gets_old;/* n_page_gets when buf_print was + ulint n_page_gets_old;/* n_page_gets when buf_print_io was last time called: used to calculate hit rate */ - ulint n_pages_read_old;/* n_pages_read when buf_print was + ulint n_pages_read_old;/* n_pages_read when buf_print_io was last time called */ ulint n_pages_written_old;/* number write operations */ ulint n_pages_created_old;/* number of pages created in diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic index cb54785128f..b644afcbdff 100644 --- a/innobase/include/buf0buf.ic +++ b/innobase/include/buf0buf.ic @@ -11,10 +11,6 @@ Created 11/5/1995 Heikki Tuuri #include "buf0rea.h" #include "mtr0mtr.h" -extern ulint buf_dbg_counter; /* This is used to insert validation - operations in execution in the - debug version */ - /************************************************************************ Recommends a move of a block to the start of the LRU list if there is danger of dropping from the buffer pool. NOTE: does not reserve the buffer pool @@ -215,14 +211,14 @@ buf_block_align( ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: Error: trying to access a stray pointer %lx\n" -"InnoDB: buf pool start is at %lx, end at %lx\n" +"InnoDB: Error: trying to access a stray pointer %p\n" +"InnoDB: buf pool start is at %p, end at %p\n" "InnoDB: Probable reason is database corruption or memory\n" "InnoDB: corruption. If this happens in an InnoDB database recovery,\n" "InnoDB: you can look from section 6.1 at http://www.innodb.com/ibman.html\n" "InnoDB: how to force recovery.\n", - (long)ptr, (long)frame_zero, - (long)(buf_pool->high_end)); + ptr, frame_zero, + buf_pool->high_end); ut_error; } @@ -251,14 +247,14 @@ buf_frame_align( ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: Error: trying to access a stray pointer %lx\n" -"InnoDB: buf pool start is at %lx, end at %lx\n" +"InnoDB: Error: trying to access a stray pointer %p\n" +"InnoDB: buf pool start is at %p, end at %p\n" "InnoDB: Probable reason is database corruption or memory\n" "InnoDB: corruption. If this happens in an InnoDB database recovery,\n" "InnoDB: you can look from section 6.1 at http://www.innodb.com/ibman.html\n" "InnoDB: how to force recovery.\n", - (long)ptr, (long)(buf_pool->frame_zero), - (long)(buf_pool->high_end)); + ptr, buf_pool->frame_zero, + buf_pool->high_end); ut_error; } diff --git a/innobase/include/buf0flu.h b/innobase/include/buf0flu.h index 1b40acaa269..6f39eef7210 100644 --- a/innobase/include/buf0flu.h +++ b/innobase/include/buf0flu.h @@ -97,6 +97,7 @@ buf_flush_ready_for_replace( /* out: TRUE if can replace immediately */ buf_block_t* block); /* in: buffer control block, must be in state BUF_BLOCK_FILE_PAGE and in the LRU list */ +#ifdef UNIV_DEBUG /********************************************************************** Validates the flush list. */ @@ -104,6 +105,7 @@ ibool buf_flush_validate(void); /*====================*/ /* out: TRUE if ok */ +#endif /* UNIV_DEBUG */ /* When buf_flush_free_margin is called, it tries to make this many blocks available to replacement in the free list and at the end of the LRU list (to diff --git a/innobase/include/buf0lru.h b/innobase/include/buf0lru.h index 69a376f8cab..98aa0252e12 100644 --- a/innobase/include/buf0lru.h +++ b/innobase/include/buf0lru.h @@ -112,6 +112,7 @@ void buf_LRU_make_block_old( /*===================*/ buf_block_t* block); /* in: control block */ +#ifdef UNIV_DEBUG /************************************************************************** Validates the LRU list. */ @@ -124,6 +125,7 @@ Prints the LRU list. */ void buf_LRU_print(void); /*===============*/ +#endif /* UNIV_DEBUG */ #ifndef UNIV_NONINL #include "buf0lru.ic" diff --git a/innobase/include/data0data.h b/innobase/include/data0data.h index c4e93bec738..99d3c297039 100644 --- a/innobase/include/data0data.h +++ b/innobase/include/data0data.h @@ -294,6 +294,7 @@ dtuple_check_typed_no_assert( /*=========================*/ /* out: TRUE if ok */ dtuple_t* tuple); /* in: tuple */ +#ifdef UNIV_DEBUG /************************************************************** Validates the consistency of a tuple which must be complete, i.e, all fields must have been set. */ @@ -303,6 +304,7 @@ dtuple_validate( /*============*/ /* out: TRUE if ok */ dtuple_t* tuple); /* in: tuple */ +#endif /* UNIV_DEBUG */ /***************************************************************** Pretty prints a dfield value according to its data type. */ @@ -324,16 +326,7 @@ The following function prints the contents of a tuple. */ void dtuple_print( /*=========*/ - dtuple_t* tuple); /* in: tuple */ -/************************************************************** -The following function prints the contents of a tuple to a buffer. */ - -ulint -dtuple_sprintf( -/*===========*/ - /* out: printed length in bytes */ - char* buf, /* in: print buffer */ - ulint buf_len,/* in: buf length in bytes */ + FILE* f, /* in: output stream */ dtuple_t* tuple); /* in: tuple */ /****************************************************************** Moves parts of long fields in entry to the big record vector so that diff --git a/innobase/include/data0data.ic b/innobase/include/data0data.ic index def80d3f430..697a272ccd6 100644 --- a/innobase/include/data0data.ic +++ b/innobase/include/data0data.ic @@ -299,7 +299,7 @@ dtuple_get_data_size( ut_ad(tuple); ut_ad(dtuple_check_typed(tuple)); - ut_ad(tuple->magic_n = DATA_TUPLE_MAGIC_N); + ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N); n_fields = tuple->n_fields; @@ -355,7 +355,7 @@ dtuple_fold( ulint fold; ut_ad(tuple); - ut_ad(tuple->magic_n = DATA_TUPLE_MAGIC_N); + ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N); ut_ad(dtuple_check_typed(tuple)); fold = ut_fold_dulint(tree_id); diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h index 2b27ead5fac..2138df97392 100644 --- a/innobase/include/data0type.h +++ b/innobase/include/data0type.h @@ -305,6 +305,7 @@ dtype_new_read_for_order_and_null_size( /*===================================*/ dtype_t* type, /* in: type struct */ byte* buf); /* in: buffer for stored type order info */ +#ifdef UNIV_DEBUG /************************************************************************* Validates a data type structure. */ @@ -313,6 +314,7 @@ dtype_validate( /*===========*/ /* out: TRUE if ok */ dtype_t* type); /* in: type struct to validate */ +#endif /* UNIV_DEBUG */ /************************************************************************* Prints a data type structure. */ diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index 688685cff8b..98636f6e1cb 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -32,20 +32,21 @@ Get the database name length in a table name. */ ulint dict_get_db_name_len( /*=================*/ - /* out: database name length */ - char* name); /* in: table name in the form dbname '/' tablename */ + /* out: database name length */ + const char* name); /* in: table name in the form + dbname '/' tablename */ /************************************************************************* Accepts a specified string. Comparisons are case-insensitive. */ -char* +const char* dict_accept( /*========*/ - /* out: if string was accepted, the pointer - is moved after that, else ptr is returned */ - char* ptr, /* in: scan from this */ - const char* string,/* in: accept only this string as the next - non-whitespace string */ - ibool* success);/* out: TRUE if accepted */ + /* out: if string was accepted, the pointer + is moved after that, else ptr is returned */ + const char* ptr, /* in: scan from this */ + const char* string, /* in: accept only this string as the next + non-whitespace string */ + ibool* success);/* out: TRUE if accepted */ /************************************************************************ Decrements the count of open MySQL handles to a table. */ @@ -69,41 +70,6 @@ database directories. */ void dict_load_space_id_list(void); /*=========================*/ -/************************************************************************** -Returns a stored procedure object and memoryfixes it. */ -UNIV_INLINE -dict_proc_t* -dict_procedure_get( -/*===============*/ - /* out: procedure, NULL if does not exist */ - char* proc_name, /* in: table name */ - trx_t* trx); /* in: transaction handle or NULL */ -/************************************************************************** -Adds a stored procedure object to the dictionary cache. */ - -void -dict_procedure_add_to_cache( -/*========================*/ - dict_proc_t* proc); /* in: procedure */ -/************************************************************************** -Reserves a parsed copy of a stored procedure to execute. If there are no -free parsed copies left at the moment, parses a new copy. Takes the copy off -the list of copies: the copy must be returned there with -dict_procedure_release_parsed_copy. */ - -que_t* -dict_procedure_reserve_parsed_copy( -/*===============================*/ - /* out: the query graph */ - dict_proc_t* proc); /* in: dictionary procedure node */ -/************************************************************************** -Releases a parsed copy of an executed stored procedure. Puts the copy to the -list of copies. */ - -void -dict_procedure_release_parsed_copy( -/*===============================*/ - que_t* graph); /* in: query graph of a stored procedure */ /************************************************************************* Gets the column data type. */ UNIV_INLINE @@ -270,7 +236,7 @@ dict_foreign_parse_drop_constraints( dict_table_t* table, /* in: table */ ulint* n, /* out: number of constraints to drop */ - char*** constraints_to_drop); /* out: id's of the + const char*** constraints_to_drop); /* out: id's of the constraints to drop */ /************************************************************************** Returns a table object and memoryfixes it. NOTE! This is a high-level @@ -354,18 +320,19 @@ dict_table_get_index_noninline( dict_table_t* table, /* in: table */ char* name); /* in: index name */ /************************************************************************** -Prints a table definition. */ +Prints a table data. */ void -dict_table_print( -/*=============*/ +dict_table_print_low( +/*=================*/ dict_table_t* table); /* in: table */ +#ifdef UNIV_DEBUG /************************************************************************** -Prints a table data. */ +Prints a table definition. */ void -dict_table_print_low( -/*=================*/ +dict_table_print( +/*=============*/ dict_table_t* table); /* in: table */ /************************************************************************** Prints a table data when we know the table name. */ @@ -374,8 +341,9 @@ void dict_table_print_by_name( /*=====================*/ char* name); +#endif /* UNIV_DEBUG */ /************************************************************************** -Sprintfs to a string info on foreign keys of a table. */ +Outputs info on foreign keys of a table. */ void dict_print_info_on_foreign_keys( @@ -384,19 +352,23 @@ dict_print_info_on_foreign_keys( a format suitable to be inserted into a CREATE TABLE, otherwise in the format of SHOW TABLE STATUS */ - char* str, /* in/out: pointer to a string */ - ulint len, /* in: space in str available for info */ + FILE* file, /* in: file where to print */ dict_table_t* table); /* in: table */ /************************************************************************** -Sprintfs to a string info on a foreign key of a table in a format suitable -for CREATE TABLE. */ - -char* +Outputs info on a foreign key of a table in a format suitable for +CREATE TABLE. */ +void dict_print_info_on_foreign_key_in_create_format( /*============================================*/ - /* out: how far in buf we printed */ - dict_foreign_t* foreign,/* in: foreign key constraint */ - char* buf); /* in: buffer of at least 5000 bytes */ + FILE* file, /* in: file where to print */ + dict_foreign_t* foreign);/* in: foreign key constraint */ +/************************************************************************ +Displays the names of the index and the table. */ +void +dict_index_name_print( +/*==================*/ + FILE* file, /* in: output stream */ + const dict_index_t* index); /* in: index to print */ /************************************************************************ Gets the first index on the table (the clustered index). */ UNIV_INLINE @@ -899,14 +871,21 @@ Releases the dictionary system mutex for MySQL. */ void dict_mutex_exit_for_mysql(void); /*===========================*/ +/************************************************************************ +Checks if the database name in two table names is the same. */ -/* The following len must be at least 10000 bytes! */ -#define DICT_FOREIGN_ERR_BUF_LEN 10000 +ibool +dict_tables_have_same_db( +/*=====================*/ + /* out: TRUE if same db name */ + const char* name1, /* in: table name in the form + dbname '/' tablename */ + const char* name2); /* in: table name in the form + dbname '/' tablename */ /* Buffers for storing detailed information about the latest foreign key and unique key errors */ -extern char* dict_foreign_err_buf; -extern char* dict_unique_err_buf; +extern FILE* dict_foreign_err_file; extern mutex_t dict_foreign_err_mutex; /* mutex protecting the buffers */ extern dict_sys_t* dict_sys; /* the dictionary system */ @@ -932,8 +911,6 @@ struct dict_sys_struct{ hash_table_t* table_id_hash; /* hash table of the tables, based on id */ hash_table_t* col_hash; /* hash table of the columns */ - hash_table_t* procedure_hash; /* hash table of the stored - procedures */ UT_LIST_BASE_NODE_T(dict_table_t) table_LRU; /* LRU list of tables */ ulint size; /* varying space in bytes occupied diff --git a/innobase/include/dict0dict.ic b/innobase/include/dict0dict.ic index b70822e331f..57ef4b896f5 100644 --- a/innobase/include/dict0dict.ic +++ b/innobase/include/dict0dict.ic @@ -582,37 +582,6 @@ dict_table_get_low( } /************************************************************************** -Returns a stored procedure object and memoryfixes it. */ -UNIV_INLINE -dict_proc_t* -dict_procedure_get( -/*===============*/ - /* out: procedure, NULL if does not exist */ - char* proc_name, /* in: table name */ - trx_t* trx) /* in: transaction handle or NULL */ -{ - dict_proc_t* proc; - ulint name_fold; - - UT_NOT_USED(trx); - - mutex_enter(&(dict_sys->mutex)); - - /* Look for the table name in the hash table */ - name_fold = ut_fold_string(proc_name); - - HASH_SEARCH(name_hash, dict_sys->procedure_hash, name_fold, proc, - ut_strcmp(proc->name, proc_name) == 0); - if (proc != NULL) { - proc->mem_fix++; - } - - mutex_exit(&(dict_sys->mutex)); - - return(proc); -} - -/************************************************************************** Returns a table object, based on table id, and memoryfixes it. */ UNIV_INLINE dict_table_t* diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index 23753df4079..674868c9fce 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -132,18 +132,6 @@ dict_foreign_t* dict_mem_foreign_create(void); /*=========================*/ /* out, own: foreign constraint struct */ -/************************************************************************** -Creates a procedure memory object. */ - -dict_proc_t* -dict_mem_procedure_create( -/*======================*/ - /* out, own: procedure object */ - char* name, /* in: procedure name */ - char* sql_string, /* in: procedure definition as an SQL - string */ - que_fork_t* graph); /* in: parsed procedure graph */ - /* Data structure for a column in a table */ struct dict_col_struct{ @@ -427,24 +415,6 @@ struct dict_table_struct{ #endif /* UNIV_DEBUG */ }; -/* Data structure for a stored procedure */ -struct dict_proc_struct{ - mem_heap_t* heap; /* memory heap */ - char* name; /* procedure name */ - char* sql_string; - /* procedure definition as an SQL string: - we can produce more parsed instances of the - procedure by parsing this string */ - hash_node_t name_hash; - /* hash chain node */ - UT_LIST_BASE_NODE_T(que_fork_t) graphs; - /* list of parsed instances of the procedure: - there may be many of them, and they are - recycled */ - ulint mem_fix;/* count of how many times this struct - has been fixed in memory */ -}; - #ifndef UNIV_NONINL #include "dict0mem.ic" #endif diff --git a/innobase/include/dict0types.h b/innobase/include/dict0types.h index 498c6f46b7b..bd8a1a996d1 100644 --- a/innobase/include/dict0types.h +++ b/innobase/include/dict0types.h @@ -15,7 +15,6 @@ typedef struct dict_field_struct dict_field_t; typedef struct dict_index_struct dict_index_t; typedef struct dict_tree_struct dict_tree_t; typedef struct dict_table_struct dict_table_t; -typedef struct dict_proc_struct dict_proc_t; typedef struct dict_foreign_struct dict_foreign_t; /* A cluster object is a table object with the type field set to diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h index 310336af38e..f7cdeb7f195 100644 --- a/innobase/include/fil0fil.h +++ b/innobase/include/fil0fil.h @@ -19,7 +19,7 @@ Created 10/25/1995 Heikki Tuuri /* When mysqld is run, the default directory "." is the mysqld datadir, but in ibbackup we must set it explicitly; the patgh must NOT contain the trailing '/' or '\' */ -extern char* fil_path_to_mysql_datadir; +extern const char* fil_path_to_mysql_datadir; /* Initial size of a single-table tablespace in pages */ #define FIL_IBD_FILE_INITIAL_SIZE 4 diff --git a/innobase/include/fsp0fsp.h b/innobase/include/fsp0fsp.h index 2fcde882df7..20f4f4c2abd 100644 --- a/innobase/include/fsp0fsp.h +++ b/innobase/include/fsp0fsp.h @@ -332,6 +332,7 @@ void fsp_print( /*======*/ ulint space); /* in: space id */ +#ifdef UNIV_DEBUG /*********************************************************************** Validates a segment. */ @@ -349,6 +350,7 @@ fseg_print( /*=======*/ fseg_header_t* header, /* in: segment header */ mtr_t* mtr); /* in: mtr */ +#endif /* UNIV_DEBUG */ /* Flags for fsp_reserve_free_extents */ #define FSP_NORMAL 1000000 diff --git a/innobase/include/fut0lst.h b/innobase/include/fut0lst.h index 5427e2248da..3f679d61ab5 100644 --- a/innobase/include/fut0lst.h +++ b/innobase/include/fut0lst.h @@ -181,6 +181,7 @@ flst_validate( /* out: TRUE if ok */ flst_base_node_t* base, /* in: pointer to base node of list */ mtr_t* mtr1); /* in: mtr */ +#ifdef UNIV_DEBUG /************************************************************************ Prints info of a file-based list. */ @@ -189,7 +190,7 @@ flst_print( /*=======*/ flst_base_node_t* base, /* in: pointer to base node of list */ mtr_t* mtr); /* in: mtr */ - +#endif /* UNIV_DEBUG */ #ifndef UNIV_NONINL #include "fut0lst.ic" diff --git a/innobase/include/ha0ha.h b/innobase/include/ha0ha.h index c3fc04b47bb..bdaecfcc57a 100644 --- a/innobase/include/ha0ha.h +++ b/innobase/include/ha0ha.h @@ -127,8 +127,7 @@ Prints info of a hash table. */ void ha_print_info( /*==========*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end,/* in: buffer end */ + FILE* file, /* in: file where to print */ hash_table_t* table); /* in: hash table */ /* The hash table external chain node */ diff --git a/innobase/include/ha0ha.ic b/innobase/include/ha0ha.ic index 5369ca7f273..63cd19fafc3 100644 --- a/innobase/include/ha0ha.ic +++ b/innobase/include/ha0ha.ic @@ -131,35 +131,6 @@ ha_search_and_get_data( return(NULL); } -/***************************************************************** -Returns the next matching hash table node in chain. */ -UNIV_INLINE -ha_node_t* -ha_next( -/*====*/ - /* out: pointer to the next hash table node - in chain with the fold value, NULL if not - found */ - ha_node_t* node) /* in: hash table node */ -{ - ulint fold; - - fold = node->fold; - - node = ha_chain_get_next(node); - - while (node) { - if (node->fold == fold) { - - return(node); - } - - node = ha_chain_get_next(node); - } - - return(NULL); -} - /************************************************************* Looks for an element when we know the pointer to the data. */ UNIV_INLINE diff --git a/innobase/include/ibuf0ibuf.h b/innobase/include/ibuf0ibuf.h index 8ef67df26f8..4f38ab4f1e9 100644 --- a/innobase/include/ibuf0ibuf.h +++ b/innobase/include/ibuf0ibuf.h @@ -290,8 +290,7 @@ Prints info of ibuf. */ void ibuf_print( /*=======*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end);/* in: buffer end */ + FILE* file); /* in: file where to print */ #define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO #define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h index 103d28cd130..9ccea5ad7a4 100644 --- a/innobase/include/lock0lock.h +++ b/innobase/include/lock0lock.h @@ -19,7 +19,11 @@ Created 5/7/1996 Heikki Tuuri #include "read0types.h" #include "hash0hash.h" +#ifdef UNIV_DEBUG extern ibool lock_print_waits; +#endif /* UNIV_DEBUG */ +/* Buffer for storing information about the most recent deadlock error */ +extern FILE* lock_latest_err_file; /************************************************************************* Gets the size of a lock struct. */ @@ -453,6 +457,7 @@ lock_check_trx_id_sanity( dict_index_t* index, /* in: clustered index */ ibool has_kernel_mutex);/* in: TRUE if the caller owns the kernel mutex */ +#ifdef UNIV_DEBUG /************************************************************************* Validates the lock queue on a single record. */ @@ -462,14 +467,14 @@ lock_rec_queue_validate( /* out: TRUE if ok */ rec_t* rec, /* in: record to look at */ dict_index_t* index); /* in: index, or NULL if not known */ +#endif /* UNIV_DEBUG */ /************************************************************************* Prints info of a table lock. */ void lock_table_print( /*=============*/ - char* buf, /* in/out: buffer where to print, must be at least - 500 bytes */ + FILE* file, /* in: file where to print */ lock_t* lock); /* in: table type lock */ /************************************************************************* Prints info of a record lock. */ @@ -477,8 +482,7 @@ Prints info of a record lock. */ void lock_rec_print( /*===========*/ - char* buf, /* in/out: buffer where to print, must be at least - 500 bytes */ + FILE* file, /* in: file where to print */ lock_t* lock); /* in: record type lock */ /************************************************************************* Prints info of locks for all transactions. */ @@ -486,8 +490,8 @@ Prints info of locks for all transactions. */ void lock_print_info( /*============*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end);/* in: buffer end */ + FILE* file); /* in: file where to print */ +#ifdef UNIV_DEBUG /************************************************************************* Validates the lock queue on a table. */ @@ -512,6 +516,7 @@ ibool lock_validate(void); /*===============*/ /* out: TRUE if ok */ +#endif /* UNIV_DEBUG */ /* The lock system */ extern lock_sys_t* lock_sys; diff --git a/innobase/include/log0log.h b/innobase/include/log0log.h index 2bdc158502f..4badd2cd7b3 100644 --- a/innobase/include/log0log.h +++ b/innobase/include/log0log.h @@ -366,7 +366,6 @@ Writes a buffer to a log file group. */ void log_group_write_buf( /*================*/ - ulint type, /* in: LOG_FLUSH or LOG_RECOVER */ log_group_t* group, /* in: log group */ byte* buf, /* in: buffer */ ulint len, /* in: buffer len; must be divisible @@ -513,8 +512,7 @@ Prints info of the log. */ void log_print( /*======*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end);/* in: buffer end */ + FILE* file); /* in: file where to print */ /********************************************************** Peeks the current lsn. */ diff --git a/innobase/include/mem0dbg.h b/innobase/include/mem0dbg.h index 6c92d669be3..61c66cc218c 100644 --- a/innobase/include/mem0dbg.h +++ b/innobase/include/mem0dbg.h @@ -31,6 +31,7 @@ check fields at the both ends of the field. */ #define MEM_SPACE_NEEDED(N) ut_calc_align((N), UNIV_MEM_ALIGNMENT) #endif +#ifdef UNIV_DEBUG /******************************************************************* Checks a memory heap for consistency and prints the contents if requested. Outputs the sum of sizes of buffers given to the user (only in @@ -60,6 +61,7 @@ mem_heap_validate_or_print( ulint* n_blocks); /* out: number of blocks in the heap, if a NULL pointer is passed as this argument, it is ignored */ +#endif /* UNIV_DEBUG */ #ifdef UNIV_MEM_DEBUG /****************************************************************** Prints the contents of a memory heap. */ @@ -69,6 +71,7 @@ mem_heap_print( /*===========*/ mem_heap_t* heap); /* in: memory heap */ #endif /* UNIV_MEM_DEBUG */ +#ifdef UNIV_DEBUG /****************************************************************** Checks that an object is a memory heap (or a block of it) */ @@ -85,6 +88,7 @@ mem_heap_validate( /*==============*/ /* out: TRUE if ok */ mem_heap_t* heap); /* in: memory heap */ +#endif /* UNIV_DEBUG */ #ifdef UNIV_MEM_DEBUG /********************************************************************* TRUE if no memory is currently allocated. */ diff --git a/innobase/include/mem0dbg.ic b/innobase/include/mem0dbg.ic index 6efac719760..2e79c814529 100644 --- a/innobase/include/mem0dbg.ic +++ b/innobase/include/mem0dbg.ic @@ -56,6 +56,7 @@ mem_hash_insert( mem_heap_t* heap, /* in: the created heap */ char* file_name, /* in: file name of creation */ ulint line); /* in: line where created */ +#ifdef UNIV_MEM_DEBUG /******************************************************************* Removes a memory heap (which is going to be freed by the caller) from the list of live memory heaps. Returns the size of the heap @@ -71,7 +72,7 @@ mem_hash_remove( mem_heap_t* heap, /* in: the heap to be freed */ char* file_name, /* in: file name of freeing */ ulint line); /* in: line where freed */ - +#endif /* UNIV_MEM_DEBUG */ void mem_field_header_set_len(byte* field, ulint len); diff --git a/innobase/include/mem0mem.h b/innobase/include/mem0mem.h index 9ab3b2cd754..89e2a337c99 100644 --- a/innobase/include/mem0mem.h +++ b/innobase/include/mem0mem.h @@ -271,6 +271,59 @@ mem_realloc( ulint n, /* in: desired number of bytes */ char* file_name,/* in: file name where called */ ulint line); /* in: line where called */ + +/************************************************************************** +Duplicates a NUL-terminated string. */ +UNIV_INLINE +char* +mem_strdup( +/*=======*/ + /* out, own: a copy of the string, + must be deallocated with mem_free */ + const char* str); /* in: string to be copied */ +/************************************************************************** +Makes a NUL-terminated copy of a nonterminated string. */ +UNIV_INLINE +char* +mem_strdupl( +/*========*/ + /* out, own: a copy of the string, + must be deallocated with mem_free */ + const char* str, /* in: string to be copied */ + ulint len); /* in: length of str, in bytes */ + +/************************************************************************** +Makes a NUL-terminated quoted copy of a NUL-terminated string. */ +UNIV_INLINE +char* +mem_strdupq( +/*========*/ + /* out, own: a quoted copy of the string, + must be deallocated with mem_free */ + const char* str, /* in: string to be copied */ + char q); /* in: quote character */ + +/************************************************************************** +Duplicates a NUL-terminated string, allocated from a memory heap. */ +UNIV_INLINE +char* +mem_heap_strdup( +/*============*/ + /* out, own: a copy of the string */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* str); /* in: string to be copied */ +/************************************************************************** +Makes a NUL-terminated copy of a nonterminated string, +allocated from a memory heap. */ +UNIV_INLINE +char* +mem_heap_strdupl( +/*=============*/ + /* out, own: a copy of the string */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* str, /* in: string to be copied */ + ulint len); /* in: length of str, in bytes */ + #ifdef MEM_PERIODIC_CHECK /********************************************************************** Goes through the list of all allocated mem blocks, checks their magic diff --git a/innobase/include/mem0mem.ic b/innobase/include/mem0mem.ic index fb4cef49ec9..c250e6948ec 100644 --- a/innobase/include/mem0mem.ic +++ b/innobase/include/mem0mem.ic @@ -579,3 +579,99 @@ mem_realloc( return(mem_alloc_func(n, file_name, line)); } + +/************************************************************************** +Duplicates a NUL-terminated string. */ +UNIV_INLINE +char* +mem_strdup( +/*=======*/ + /* out, own: a copy of the string, + must be deallocated with mem_free */ + const char* str) /* in: string to be copied */ +{ + ulint len = strlen(str) + 1; + return(memcpy(mem_alloc(len), str, len)); +} + +/************************************************************************** +Makes a NUL-terminated copy of a nonterminated string. */ +UNIV_INLINE +char* +mem_strdupl( +/*========*/ + /* out, own: a copy of the string, + must be deallocated with mem_free */ + const char* str, /* in: string to be copied */ + ulint len) /* in: length of str, in bytes */ +{ + char* s = mem_alloc(len + 1); + s[len] = 0; + return(memcpy(s, str, len)); +} + +/************************************************************************** +Makes a NUL-terminated quoted copy of a NUL-terminated string. */ +UNIV_INLINE +char* +mem_strdupq( +/*========*/ + /* out, own: a quoted copy of the string, + must be deallocated with mem_free */ + const char* str, /* in: string to be copied */ + char q) /* in: quote character */ +{ + char* dst; + char* d; + const char* s = str; + int len = strlen(str) + 3; + /* calculate the number of quote characters in the string */ + while((s = strchr(s, q)) != NULL) { + s++; + len++; + } + /* allocate the quoted string, and copy it */ + d = dst = mem_alloc(len); + *d++ = q; + s = str; + while(*s) { + if ((*d++ = *s++) == q) { + *d++ = q; + } + } + *d++ = q; + *d++ = '\0'; + ut_ad(len == d - dst); + return(dst); +} + +/************************************************************************** +Duplicates a NUL-terminated string, allocated from a memory heap. */ +UNIV_INLINE +char* +mem_heap_strdup( +/*============*/ + /* out, own: a copy of the string */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* str) /* in: string to be copied */ +{ + ulint len = strlen(str) + 1; + return(memcpy(mem_heap_alloc(heap, len), str, len)); +} + +/************************************************************************** +Makes a NUL-terminated copy of a nonterminated string, +allocated from a memory heap. */ +UNIV_INLINE +char* +mem_heap_strdupl( +/*=============*/ + /* out, own: a copy of the string */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* str, /* in: string to be copied */ + ulint len) /* in: length of str, in bytes */ +{ + char* s = mem_heap_alloc(heap, len + 1); + s[len] = 0; + return(memcpy(s, str, len)); +} diff --git a/innobase/include/mem0pool.h b/innobase/include/mem0pool.h index 51c53afe788..08327d95d37 100644 --- a/innobase/include/mem0pool.h +++ b/innobase/include/mem0pool.h @@ -85,6 +85,7 @@ Releases the mem pool mutex. */ void mem_pool_mutex_exit(void); /*=====================*/ +#ifdef UNIV_DEBUG /************************************************************************ Validates a memory pool. */ @@ -101,7 +102,7 @@ mem_pool_print_info( /*================*/ FILE* outfile,/* in: output file to write to */ mem_pool_t* pool); /* in: memory pool */ - +#endif /* UNIV_DEBUG */ #ifndef UNIV_NONINL #include "mem0pool.ic" diff --git a/innobase/include/mtr0log.ic b/innobase/include/mtr0log.ic index 60a5b390be9..c02e0a96a81 100644 --- a/innobase/include/mtr0log.ic +++ b/innobase/include/mtr0log.ic @@ -171,7 +171,8 @@ mlog_write_initial_log_record_fast( mtr->n_log_recs++; #ifdef UNIV_LOG_DEBUG -/* printf("Adding to mtr log record type %lu space %lu page no %lu\n", +/* fprintf(stderr, + "Adding to mtr log record type %lu space %lu page no %lu\n", type, space, offset); */ #endif diff --git a/innobase/include/mtr0mtr.h b/innobase/include/mtr0mtr.h index 9cf592f71e1..73338977b9c 100644 --- a/innobase/include/mtr0mtr.h +++ b/innobase/include/mtr0mtr.h @@ -256,6 +256,7 @@ mtr_memo_contains( mtr_t* mtr, /* in: mtr */ void* object, /* in: object to search */ ulint type); /* in: type of object */ +#ifdef UNIV_DEBUG /************************************************************* Prints info of an mtr handle. */ @@ -263,6 +264,7 @@ void mtr_print( /*======*/ mtr_t* mtr); /* in: mtr */ +#endif /* UNIV_DEBUG */ /*######################################################################*/ #define MTR_BUF_MEMO_SIZE 200 /* number of slots in memo */ diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index 813e6e72e65..263142db74f 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -647,8 +647,7 @@ Prints info of the aio arrays. */ void os_aio_print( /*=========*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end);/* in: buffer end */ + FILE* file); /* in: file where to print */ /************************************************************************** Refreshes the statistics used to print per-second averages. */ diff --git a/innobase/include/pars0opt.h b/innobase/include/pars0opt.h index d091c3ee2d0..ac0e885d05a 100644 --- a/innobase/include/pars0opt.h +++ b/innobase/include/pars0opt.h @@ -43,6 +43,7 @@ opt_find_all_cols( to add new found columns */ plan_t* plan, /* in: plan or NULL */ que_node_t* exp); /* in: expression or condition */ +#ifdef UNIV_SQL_DEBUG /************************************************************************ Prints info of a query plan. */ @@ -50,6 +51,7 @@ void opt_print_query_plan( /*=================*/ sel_node_t* sel_node); /* in: select node */ +#endif /* UNIV_SQL_DEBUG */ #ifndef UNIV_NONINL #include "pars0opt.ic" diff --git a/innobase/include/pars0pars.h b/innobase/include/pars0pars.h index 8ff226ebbd0..2e86a7e5534 100644 --- a/innobase/include/pars0pars.h +++ b/innobase/include/pars0pars.h @@ -87,13 +87,6 @@ pars_get_lex_chars( int max_size); /* in: maximum number of characters which fit in the buffer */ /***************************************************************** -Instructs the lexical analyzer to stop when it receives the EOF integer. */ - -int -yywrap(void); -/*========*/ - /* out: returns TRUE */ -/***************************************************************** Called by yyparse on error. */ void @@ -456,18 +449,6 @@ struct proc_node_struct{ sym_node_t* param_list; /* input and output parameters */ que_node_t* stat_list; /* statement list */ sym_tab_t* sym_tab; /* symbol table of this procedure */ - dict_proc_t* dict_proc; /* stored procedure node in the - dictionary cache, if defined */ -}; - -/* Stored procedure call node */ -struct call_node_struct{ - que_common_t common; /* type: QUE_NODE_CALL */ - sym_node_t* proc_name; /* stored procedure name */ - dict_proc_t* procedure_def; /* pointer to a stored procedure graph - in the dictionary stored procedure - cache */ - sym_tab_t* sym_tab; /* symbol table of this query */ }; /* elsif-element node */ diff --git a/innobase/include/pars0sym.h b/innobase/include/pars0sym.h index 9fdeb1984a9..3060fd06c8f 100644 --- a/innobase/include/pars0sym.h +++ b/innobase/include/pars0sym.h @@ -127,9 +127,6 @@ struct sym_node_struct{ dict_table_t* table; /* table definition if a table id or a column id */ - dict_proc_t* procedure_def; /* stored procedure - definition, if a - stored procedure name */ ulint col_no; /* column number if a column */ sel_buf_t* prefetch_buf; /* NULL, or a buffer diff --git a/innobase/include/pars0types.h b/innobase/include/pars0types.h index e7471260501..9fbfd6efaa1 100644 --- a/innobase/include/pars0types.h +++ b/innobase/include/pars0types.h @@ -15,7 +15,6 @@ typedef struct pars_res_word_struct pars_res_word_t; typedef struct func_node_struct func_node_t; typedef struct order_node_struct order_node_t; typedef struct proc_node_struct proc_node_t; -typedef struct call_node_struct call_node_t; typedef struct elsif_node_struct elsif_node_t; typedef struct if_node_struct if_node_t; typedef struct while_node_struct while_node_t; diff --git a/innobase/include/rem0rec.h b/innobase/include/rem0rec.h index ebdd3c1ac81..86bf263170f 100644 --- a/innobase/include/rem0rec.h +++ b/innobase/include/rem0rec.h @@ -390,16 +390,7 @@ Prints a physical record. */ void rec_print( /*======*/ - rec_t* rec); /* in: physical record */ -/******************************************************************* -Prints a physical record to a buffer. */ - -ulint -rec_sprintf( -/*========*/ - /* out: printed length in bytes */ - char* buf, /* in: buffer to print to */ - ulint buf_len,/* in: buffer length */ + FILE* file, /* in: file where to print */ rec_t* rec); /* in: physical record */ #define REC_INFO_BITS 6 /* This is single byte bit-field */ diff --git a/innobase/include/rem0rec.ic b/innobase/include/rem0rec.ic index f4acd8547db..c36bf8f6d6e 100644 --- a/innobase/include/rem0rec.ic +++ b/innobase/include/rem0rec.ic @@ -190,7 +190,7 @@ rec_set_bit_field_2( + (REC_N_OWNED_MASK << (8 * (REC_N_OWNED - 3))) + (REC_INFO_BITS_MASK << (8 * (REC_INFO_BITS - 3)))); if (m != ut_dbg_zero + 0xFFFFFFFFUL) { - printf("Sum of masks %lx\n", m); + fprintf(stderr, "Sum of masks %lx\n", m); ut_error; } } diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 32a0c8b5d75..0fb2994a414 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -337,7 +337,9 @@ row_drop_table_for_mysql( /*=====================*/ /* out: error code or DB_SUCCESS */ char* name, /* in: table name */ - trx_t* trx); /* in: transaction handle */ + trx_t* trx, /* in: transaction handle */ + ibool drop_db);/* in: TRUE=dropping whole database */ + /************************************************************************* Discards the tablespace of a table which stored in an .ibd file. Discarding means that this function deletes the .ibd file and assigns a new table id for diff --git a/innobase/include/row0sel.ic b/innobase/include/row0sel.ic index 994638790c0..595cea1138b 100644 --- a/innobase/include/row0sel.ic +++ b/innobase/include/row0sel.ic @@ -77,12 +77,9 @@ open_step( if (err != DB_SUCCESS) { /* SQL error detected */ - printf("SQL error %lu\n", (unsigned long) err); + fprintf(stderr, "SQL error %lu\n", (ulong) err); ut_error; - que_thr_handle_error(thr, err, NULL, 0); - - return(NULL); } thr->run_node = que_node_get_parent(node); diff --git a/innobase/include/row0uins.h b/innobase/include/row0uins.h index df5e072487e..fc57881f691 100644 --- a/innobase/include/row0uins.h +++ b/innobase/include/row0uins.h @@ -26,8 +26,7 @@ ulint row_undo_ins( /*=========*/ /* out: DB_SUCCESS */ - undo_node_t* node, /* in: row undo node */ - que_thr_t* thr); /* in: query thread */ + undo_node_t* node); /* in: row undo node */ #ifndef UNIV_NONINL diff --git a/innobase/include/row0undo.h b/innobase/include/row0undo.h index 5402f1d9236..d64a00dcb8f 100644 --- a/innobase/include/row0undo.h +++ b/innobase/include/row0undo.h @@ -41,8 +41,7 @@ row_undo_search_clust_to_pcur( /* out: TRUE if found; NOTE the node->pcur must be closed by the caller, regardless of the return value */ - undo_node_t* node, /* in: row undo node */ - que_thr_t* thr); /* in: query thread */ + undo_node_t* node); /* in: row undo node */ /*************************************************************** Undoes a row operation in a table. This is a high-level function used in SQL execution graphs. */ diff --git a/innobase/include/row0upd.ic b/innobase/include/row0upd.ic index 6b9deeac5e3..d89938d696a 100644 --- a/innobase/include/row0upd.ic +++ b/innobase/include/row0upd.ic @@ -84,10 +84,12 @@ upd_field_set_field_no( if (field_no >= dict_index_get_n_fields(index)) { fprintf(stderr, - "InnoDB: Error: trying to access field %lu in table %s\n" - "InnoDB: index %s, but index has only %lu fields\n", - (unsigned long) field_no, index->table_name, index->name, - (unsigned long) dict_index_get_n_fields(index)); + "InnoDB: Error: trying to access field %lu in ", + (ulong) field_no); + dict_index_name_print(stderr, index); + fprintf(stderr, "\n" + "InnoDB: but index only has %lu fields\n", + (ulong) dict_index_get_n_fields(index)); } dtype_copy(dfield_get_type(&(upd_field->new_val)), diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 8aac71de2a9..7f067c75466 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -32,6 +32,11 @@ at a time */ /* This is set to TRUE if the MySQL user has set it in MySQL */ extern ibool srv_lower_case_table_names; +/* Mutex for locking srv_monitor_file */ +extern mutex_t srv_monitor_file_mutex; +/* Temporary file for innodb monitor output */ +extern FILE* srv_monitor_file; + /* Server parameters which are read from the initfile */ extern char* srv_data_home; @@ -162,8 +167,8 @@ extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, /* Array of English strings describing the current state of an i/o handler thread */ -extern char* srv_io_thread_op_info[]; -extern char* srv_io_thread_function[]; +extern const char* srv_io_thread_op_info[]; +extern const char* srv_io_thread_function[]; typedef struct srv_sys_struct srv_sys_t; @@ -241,6 +246,15 @@ srv_get_thread_type(void); /*=====================*/ /* out: SRV_COM, ... */ /************************************************************************* +Sets the info describing an i/o thread current state. */ + +void +srv_set_io_thread_op_info( +/*======================*/ + ulint i, /* in: the 'segment' of the i/o thread */ + const char* str); /* in: constant char string describing the + state */ +/************************************************************************* Releases threads of the type given from suspension in the thread table. NOTE! The server mutex has to be reserved by the caller! */ @@ -366,13 +380,12 @@ srv_error_monitor_thread( void* arg); /* in: a dummy parameter required by os_thread_create */ /********************************************************************** -Sprintfs to a buffer the output of the InnoDB Monitor. */ +Outputs to a file the output of the InnoDB Monitor. */ void -srv_sprintf_innodb_monitor( -/*=======================*/ - char* buf, /* in/out: buffer which must be at least 4 kB */ - ulint len); /* in: length of the buffer */ +srv_printf_innodb_monitor( +/*======================*/ + FILE* file); /* in: output stream */ /* Types for the threads existing in the system. Threads of types 4 - 9 diff --git a/innobase/include/sync0arr.h b/innobase/include/sync0arr.h index 765ad33afea..383d0c69fb2 100644 --- a/innobase/include/sync0arr.h +++ b/innobase/include/sync0arr.h @@ -114,8 +114,7 @@ Prints info of the wait array. */ void sync_array_print_info( /*==================*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end,/* in: buffer end */ + FILE* file, /* in: file where to print */ sync_array_t* arr); /* in: wait array */ diff --git a/innobase/include/sync0rw.h b/innobase/include/sync0rw.h index d71691b4353..82123a529a3 100644 --- a/innobase/include/sync0rw.h +++ b/innobase/include/sync0rw.h @@ -85,6 +85,7 @@ void rw_lock_free( /*=========*/ rw_lock_t* lock); /* in: rw-lock */ +#ifdef UNIV_DEBUG /********************************************************************** Checks that the rw-lock has been initialized and that there are no simultaneous shared and exclusive locks. */ @@ -93,6 +94,7 @@ ibool rw_lock_validate( /*=============*/ rw_lock_t* lock); +#endif /* UNIV_DEBUG */ /****************************************************************** NOTE! The following macros should be used in rw s-locking, not the corresponding function. */ diff --git a/innobase/include/sync0sync.h b/innobase/include/sync0sync.h index 3a7203bbb56..332c08fd38a 100644 --- a/innobase/include/sync0sync.h +++ b/innobase/include/sync0sync.h @@ -65,6 +65,15 @@ NOTE! The following macro should be used in mutex locking, not the corresponding function. */ #define mutex_enter(M) mutex_enter_func((M), IB__FILE__, __LINE__) +/********************************************************************** +A noninlined function that reserves a mutex. In ha_innodb.cc we have disabled +inlining of InnoDB functions, and no inlined functions should be called from +there. That is why we need to duplicate the inlined function here. */ + +void +mutex_enter_noninline( +/*==================*/ + mutex_t* mutex); /* in: mutex */ /****************************************************************** NOTE! The following macro should be used in mutex locking, not the corresponding function. */ @@ -105,6 +114,13 @@ mutex_exit( /*=======*/ mutex_t* mutex); /* in: pointer to mutex */ /********************************************************************** +Releases a mutex. */ + +void +mutex_exit_noninline( +/*=================*/ + mutex_t* mutex); /* in: mutex */ +/********************************************************************** Returns TRUE if no mutex or rw-lock is currently locked. Works only in the debug version. */ @@ -119,16 +135,15 @@ Prints wait info of the sync system. */ void sync_print_wait_info( /*=================*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end); /* in: buffer end */ + FILE* file); /* in: file where to print */ /*********************************************************************** Prints info of the sync system. */ void sync_print( /*=======*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end); /* in: buffer end */ + FILE* file); /* in: file where to print */ +#ifdef UNIV_DEBUG /********************************************************************** Checks that the mutex has been initialized. */ @@ -136,6 +151,7 @@ ibool mutex_validate( /*===========*/ mutex_t* mutex); +#endif /* UNIV_DEBUG */ /********************************************************************** Sets the mutex latching level field. */ diff --git a/innobase/include/trx0sys.h b/innobase/include/trx0sys.h index 0005c4a1711..9987955ec76 100644 --- a/innobase/include/trx0sys.h +++ b/innobase/include/trx0sys.h @@ -270,8 +270,9 @@ the magic number shows it valid. */ void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ +#ifdef UNIV_HOTBACKUP /********************************************************************* -Prints to stdout the MySQL binlog info in the system header if the +Prints to stderr the MySQL binlog info in the system header if the magic number shows it valid. */ void @@ -279,6 +280,7 @@ trx_sys_print_mysql_binlog_offset_from_page( /*========================================*/ byte* page); /* in: buffer containing the trx system header page, i.e., page number TRX_SYS_PAGE_NO in the tablespace */ +#endif /* UNIV_HOTBACKUP */ /********************************************************************* Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index d9b91ee62dc..bb2d7e8f64d 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -280,8 +280,7 @@ own the kernel mutex. */ void trx_print( /*======*/ - char* buf, /* in/out: buffer where to print, must be at least - 800 bytes */ + FILE* f, /* in: output stream */ trx_t* trx); /* in: transaction */ diff --git a/innobase/include/ut0byte.h b/innobase/include/ut0byte.h index 4274956421e..fed6a23d144 100644 --- a/innobase/include/ut0byte.h +++ b/innobase/include/ut0byte.h @@ -235,21 +235,19 @@ Copies a string to a memory location, setting characters to lower case. */ void ut_cpy_in_lower_case( /*=================*/ - char* dest, /* in: destination */ - char* source, /* in: source */ - ulint len); /* in: string length */ + char* dest, /* in: destination */ + const char* source, /* in: source */ + ulint len); /* in: string length */ /**************************************************************** Compares two strings when converted to lower case. */ int ut_cmp_in_lower_case( /*=================*/ - /* out: -1, 0, 1 if str1 < str2, str1 == str2, - str1 > str2, respectively */ - char* str1, /* in: string1 */ - char* str2, /* in: string2 */ - ulint len); /* in: length of both strings */ - + /* out: -1, 0, 1 if str1 < str2, str1 == str2, + str1 > str2, respectively */ + const char* str1, /* in: string1 */ + const char* str2); /* in: string2 */ #ifndef UNIV_NONINL #include "ut0byte.ic" diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h index b7dfe77a08e..b208fac8691 100644 --- a/innobase/include/ut0mem.h +++ b/innobase/include/ut0mem.h @@ -86,6 +86,39 @@ int ut_strcmp(void* str1, void* str2); /************************************************************************** +Determine the length of a string when it is quoted with ut_strcpyq(). */ +UNIV_INLINE +ulint +ut_strlenq( +/*=======*/ + /* out: length of the string when quoted */ + const char* str, /* in: null-terminated string */ + char q); /* in: the quote character */ + +/************************************************************************** +Make a quoted copy of a string. */ + +char* +ut_strcpyq( +/*=======*/ + /* out: pointer to end of dest */ + char* dest, /* in: output buffer */ + char q, /* in: the quote character */ + const char* src); /* in: null-terminated string */ + +/************************************************************************** +Make a quoted copy of a fixed-length string. */ + +char* +ut_memcpyq( +/*=======*/ + /* out: pointer to end of dest */ + char* dest, /* in: output buffer */ + char q, /* in: the quote character */ + const char* src, /* in: string to be quoted */ + ulint len); /* in: length of src */ + +/************************************************************************** Catenates two strings into newly allocated memory. The memory must be freed using mem_free. */ @@ -95,6 +128,7 @@ ut_str_catenate( /* out, own: catenated null-terminated string */ char* str1, /* in: null-terminated string */ char* str2); /* in: null-terminated string */ + /************************************************************************** Return a copy of the given string. The returned string must be freed using mem_free. */ @@ -104,14 +138,6 @@ ut_strdup( /*======*/ /* out, own: cnull-terminated string */ char* str); /* in: null-terminated string */ -/************************************************************************** -Checks if a null-terminated string contains a certain character. */ - -ibool -ut_str_contains( -/*============*/ - char* str, /* in: null-terminated string */ - char c); /* in: character */ #ifndef UNIV_NONINL #include "ut0mem.ic" diff --git a/innobase/include/ut0mem.ic b/innobase/include/ut0mem.ic index 1049aee8ecc..951d9538424 100644 --- a/innobase/include/ut0mem.ic +++ b/innobase/include/ut0mem.ic @@ -48,3 +48,23 @@ ut_strcmp(void* str1, void* str2) return(strcmp((char*)str1, (char*)str2)); } +/************************************************************************** +Determine the length of a string when it is quoted with ut_strcpyq(). */ +UNIV_INLINE +ulint +ut_strlenq( +/*=======*/ + /* out: length of the string when quoted */ + const char* str, /* in: null-terminated string */ + char q) /* in: the quote character */ +{ + ulint len; + + for (len = 0; *str; len++, str++) { + if (*str == q) { + len++; + } + } + + return(len); +} diff --git a/innobase/include/ut0ut.h b/innobase/include/ut0ut.h index 4517b8f8d40..6c173f5cba9 100644 --- a/innobase/include/ut0ut.h +++ b/innobase/include/ut0ut.h @@ -61,7 +61,9 @@ ut_fprintf( negative in case of an error */ FILE* stream, /* in: stream where to print */ const char* format, /* in: format of prints */ - ...); /* in: arguments to be printed */ + ...) /* in: arguments to be printed */ + __attribute__((__format__ (__printf__, 2, 3))); + /************************************************************ Gets the high 32 bits in a ulint. That is makes a shift >> 32, but since there seem to be compiler bugs in both gcc and Visual C++, @@ -200,7 +202,7 @@ ut_print_timestamp( /*===============*/ FILE* file); /* in: file where to print */ /************************************************************** -Sprintfs a timestamp to a buffer. */ +Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */ void ut_sprintf_timestamp( @@ -238,19 +240,37 @@ Prints the contents of a memory buffer in hex and ascii. */ void ut_print_buf( /*=========*/ - byte* buf, /* in: memory buffer */ - ulint len); /* in: length of the buffer */ -/***************************************************************** -Prints the contents of a memory buffer in hex and ascii. */ + FILE* file, /* in: file where to print */ + const byte* buf, /* in: memory buffer */ + ulint len); /* in: length of the buffer */ -ulint -ut_sprintf_buf( -/*===========*/ - /* out: printed length in bytes */ - char* str, /* in: buffer to print to */ - byte* buf, /* in: memory buffer */ - ulint len); /* in: length of the buffer */ +/************************************************************************** +Outputs a NUL-terminated string, quoted as an SQL identifier. */ + +void +ut_print_name( +/*==========*/ + FILE* f, /* in: output stream */ + const char* name); /* in: name to print */ +/************************************************************************** +Outputs a fixed-length string, quoted as an SQL identifier. */ + +void +ut_print_namel( +/*==========*/ + FILE* f, /* in: output stream */ + const char* name, /* in: name to print */ + ulint namelen);/* in: length of name */ + +/************************************************************************** +Catenate files. */ + +void +ut_copy_file( +/*=========*/ + FILE* dest, /* in: output file */ + FILE* src); /* in: input file to be appended to output */ #ifndef UNIV_NONINL #include "ut0ut.ic" diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 2430380d65c..f12389cb6b2 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -266,7 +266,9 @@ waiting, in its lock queue. Solution: We can copy the locks as gap type locks, so that also the waiting locks are transformed to granted gap type locks on the inserted record. */ +#ifdef UNIV_DEBUG ibool lock_print_waits = FALSE; +#endif /* UNIV_DEBUG */ /* The lock system */ lock_sys_t* lock_sys = NULL; @@ -310,7 +312,7 @@ struct lock_struct{ /* We store info on the latest deadlock error to this buffer. InnoDB Monitor will then fetch it and print */ ibool lock_deadlock_found = FALSE; -char* lock_latest_err_buf; /* We allocate 5000 bytes for this */ +FILE* lock_latest_err_file; /* Flags for recursive deadlock search */ #define LOCK_VICTIM_IS_START 1 @@ -356,7 +358,6 @@ lock_check_trx_id_sanity( ibool has_kernel_mutex)/* in: TRUE if the caller owns the kernel mutex */ { - char err_buf[500]; ibool is_ok = TRUE; if (!has_kernel_mutex) { @@ -367,14 +368,16 @@ lock_check_trx_id_sanity( trx id counter */ if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) { - rec_sprintf(err_buf, 400, rec); ut_print_timestamp(stderr); - fprintf(stderr, -"InnoDB: Error: transaction id associated with record\n%s\n" -"InnoDB: in table %s index %s\n" + fputs(" InnoDB: Error: transaction id associated" + " with record\n", + stderr); + rec_print(stderr, rec); + fputs("InnoDB: in ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, "\n" "InnoDB: is %lu %lu which is higher than the global trx id counter %lu %lu!\n" "InnoDB: The table is corrupt. You have to do dump + drop + reimport.\n", - err_buf, index->table_name, index->name, (ulong) ut_dulint_get_high(trx_id), (ulong) ut_dulint_get_low(trx_id), (ulong) ut_dulint_get_high(trx_sys->max_trx_id), @@ -481,7 +484,7 @@ lock_sys_create( /* hash_create_mutexes(lock_sys->rec_hash, 2, SYNC_REC_LOCK); */ - lock_latest_err_buf = mem_alloc(5000); + lock_latest_err_file = tmpfile(); } /************************************************************************* @@ -1325,7 +1328,8 @@ lock_rec_has_expl( return(NULL); } - + +#ifdef UNIV_DEBUG /************************************************************************* Checks if some other transaction has a lock request in the queue. */ static @@ -1368,6 +1372,7 @@ lock_rec_other_has_expl_req( return(NULL); } +#endif /* UNIV_DEBUG */ /************************************************************************* Checks if some other transaction has a conflicting explicit lock request @@ -1620,11 +1625,12 @@ lock_rec_enqueue_waiting( if (trx->dict_operation) { ut_print_timestamp(stderr); - - fprintf(stderr, + fputs( " InnoDB: Error: a record lock wait happens in a dictionary operation!\n" -"InnoDB: Table name %s. Send a bug report to mysql@lists.mysql.com\n", -index->table_name); +"InnoDB: Table name ", stderr); + ut_print_name(stderr, index->table_name); + fputs(". Send a bug report to mysql@lists.mysql.com\n", + stderr); } /* Enqueue the lock request that will wait to be granted */ @@ -1655,11 +1661,13 @@ index->table_name); ut_a(que_thr_stop(thr)); +#ifdef UNIV_DEBUG if (lock_print_waits) { - printf("Lock wait for trx %lu in index %s\n", - (ulong) ut_dulint_get_low(trx->id), - index->name); + fprintf(stderr, "Lock wait for trx %lu in index ", + (ulong) ut_dulint_get_low(trx->id)); + ut_print_name(stderr, index->name); } +#endif /* UNIV_DEBUG */ return(DB_LOCK_WAIT); } @@ -1995,10 +2003,12 @@ lock_grant( lock->trx->auto_inc_lock = lock; } +#ifdef UNIV_DEBUG if (lock_print_waits) { - printf("Lock wait for trx %lu ends\n", + fprintf(stderr, "Lock wait for trx %lu ends\n", (ulong) ut_dulint_get_low(lock->trx->id)); } +#endif /* UNIV_DEBUG */ /* If we are resolving a deadlock by choosing another transaction as a victim, then our original transaction may not be in the @@ -2386,7 +2396,7 @@ lock_move_reorganize_page( /* if ((page_cur_get_rec(&cur1) == sup) && lock_get_wait(lock)) { - printf( + fprintf(stderr, "---\n--\n!!!Lock reorg: supr type %lu\n", lock->type_mode); } */ @@ -2902,7 +2912,6 @@ lock_deadlock_occurs( trx_t* mark_trx; ulint ret; ulint cost = 0; - char* err_buf; ut_ad(trx && lock); #ifdef UNIV_SYNC_DEBUG @@ -2940,14 +2949,8 @@ retry: lock_deadlock_found = TRUE; - err_buf = lock_latest_err_buf + strlen(lock_latest_err_buf); - - ut_a(err_buf <= lock_latest_err_buf + 4000); - - err_buf += sprintf(err_buf, - "*** WE ROLL BACK TRANSACTION (2)\n"); - - ut_a(strlen(lock_latest_err_buf) < 4100); + fputs("*** WE ROLL BACK TRANSACTION (2)\n", + lock_latest_err_file); return(TRUE); } @@ -2979,7 +2982,6 @@ lock_deadlock_recursive( lock_t* lock; ulint bit_no = ULINT_UNDEFINED; trx_t* lock_trx; - char* err_buf; ulint ret; ut_a(trx && start && wait_lock); @@ -3037,72 +3039,51 @@ lock_deadlock_recursive( if (lock_trx == start) { /* We came back to the recursion starting point: a deadlock detected */ + FILE* ef = lock_latest_err_file; - err_buf = lock_latest_err_buf; - - ut_sprintf_timestamp(err_buf); - err_buf += strlen(err_buf); + rewind(ef); + ut_print_timestamp(ef); - err_buf += sprintf(err_buf, - "\n*** (1) TRANSACTION:\n"); + fputs("\n*** (1) TRANSACTION:\n", ef); - trx_print(err_buf, wait_lock->trx); - err_buf += strlen(err_buf); + trx_print(ef, wait_lock->trx); - err_buf += sprintf(err_buf, - "*** (1) WAITING FOR THIS LOCK TO BE GRANTED:\n"); - - ut_a(err_buf <= lock_latest_err_buf + 4000); + fputs( + "*** (1) WAITING FOR THIS LOCK TO BE GRANTED:\n", ef); if (lock_get_type(wait_lock) == LOCK_REC) { - lock_rec_print(err_buf, wait_lock); - err_buf += strlen(err_buf); + lock_rec_print(ef, wait_lock); } else { - lock_table_print(err_buf, wait_lock); - err_buf += strlen(err_buf); + lock_table_print(ef, wait_lock); } - ut_a(err_buf <= lock_latest_err_buf + 4000); - err_buf += sprintf(err_buf, - "*** (2) TRANSACTION:\n"); - - trx_print(err_buf, lock->trx); - err_buf += strlen(err_buf); + fputs("*** (2) TRANSACTION:\n", ef); - err_buf += sprintf(err_buf, - "*** (2) HOLDS THE LOCK(S):\n"); + trx_print(ef, lock->trx); - ut_a(err_buf <= lock_latest_err_buf + 4000); + fputs("*** (2) HOLDS THE LOCK(S):\n", ef); if (lock_get_type(lock) == LOCK_REC) { - lock_rec_print(err_buf, lock); - err_buf += strlen(err_buf); + lock_rec_print(ef, lock); } else { - lock_table_print(err_buf, lock); - err_buf += strlen(err_buf); + lock_table_print(ef, lock); } - ut_a(err_buf <= lock_latest_err_buf + 4000); - - err_buf += sprintf(err_buf, - "*** (2) WAITING FOR THIS LOCK TO BE GRANTED:\n"); - - ut_a(err_buf <= lock_latest_err_buf + 4000); + fputs( + "*** (2) WAITING FOR THIS LOCK TO BE GRANTED:\n", ef); if (lock_get_type(start->wait_lock) == LOCK_REC) { - lock_rec_print(err_buf, - start->wait_lock); - err_buf += strlen(err_buf); + lock_rec_print(ef, start->wait_lock); } else { - lock_table_print(err_buf, - start->wait_lock); - err_buf += strlen(err_buf); + lock_table_print(ef, start->wait_lock); } +#ifdef UNIV_DEBUG if (lock_print_waits) { - printf("Deadlock detected\n"); + fputs("Deadlock detected\n", stderr); } +#endif /* UNIV_DEBUG */ if (ut_dulint_cmp(wait_lock->trx->undo_no, start->undo_no) >= 0) { @@ -3116,14 +3097,12 @@ lock_deadlock_recursive( lock_deadlock_found = TRUE; - ut_a(err_buf <= lock_latest_err_buf + 4000); - /* Let us choose the transaction of wait_lock as a victim to try to avoid deadlocking our recursion starting point transaction */ - err_buf += sprintf(err_buf, - "*** WE ROLL BACK TRANSACTION (1)\n"); + fputs("*** WE ROLL BACK TRANSACTION (1)\n", + ef); wait_lock->trx->was_chosen_as_deadlock_victim = TRUE; @@ -3282,11 +3261,12 @@ lock_table_enqueue_waiting( if (trx->dict_operation) { ut_print_timestamp(stderr); - - fprintf(stderr, + fputs( " InnoDB: Error: a table lock wait happens in a dictionary operation!\n" -"InnoDB: Table name %s. Send a bug report to mysql@lists.mysql.com\n", -table->name); +"InnoDB: Table name ", stderr); + ut_print_name(stderr, table->name); + fputs(". Send a bug report to mysql@lists.mysql.com\n", + stderr); } /* Enqueue the lock request that will wait to be granted */ @@ -3704,8 +3684,7 @@ Prints info of a table lock. */ void lock_table_print( /*=============*/ - char* buf, /* in/out: buffer where to print, must be at least - 500 bytes */ + FILE* file, /* in: file where to print */ lock_t* lock) /* in: table type lock */ { #ifdef UNIV_SYNC_DEBUG @@ -3713,30 +3692,30 @@ lock_table_print( #endif /* UNIV_SYNC_DEBUG */ ut_a(lock_get_type(lock) == LOCK_TABLE); - buf += sprintf(buf, "TABLE LOCK table %s trx id %lu %lu", - lock->un_member.tab_lock.table->name, + fputs("TABLE LOCK table ", file); + ut_print_name(file, lock->un_member.tab_lock.table->name); + fprintf(file, " trx id %lu %lu", (ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low); if (lock_get_mode(lock) == LOCK_S) { - buf += sprintf(buf, " lock mode S"); + fputs(" lock mode S", file); } else if (lock_get_mode(lock) == LOCK_X) { - buf += sprintf(buf, " lock_mode X"); + fputs(" lock mode X", file); } else if (lock_get_mode(lock) == LOCK_IS) { - buf += sprintf(buf, " lock_mode IS"); + fputs(" lock mode IS", file); } else if (lock_get_mode(lock) == LOCK_IX) { - buf += sprintf(buf, " lock_mode IX"); + fputs(" lock mode IX", file); } else if (lock_get_mode(lock) == LOCK_AUTO_INC) { - buf += sprintf(buf, " lock_mode AUTO-INC"); + fputs(" lock mode AUTO-INC", file); } else { - buf += sprintf(buf, - " unknown lock_mode %lu", (ulong) lock_get_mode(lock)); + fprintf(file, " unknown lock mode %lu", (ulong) lock_get_mode(lock)); } if (lock_get_wait(lock)) { - buf += sprintf(buf, " waiting"); + fputs(" waiting", file); } - buf += sprintf(buf, "\n"); + putc('\n', file); } /************************************************************************* @@ -3745,16 +3724,13 @@ Prints info of a record lock. */ void lock_rec_print( /*===========*/ - char* buf, /* in/out: buffer where to print, must be at least - 500 bytes */ + FILE* file, /* in: file where to print */ lock_t* lock) /* in: record type lock */ { page_t* page; ulint space; ulint page_no; ulint i; - ulint count = 0; - char* buf_start = buf; mtr_t mtr; #ifdef UNIV_SYNC_DEBUG @@ -3765,42 +3741,41 @@ lock_rec_print( space = lock->un_member.rec_lock.space; page_no = lock->un_member.rec_lock.page_no; - buf += sprintf(buf, "RECORD LOCKS space id %lu page no %lu n bits %lu", + fprintf(file, "RECORD LOCKS space id %lu page no %lu n bits %lu ", (ulong) space, (ulong) page_no, (ulong) lock_rec_get_n_bits(lock)); - - buf += sprintf(buf, " table %s index %s trx id %lu %lu", - lock->index->table->name, lock->index->name, + dict_index_name_print(file, lock->index); + fprintf(file, " trx id %lu %lu", (ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low); if (lock_get_mode(lock) == LOCK_S) { - buf += sprintf(buf, " lock mode S"); + fputs(" lock mode S", file); } else if (lock_get_mode(lock) == LOCK_X) { - buf += sprintf(buf, " lock_mode X"); + fputs(" lock_mode X", file); } else { ut_error; } if (lock_rec_get_gap(lock)) { - buf += sprintf(buf, " locks gap before rec"); + fputs(" locks gap before rec", file); } if (lock_rec_get_rec_not_gap(lock)) { - buf += sprintf(buf, " locks rec but not gap"); + fputs(" locks rec but not gap", file); } if (lock_rec_get_insert_intention(lock)) { - buf += sprintf(buf, " insert intention"); + fputs(" insert intention", file); } if (lock_get_wait(lock)) { - buf += sprintf(buf, " waiting"); + fputs(" waiting", file); } mtr_start(&mtr); - buf += sprintf(buf, "\n"); + putc('\n', file); /* If the page is not in the buffer pool, we cannot load it because we have the kernel mutex and ibuf operations would @@ -3830,29 +3805,16 @@ lock_rec_print( for (i = 0; i < lock_rec_get_n_bits(lock); i++) { - if (buf - buf_start > 300) { - - buf += sprintf(buf, - "Suppressing further record lock prints for this page\n"); - - mtr_commit(&mtr); - - return; - } - if (lock_rec_get_nth_bit(lock, i)) { - buf += sprintf(buf, "Record lock, heap no %lu ", - (ulong) i); + fprintf(file, "Record lock, heap no %lu ", (ulong) i); if (page) { - buf += rec_sprintf(buf, 120, + rec_print(file, page_find_rec_with_heap_no(page, i)); - *buf = '\0'; } - buf += sprintf(buf, "\n"); - count++; + putc('\n', file); } } @@ -3894,8 +3856,7 @@ Prints info of locks for all transactions. */ void lock_print_info( /*============*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end)/* in: buffer end */ + FILE* file) /* in: file where to print */ { lock_t* lock; trx_t* trx; @@ -3908,79 +3869,47 @@ lock_print_info( ulint i; mtr_t mtr; - if (buf_end - buf < 600) { - sprintf(buf, "... output truncated!\n"); - - return; - } - lock_mutex_enter_kernel(); if (lock_deadlock_found) { - - buf += sprintf(buf, + fputs( "------------------------\n" "LATEST DETECTED DEADLOCK\n" -"------------------------\n"); +"------------------------\n", file); - if ((ulint)(buf_end - buf) - < 100 + strlen(lock_latest_err_buf)) { - - lock_mutex_exit_kernel(); - sprintf(buf, "... output truncated!\n"); - - return; - } - - buf += sprintf(buf, "%s", lock_latest_err_buf); + ut_copy_file(file, lock_latest_err_file); } - if (buf_end - buf < 600) { - lock_mutex_exit_kernel(); - sprintf(buf, "... output truncated!\n"); - - return; - } - - buf += sprintf(buf, + fputs( "------------\n" "TRANSACTIONS\n" -"------------\n"); +"------------\n", file); - buf += sprintf(buf, "Trx id counter %lu %lu\n", + fprintf(file, "Trx id counter %lu %lu\n", (ulong) ut_dulint_get_high(trx_sys->max_trx_id), (ulong) ut_dulint_get_low(trx_sys->max_trx_id)); - buf += sprintf(buf, + fprintf(file, "Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n", (ulong) ut_dulint_get_high(purge_sys->purge_trx_no), (ulong) ut_dulint_get_low(purge_sys->purge_trx_no), (ulong) ut_dulint_get_high(purge_sys->purge_undo_no), (ulong) ut_dulint_get_low(purge_sys->purge_undo_no)); - buf += sprintf(buf, + fprintf(file, "Total number of lock structs in row lock hash table %lu\n", (ulong) lock_get_n_rec_locks()); - buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); + fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); /* First print info on non-active transactions */ trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); while (trx) { - if (buf_end - buf < 900) { - lock_mutex_exit_kernel(); - sprintf(buf, "... output truncated!\n"); - - return; - } - if (trx->conc_state == TRX_NOT_STARTED) { - buf += sprintf(buf, "---"); - trx_print(buf, trx); - - buf += strlen(buf); + fputs("---", file); + trx_print(file, trx); } trx = UT_LIST_GET_NEXT(mysql_trx_list, trx); @@ -4004,33 +3933,17 @@ loop: if (trx == NULL) { lock_mutex_exit_kernel(); - /* lock_validate(); */ - - return; - } - - if (buf_end - buf < 900) { - lock_mutex_exit_kernel(); - sprintf(buf, "... output truncated!\n"); + ut_ad(lock_validate()); return; } if (nth_lock == 0) { - buf += sprintf(buf, "---"); - trx_print(buf, trx); - - buf += strlen(buf); - - if (buf_end - buf < 500) { - lock_mutex_exit_kernel(); - sprintf(buf, "... output truncated!\n"); - - return; - } + fputs("---", file); + trx_print(file, trx); if (trx->read_view) { - buf += sprintf(buf, + fprintf(file, "Trx read view will not see trx with id >= %lu %lu, sees < %lu %lu\n", (ulong) ut_dulint_get_high(trx->read_view->low_limit_id), (ulong) ut_dulint_get_low(trx->read_view->low_limit_id), @@ -4039,19 +3952,17 @@ loop: } if (trx->que_state == TRX_QUE_LOCK_WAIT) { - buf += sprintf(buf, + fprintf(file, "------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:\n", (ulong)difftime(time(NULL), trx->wait_started)); if (lock_get_type(trx->wait_lock) == LOCK_REC) { - lock_rec_print(buf, trx->wait_lock); + lock_rec_print(file, trx->wait_lock); } else { - lock_table_print(buf, trx->wait_lock); + lock_table_print(file, trx->wait_lock); } - buf += strlen(buf); - buf += sprintf(buf, - "------------------\n"); + fputs("------------------\n", file); } } @@ -4079,13 +3990,6 @@ loop: goto loop; } - if (buf_end - buf < 500) { - lock_mutex_exit_kernel(); - sprintf(buf, "... output truncated!\n"); - - return; - } - if (lock_get_type(lock) == LOCK_REC) { space = lock->un_member.rec_lock.space; page_no = lock->un_member.rec_lock.page_no; @@ -4106,22 +4010,21 @@ loop: goto loop; } - lock_rec_print(buf, lock); + lock_rec_print(file, lock); } else { ut_ad(lock_get_type(lock) == LOCK_TABLE); - lock_table_print(buf, lock); + lock_table_print(file, lock); } - buf += strlen(buf); - load_page_first = TRUE; nth_lock++; if (nth_lock >= 10) { - buf += sprintf(buf, - "10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n"); + fputs( + "10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n", + file); nth_trx++; nth_lock = 0; @@ -4132,6 +4035,7 @@ loop: goto loop; } +#ifdef UNIV_DEBUG /************************************************************************* Validates the lock queue on a table. */ @@ -4338,8 +4242,8 @@ loop: index = lock->index; rec = page_find_rec_with_heap_no(page, i); - printf("Validating %lu %lu\n", (ulong) space, - (ulong) page_no); + fprintf(stderr, + "Validating %lu %lu\n", (ulong) space, (ulong) page_no); lock_mutex_exit_kernel(); @@ -4442,6 +4346,7 @@ lock_validate(void) return(TRUE); } +#endif /* UNIV_DEBUG */ /*============ RECORD LOCK CHECKS FOR ROW OPERATIONS ====================*/ @@ -4598,7 +4503,6 @@ lock_clust_rec_modify_check_and_lock( dict_index_t* index, /* in: clustered index */ que_thr_t* thr) /* in: query thread */ { - trx_t* trx; ulint err; if (flags & BTR_NO_LOCKING_FLAG) { @@ -4608,8 +4512,6 @@ lock_clust_rec_modify_check_and_lock( ut_ad(index->type & DICT_CLUSTERED); - trx = thr_get_trx(thr); - lock_mutex_enter_kernel(); ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX)); diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index e99ea269920..292fed4b4ec 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -511,7 +511,8 @@ log_group_calc_lsn_offset( ut_a(offset < (((ib_longlong) 1) << 32)); /* offset must be < 4 GB */ - /* printf("Offset is %lu gr_lsn_offset is %lu difference is %lu\n", + /* fprintf(stderr, + "Offset is %lu gr_lsn_offset is %lu difference is %lu\n", (ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference); */ @@ -931,8 +932,8 @@ log_group_check_flush_completion( if (!log_sys->one_flushed && group->n_pending_writes == 0) { #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf("Log flushed first to group %lu\n", - (ulong) group->id); + fprintf(stderr, + "Log flushed first to group %lu\n", (ulong) group->id); } #endif /* UNIV_LOG_DEBUG */ @@ -945,7 +946,7 @@ log_group_check_flush_completion( #ifdef UNIV_LOG_DEBUG if (log_debug_writes && (group->n_pending_writes == 0)) { - printf("Log flushed to group %lu\n", (ulong) group->id); + fprintf(stderr, "Log flushed to group %lu\n", (ulong) group->id); } #endif /* UNIV_LOG_DEBUG */ @@ -1068,7 +1069,6 @@ static void log_group_file_header_flush( /*========================*/ - ulint type, /* in: LOG_FLUSH or LOG_RECOVER */ log_group_t* group, /* in: log group */ ulint nth_file, /* in: header to the nth file in the log file space */ @@ -1077,9 +1077,6 @@ log_group_file_header_flush( { byte* buf; ulint dest_offset; - - UT_NOT_USED(type); - #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ @@ -1098,9 +1095,9 @@ log_group_file_header_flush( #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf( - "Writing log file header to group %lu file %lu\n", - (ulong) group->id, (ulong) nth_file); + fprintf(stderr, + "Writing log file header to group %lu file %lu\n", + (ulong) group->id, (ulong) nth_file); } #endif /* UNIV_LOG_DEBUG */ @@ -1134,7 +1131,6 @@ Writes a buffer to a log file group. */ void log_group_write_buf( /*================*/ - ulint type, /* in: LOG_FLUSH or LOG_RECOVER */ log_group_t* group, /* in: log group */ byte* buf, /* in: buffer */ ulint len, /* in: buffer len; must be divisible @@ -1175,7 +1171,7 @@ loop: && write_header) { /* We start to write a new log file instance in the group */ - log_group_file_header_flush(type, group, + log_group_file_header_flush(group, next_offset / group->file_size, start_lsn); } @@ -1190,15 +1186,14 @@ loop: #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf( + fprintf(stderr, "Writing log file segment to group %lu offset %lu len %lu\n" - "start lsn %lu %lu\n", + "start lsn %lu %lu\n" + "First block n:o %lu last block n:o %lu\n", (ulong) group->id, (ulong) next_offset, (ulong) write_len, (ulong) ut_dulint_get_high(start_lsn), - (ulong) ut_dulint_get_low(start_lsn)); - printf( - "First block n:o %lu last block n:o %lu\n", + (ulong) ut_dulint_get_low(start_lsn). (ulong) log_block_get_hdr_no(buf), (ulong) log_block_get_hdr_no( buf + write_len - OS_FILE_LOG_BLOCK_SIZE)); @@ -1279,7 +1274,7 @@ loop: ut_ad(loop_count < 5); if (loop_count > 2) { -/* printf("Log loop count %lu\n", loop_count); */ +/* fprintf(stderr, "Log loop count %lu\n", loop_count); */ } mutex_enter(&(log_sys->mutex)); @@ -1342,7 +1337,8 @@ loop: #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf("Writing log from %lu %lu up to lsn %lu %lu\n", + fprintf(stderr, + "Writing log from %lu %lu up to lsn %lu %lu\n", (ulong) ut_dulint_get_high(log_sys->written_to_all_lsn), (ulong) ut_dulint_get_low(log_sys->written_to_all_lsn), (ulong) ut_dulint_get_high(log_sys->lsn), @@ -1396,7 +1392,7 @@ loop: /* Do the write to the log files */ while (group) { - log_group_write_buf(LOG_FLUSH, group, + log_group_write_buf(group, log_sys->buf + area_start, area_end - area_start, ut_dulint_align_down(log_sys->written_to_all_lsn, @@ -1762,11 +1758,11 @@ log_reset_first_header_and_checkpoint( lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE); /* Write the label of ibbackup --restore */ - sprintf((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, + strcpy((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup "); ut_sprintf_timestamp( - (char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP - + strlen("ibbackup ")); + (char*) hdr_buf + (LOG_FILE_WAS_CREATED_BY_HOT_BACKUP + + (sizeof "ibbackup ") - 1)); buf = hdr_buf + LOG_CHECKPOINT_1; mach_write_to_8(buf + LOG_CHECKPOINT_NO, ut_dulint_zero); @@ -1909,7 +1905,7 @@ log_checkpoint( #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf("Making checkpoint no %lu at lsn %lu %lu\n", + fprintf(stderr, "Making checkpoint no %lu at lsn %lu %lu\n", (ulong) ut_dulint_get_low(log_sys->next_checkpoint_no), (ulong) ut_dulint_get_high(oldest_lsn), (ulong) ut_dulint_get_low(oldest_lsn)); @@ -2137,13 +2133,13 @@ void log_archived_file_name_gen( /*=======================*/ char* buf, /* in: buffer where to write */ - ulint id, /* in: group id */ + ulint id __attribute__((unused)), + /* in: group id; + currently we only archive the first group */ ulint file_no)/* in: file number */ { ut_a(0); - UT_NOT_USED(id); /* Currently we only archive the first group */ - sprintf(buf, "%sib_arch_log_%010lu", srv_arch_dir, (ulong) file_no); } @@ -2292,18 +2288,17 @@ loop: if (!ret) { fprintf(stderr, - "InnoDB: Cannot create or open archive log file %s.\n", - name); - fprintf(stderr, "InnoDB: Cannot continue operation.\n" - "InnoDB: Check that the log archive directory exists,\n" - "InnoDB: you have access rights to it, and\n" - "InnoDB: there is space available.\n"); - exit(1); + "InnoDB: Cannot create or open archive log file %s.\n" + "InnoDB: Cannot continue operation.\n" + "InnoDB: Check that the log archive directory exists,\n" + "InnoDB: you have access rights to it, and\n" + "InnoDB: there is space available.\n", name); + exit(1); } #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf("Created archive file %s\n", name); + fprintf(stderr, "Created archive file %s\n", name); } #endif /* UNIV_LOG_DEBUG */ @@ -2334,7 +2329,7 @@ loop: #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf( + fprintf(stderr, "Archiving starting at lsn %lu %lu, len %lu to group %lu\n", (ulong) ut_dulint_get_high(start_lsn), (ulong) ut_dulint_get_low(start_lsn), @@ -2437,7 +2432,8 @@ log_archive_write_complete_groups(void) #ifdef UNIV_LOG_DEBUG if (log_debug_writes && trunc_files) { - printf("Complete file(s) archived to group %lu\n", + fprintf(stderr, + "Complete file(s) archived to group %lu\n", (ulong) group->id); } #endif /* UNIV_LOG_DEBUG */ @@ -2465,7 +2461,7 @@ log_archive_write_complete_groups(void) #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf("Archiving writes completed\n"); + fputs("Archiving writes completed\n", stderr); } #endif /* UNIV_LOG_DEBUG */ } @@ -2488,7 +2484,7 @@ log_archive_check_completion_low(void) #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf("Archiving read completed\n"); + fputs("Archiving read completed\n", stderr); } #endif /* UNIV_LOG_DEBUG */ @@ -2640,7 +2636,8 @@ loop: #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf("Archiving from lsn %lu %lu to lsn %lu %lu\n", + fprintf(stderr, + "Archiving from lsn %lu %lu to lsn %lu %lu\n", (ulong) ut_dulint_get_high(log_sys->archived_lsn), (ulong) ut_dulint_get_low(log_sys->archived_lsn), (ulong) ut_dulint_get_high(limit_lsn), @@ -2755,7 +2752,7 @@ log_archive_close_groups( #ifdef UNIV_LOG_DEBUG if (log_debug_writes) { - printf( + fprintf(stderr, "Incrementing arch file no to %lu in log group %lu\n", (ulong) group->archived_file_no + 2, (ulong) group->id); @@ -3313,20 +3310,15 @@ Prints info of the log. */ void log_print( /*======*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end)/* in: buffer end */ + FILE* file) /* in: file where to print */ { double time_elapsed; time_t current_time; - if (buf_end - buf < 300) { - - return; - } - mutex_enter(&(log_sys->mutex)); - buf += sprintf(buf, "Log sequence number %lu %lu\n" + fprintf(file, + "Log sequence number %lu %lu\n" "Log flushed up to %lu %lu\n" "Last checkpoint at %lu %lu\n", (ulong) ut_dulint_get_high(log_sys->lsn), @@ -3340,7 +3332,7 @@ log_print( time_elapsed = 0.001 + difftime(current_time, log_sys->last_printout_time); - buf += sprintf(buf, + fprintf(file, "%lu pending log writes, %lu pending chkp writes\n" "%lu log i/o's done, %.2f log i/o's/second\n", (ulong) log_sys->n_pending_writes, diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 432a6ed1e85..4f4220962f0 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -288,8 +288,7 @@ recv_truncate_group( len = ut_dulint_minus(end_lsn, start_lsn); - log_group_write_buf(LOG_RECOVER, group, log_sys->buf, len, - start_lsn, 0); + log_group_write_buf(group, log_sys->buf, len, start_lsn, 0); if (ut_dulint_cmp(end_lsn, finish_lsn) >= 0) { return; @@ -345,8 +344,7 @@ recv_copy_group( len = ut_dulint_minus(end_lsn, start_lsn); - log_group_write_buf(LOG_RECOVER, group, log_sys->buf, len, - start_lsn, 0); + log_group_write_buf(group, log_sys->buf, len, start_lsn, 0); if (ut_dulint_cmp(end_lsn, recovered_lsn) >= 0) { @@ -541,7 +539,7 @@ recv_find_max_checkpoint( "InnoDB: the problem may be that during an earlier attempt you managed\n" "InnoDB: to create the InnoDB data files, but log file creation failed.\n" "InnoDB: If that is the case, please refer to section 3.1 of\n" -"InnoDB: http://www.innodb.com/ibman.html\n"); +"InnoDB: http://www.innodb.com/ibman.php\n"); return(DB_ERROR); } @@ -609,7 +607,7 @@ recv_read_cp_info_for_backup( *fsp_limit = 1000000000; } -/* printf("fsp limit %lu MB\n", *fsp_limit); */ +/* fprintf(stderr, "fsp limit %lu MB\n", *fsp_limit); */ *cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO); @@ -685,7 +683,7 @@ recv_scan_log_seg_for_backup( if (no != log_block_convert_lsn_to_no(*scanned_lsn) || !log_block_checksum_is_ok_or_old_format(log_block)) { /* - printf( + fprintf(stderr, "Log block n:o %lu, scanned lsn n:o %lu\n", no, log_block_convert_lsn_to_no(*scanned_lsn)); */ @@ -693,7 +691,7 @@ recv_scan_log_seg_for_backup( log_block += OS_FILE_LOG_BLOCK_SIZE; /* - printf( + fprintf(stderr, "Next log block n:o %lu\n", log_block_get_hdr_no(log_block)); */ @@ -710,7 +708,8 @@ recv_scan_log_seg_for_backup( /* Garbage from a log buffer flush which was made before the most recent database recovery */ /* - printf("Scanned cp n:o %lu, block cp n:o %lu\n", + fprintf(stderr, + "Scanned cp n:o %lu, block cp n:o %lu\n", *scanned_checkpoint_no, log_block_get_checkpoint_no(log_block)); */ @@ -728,7 +727,8 @@ recv_scan_log_seg_for_backup( if (data_len < OS_FILE_LOG_BLOCK_SIZE) { /* Log data ends here */ - /* printf("Log block data len %lu\n", data_len); */ + /* fprintf(stderr, "Log block data len %lu\n", + data_len); */ break; } @@ -939,7 +939,7 @@ recv_add_to_hash_table( recv_fold(space, page_no), recv_addr); recv_sys->n_addrs++; - /* printf("Inserting log rec for space %lu, page %lu\n", + /* fprintf(stderr, "Inserting log rec for space %lu, page %lu\n", space, page_no); */ } @@ -1057,7 +1057,7 @@ recv_recover_page( return; } - /* printf("Recovering space %lu, page %lu\n", space, page_no); */ + /* fprintf(stderr, "Recovering space %lu, page %lu\n", space, page_no); */ recv_addr->state = RECV_BEING_PROCESSED; @@ -1248,7 +1248,7 @@ recv_read_in_area( buf_read_recv_pages(FALSE, space, page_nos, n); /* - printf("Recv pages at %lu n %lu\n", page_nos[0], n); + fprintf(stderr, "Recv pages at %lu n %lu\n", page_nos[0], n); */ return(n); } @@ -1311,9 +1311,9 @@ loop: if (recv_addr->state == RECV_NOT_PROCESSED) { if (!has_printed) { ut_print_timestamp(stderr); - fprintf(stderr, + fputs( " InnoDB: Starting an apply batch of log records to the database...\n" -"InnoDB: Progress in percents: "); +"InnoDB: Progress in percents: ",stderr); has_printed = TRUE; } @@ -1431,9 +1431,9 @@ recv_apply_log_recs_for_backup(void) page = recv_backup_application_page; - printf( + fputs( "InnoDB: Starting an apply batch of log records to the database...\n" -"InnoDB: Progress in percents: "); +"InnoDB: Progress in percents: ", stderr); n_hash_cells = hash_get_n_cells(recv_sys->addr_hash); @@ -1445,7 +1445,7 @@ recv_apply_log_recs_for_backup(void) if (!fil_tablespace_exists_in_mem(recv_addr->space)) { /* - printf( + fprintf(stderr, "InnoDB: Warning: cannot apply log record to tablespace %lu page %lu,\n" "InnoDB: because tablespace with that id does not exist.\n", recv_addr->space, recv_addr->page_no); @@ -1478,7 +1478,7 @@ recv_apply_log_recs_for_backup(void) recv_addr->space, recv_addr->page_no + 1); if (!success) { - printf( + fprintf(stderr, "InnoDB: Fatal error: cannot extend tablespace %lu to hold %lu pages\n", recv_addr->space, recv_addr->page_no); @@ -1492,9 +1492,9 @@ recv_apply_log_recs_for_backup(void) recv_addr->page_no, 0, UNIV_PAGE_SIZE, page, NULL); if (error != DB_SUCCESS) { - printf( + fprintf(stderr, "InnoDB: Fatal error: cannot read from tablespace %lu page number %lu\n", - recv_addr->space, recv_addr->page_no); + (ulong) recv_addr->space, (ulong) recv_addr->page_no); exit(1); } @@ -1519,8 +1519,9 @@ skip_this_recv_addr: if ((100 * i) / n_hash_cells != (100 * (i + 1)) / n_hash_cells) { - printf("%lu ", (100 * i) / n_hash_cells); - fflush(stdout); + fprintf(stderr, "%lu ", + (ulong) ((100 * i) / n_hash_cells)); + fflush(stderr); } } @@ -1859,53 +1860,46 @@ recv_report_corrupt_log( ulint space, /* in: space id, this may also be garbage */ ulint page_no)/* in: page number, this may also be garbage */ { - char* err_buf; - fprintf(stderr, "InnoDB: ############### CORRUPT LOG RECORD FOUND\n" "InnoDB: Log record type %lu, space id %lu, page number %lu\n" -"InnoDB: Log parsing proceeded successfully up to %lu %lu\n", - (ulong) type, (ulong) space, (ulong) page_no, - (ulong) ut_dulint_get_high(recv_sys->recovered_lsn), - (ulong) ut_dulint_get_low(recv_sys->recovered_lsn)); - - err_buf = ut_malloc(1000000); - - fprintf(stderr, +"InnoDB: Log parsing proceeded successfully up to %lu %lu\n" "InnoDB: Previous log record type %lu, is multi %lu\n" "InnoDB: Recv offset %lu, prev %lu\n", - (ulong) recv_previous_parsed_rec_type, - (ulong) recv_previous_parsed_rec_is_multi, - (ulong) (ptr - recv_sys->buf), - (ulong) recv_previous_parsed_rec_offset); + (ulong) type, (ulong) space, (ulong) page_no, + (ulong) ut_dulint_get_high(recv_sys->recovered_lsn), + (ulong) ut_dulint_get_low(recv_sys->recovered_lsn), + (ulong) recv_previous_parsed_rec_type, + (ulong) recv_previous_parsed_rec_is_multi, + (ulong) (ptr - recv_sys->buf), + (ulong) recv_previous_parsed_rec_offset); if ((ulint)(ptr - recv_sys->buf + 100) > recv_previous_parsed_rec_offset && (ulint)(ptr - recv_sys->buf + 100 - recv_previous_parsed_rec_offset) < 200000) { + fputs( +"InnoDB: Hex dump of corrupt log starting 100 bytes before the start\n" +"InnoDB: of the previous log rec,\n" +"InnoDB: and ending 100 bytes after the start of the corrupt rec:\n", + stderr); - ut_sprintf_buf(err_buf, + ut_print_buf(stderr, recv_sys->buf + recv_previous_parsed_rec_offset - 100, ptr - recv_sys->buf + 200 - recv_previous_parsed_rec_offset); - fprintf(stderr, -"InnoDB: Hex dump of corrupt log starting 100 bytes before the start\n" -"InnoDB: of the previous log rec,\n" -"InnoDB: and ending 100 bytes after the start of the corrupt rec:\n%s\n", - err_buf); + putc('\n', stderr); } - ut_free(err_buf); - - fprintf(stderr, + fputs( "InnoDB: WARNING: the log file may have been corrupt and it\n" "InnoDB: is possible that the log scan did not proceed\n" "InnoDB: far enough in recovery! Please run CHECK TABLE\n" "InnoDB: on your InnoDB tables to check that they are ok!\n" "InnoDB: If mysqld crashes after this recovery, look at\n" - "InnoDB: section 6.1 of http://www.innodb.com/ibman.html\n" - "InnoDB: about forcing recovery.\n"); + "InnoDB: section 6.1 of http://www.innodb.com/ibman.php\n" + "InnoDB: about forcing recovery.\n", stderr); fflush(stderr); } @@ -2583,7 +2577,7 @@ recv_recovery_from_checkpoint_start( log_hdr_buf, max_cp_group); if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, - (byte*)"ibbackup", ut_strlen((char*)"ibbackup"))) { + (byte*)"ibbackup", (sizeof "ibbackup") - 1)) { /* This log file was created by ibbackup --restore: print a note to the user about it */ @@ -2991,38 +2985,47 @@ recv_reset_log_files_for_backup( ibool success; byte* buf; ulint i; - char name[5000]; - + ulint log_dir_len; + char* name; + static + char logfilename[] = "ib_logfile"; + + log_dir_len = strlen(log_dir); + /* reserve space for log_dir, "ib_logfile" and a number */ + name = memcpy(mem_alloc(log_dir_len + ((sizeof logfilename) + 11)), + log_dir, log_dir_len); + memcpy(name + log_dir_len, logfilename, sizeof logfilename); + buf = ut_malloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE); - - memset(buf, LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE, '\0'); + memset(buf, LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE, '\0'); + for (i = 0; i < n_log_files; i++) { - sprintf(name, "%sib_logfile%lu", log_dir, (ulong) i); + sprintf(name + log_dir_len + sizeof logfilename, "%lu", (ulong) i); log_file = os_file_create_simple(name, OS_FILE_CREATE, OS_FILE_READ_WRITE, &success); if (!success) { - printf( + fprintf(stderr, "InnoDB: Cannot create %s. Check that the file does not exist yet.\n", name); exit(1); } - printf( -"Setting log file size to %lu %lu\n", (ulong) ut_get_high32(log_file_size), - (ulong) (log_file_size & 0xFFFFFFFFUL)); + fprintf(stderr, + "Setting log file size to %lu %lu\n", + (ulong) ut_get_high32(log_file_size), + (ulong) log_file_size & 0xFFFFFFFFUL); success = os_file_set_size(name, log_file, log_file_size & 0xFFFFFFFFUL, ut_get_high32(log_file_size)); if (!success) { - printf( -"InnoDB: Cannot set %s size to %lu %lu\n", name, - (ulong) ut_get_high32(log_file_size), - (ulong) (log_file_size & 0xFFFFFFFFUL)); + fprintf(stderr, +"InnoDB: Cannot set %s size to %lu %lu\n", name, (ulong) ut_get_high32(log_file_size), + (ulong) (log_file_size & 0xFFFFFFFFUL)); exit(1); } @@ -3037,12 +3040,12 @@ recv_reset_log_files_for_backup( log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn); log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE, LOG_BLOCK_HDR_SIZE); - sprintf(name, "%sib_logfile%lu", log_dir, (ulong) 0); + strcpy(name + log_dir_len + sizeof logfilename, "0"); log_file = os_file_create_simple(name, OS_FILE_OPEN, OS_FILE_READ_WRITE, &success); if (!success) { - printf("InnoDB: Cannot open %s.\n", name); + fprintf(stderr, "InnoDB: Cannot open %s.\n", name); exit(1); } @@ -3052,6 +3055,7 @@ recv_reset_log_files_for_backup( os_file_flush(log_file); os_file_close(log_file); + mem_free(name); ut_free(buf); } diff --git a/innobase/mem/mem0dbg.c b/innobase/mem/mem0dbg.c index d521143eb47..5ace0441180 100644 --- a/innobase/mem/mem0dbg.c +++ b/innobase/mem/mem0dbg.c @@ -336,7 +336,7 @@ mem_hash_remove( } if (node == NULL) { - printf( + fprintf(stderr, "Memory heap or buffer freed in %s line %lu did not exist.\n", file_name, (ulong) line); ut_error; @@ -351,20 +351,14 @@ mem_hash_remove( mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size, NULL, NULL); if (error) { - printf( -"Inconsistency in memory heap or buffer n:o %lu created\n", - (ulong) node->nth_heap); - printf("in %s line %lu and tried to free in %s line %lu.\n", - node->file_name, (ulong) node->line, - file_name, (ulong) line); - - printf( -"Hex dump of 400 bytes around memory heap first block start:\n"); - - ut_print_buf((byte*)(node->heap) - 200, 400); - - printf("\nDump of the mem heap:\n"); - + fprintf(stderr, + "Inconsistency in memory heap or buffer n:o %lu created\n" + "in %s line %lu and tried to free in %s line %lu.\n" + "Hex dump of 400 bytes around memory heap first block start:\n", + node->nth_heap, node->file_name, (ulong) node->line, + file_name, (ulong) line); + ut_print_buf(stderr, (byte*)node->heap - 200, 400); + fputs("\nDump of the mem heap:\n", stderr); mem_heap_validate_or_print(node->heap, NULL, TRUE, &error, &size, NULL, NULL); ut_error; @@ -379,6 +373,7 @@ mem_hash_remove( } #endif /* UNIV_MEM_DEBUG */ +#ifdef UNIV_DEBUG /******************************************************************* Checks a memory heap for consistency and prints the contents if requested. Outputs the sum of sizes of buffers given to the user (only in @@ -440,7 +435,7 @@ mem_heap_validate_or_print( } if (print) { - printf("Memory heap:"); + fputs("Memory heap:", stderr); } while (block != NULL) { @@ -461,7 +456,7 @@ mem_heap_validate_or_print( /* We can trace the fields of the block only in the debug version */ if (print) { - printf(" Block %ld:", block_count); + fprintf(stderr, " Block %ld:", block_count); } field = (byte*)block + mem_block_get_start(block); @@ -481,7 +476,7 @@ mem_heap_validate_or_print( len = mem_field_header_get_len(user_field); if (print) { - ut_print_buf(user_field, len); + ut_print_buf(stderr, user_field, len); } total_len += len; @@ -561,7 +556,7 @@ mem_heap_print( mem_heap_validate_or_print(heap, NULL, TRUE, &error, &us_size, &phys_size, &n_blocks); - printf( + fprintf(stderr, "\nheap type: %lu; size: user size %lu; physical size %lu; blocks %lu.\n", (ulong) heap->type, (ulong) us_size, (ulong) phys_size, (ulong) n_blocks); @@ -608,6 +603,7 @@ mem_heap_validate( return(TRUE); } +#endif /* UNIV_DEBUG */ #ifdef UNIV_MEM_DEBUG /********************************************************************* @@ -680,9 +676,11 @@ mem_validate_no_assert(void) &ph_size, &n_blocks); if (error) { - printf("\nERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n"); - printf("Inconsistency in memory heap or buffer created\n"); - printf("in %s line %lu.\n", node->file_name, node->line); + fprintf(stderr, + "\nERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n" + "Inconsistency in memory heap or buffer created\n" + "in %s line %lu.\n", + node->file_name, node->line); mutex_exit(&mem_hash_mutex); @@ -742,12 +740,10 @@ mem_analyze_corruption( ulint i; ulint dist; - ut_sprintf_buf(srv_fatal_errbuf, ptr - 250, 500); - fprintf(stderr, - "InnoDB: Apparent memory corruption: mem dump %s\n", srv_fatal_errbuf); + fputs("InnoDB: Apparent memory corruption: mem dump ", stderr); + ut_print_buf(stderr, ptr - 250, 500); - fprintf(stderr, - "InnoDB: Scanning backward trying to find previous allocated mem blocks\n"); + fputs("\nInnoDB: Scanning backward trying to find previous allocated mem blocks\n", stderr); p = ptr; dist = 0; diff --git a/innobase/mem/mem0mem.c b/innobase/mem/mem0mem.c index 6de8d0c5f20..e1b9a762381 100644 --- a/innobase/mem/mem0mem.c +++ b/innobase/mem/mem0mem.c @@ -196,12 +196,7 @@ mem_heap_create_block( mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE); block->free_block = NULL; - - if (init_block != NULL) { - block->init_block = TRUE; - } else { - block->init_block = FALSE; - } + block->init_block = (init_block != NULL); ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len); diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 4f1ac2bcd7c..7f36b37f734 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -567,6 +567,7 @@ mem_area_free( ut_ad(mem_pool_validate(pool)); } +#ifdef UNIV_DEBUG /************************************************************************ Validates a memory pool. */ @@ -644,6 +645,7 @@ mem_pool_print_info( (ulong) pool->reserved); mutex_exit(&(pool->mutex)); } +#endif /* UNIV_DEBUG */ /************************************************************************ Returns the amount of reserved memory. */ diff --git a/innobase/mtr/mtr0log.c b/innobase/mtr/mtr0log.c index 5a4aaa2377d..82baa8905ba 100644 --- a/innobase/mtr/mtr0log.c +++ b/innobase/mtr/mtr0log.c @@ -54,15 +54,15 @@ mlog_write_initial_log_record( byte* log_ptr; ut_ad(type <= MLOG_BIGGEST_TYPE); + ut_ad(type > MLOG_8BYTES); if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) { fprintf(stderr, - "InnoDB: Error: trying to write to a stray memory location %lx\n", - (ulong) ptr); + "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); ut_error; } - log_ptr = mlog_open(mtr, 20); + log_ptr = mlog_open(mtr, 11); /* If no logging is requested, we may return now */ if (log_ptr == NULL) { @@ -95,6 +95,7 @@ mlog_parse_initial_log_record( } *type = (byte)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG); + ut_ad(*type <= MLOG_BIGGEST_TYPE); ptr++; @@ -220,8 +221,7 @@ mlog_write_ulint( if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) { fprintf(stderr, - "InnoDB: Error: trying to write to a stray memory location %lx\n", - (ulong) ptr); + "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); ut_error; } @@ -234,7 +234,7 @@ mlog_write_ulint( mach_write_to_4(ptr, val); } - log_ptr = mlog_open(mtr, 30); + log_ptr = mlog_open(mtr, 11 + 2 + 5); /* If no logging is requested, we may return now */ if (log_ptr == NULL) { @@ -267,8 +267,7 @@ mlog_write_dulint( if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) { fprintf(stderr, - "InnoDB: Error: trying to write to a stray memory location %lx\n", - (ulong) ptr); + "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); ut_error; } @@ -276,7 +275,7 @@ mlog_write_dulint( mach_write_to_8(ptr, val); - log_ptr = mlog_open(mtr, 30); + log_ptr = mlog_open(mtr, 11 + 2 + 9); /* If no logging is requested, we may return now */ if (log_ptr == NULL) { @@ -311,8 +310,7 @@ mlog_write_string( if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) { fprintf(stderr, - "InnoDB: Error: trying to write to a stray memory location %lx\n", - (ulong) ptr); + "InnoDB: Error: trying to write to a stray memory location %p\n", ptr); ut_error; } ut_ad(ptr && mtr); diff --git a/innobase/mtr/mtr0mtr.c b/innobase/mtr/mtr0mtr.c index ac1a638063d..fa1481dcb5f 100644 --- a/innobase/mtr/mtr0mtr.c +++ b/innobase/mtr/mtr0mtr.c @@ -262,7 +262,8 @@ mtr_first_to_modify_page_after_backup( block->frame), backup_lsn) <= 0) { - printf("Page %lu newest %lu backup %lu\n", + fprintf(stderr, + "Page %lu newest %lu backup %lu\n", (ulong) block->offset, (ulong) ut_dulint_get_low( buf_frame_get_newest_modification( @@ -507,6 +508,7 @@ mtr_read_dulint( return(mach_read_from_8(ptr)); } +#ifdef UNIV_DEBUG /************************************************************* Prints info of an mtr handle. */ @@ -515,8 +517,9 @@ mtr_print( /*======*/ mtr_t* mtr) /* in: mtr */ { - printf( + fprintf(stderr, "Mini-transaction handle: memo size %lu bytes log size %lu bytes\n", (ulong) dyn_array_get_data_size(&(mtr->memo)), (ulong) dyn_array_get_data_size(&(mtr->log))); } +#endif /* UNIV_DEBUG */ diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 7973cfc6fe8..92e7f1e4fc3 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -234,7 +234,7 @@ os_file_get_last_error( "InnoDB: of the same name as a data file.\n"); } else { fprintf(stderr, - "InnoDB: See section 13.2 at http://www.innodb.com/ibman.html\n" + "InnoDB: See section 13.2 at http://www.innodb.com/ibman.php\n" "InnoDB: about operating system error numbers.\n"); } } @@ -258,7 +258,7 @@ os_file_get_last_error( ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Operating system error number %lu in a file operation.\n", err); + " InnoDB: Operating system error number %lu in a file operation.\n", (ulong) err); if (err == ENOENT) { fprintf(stderr, @@ -280,7 +280,7 @@ os_file_get_last_error( } fprintf(stderr, - "InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n" + "InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" "InnoDB: about operating system error numbers.\n"); } } @@ -1097,7 +1097,7 @@ try_again: ut_error; } -/* printf("Opening file %s, mode %s, type %s, purpose %s\n", +/* fprintf(stderr, "Opening file %s, mode %s, type %s, purpose %s\n", name, mode_str, type_str, purpose_str); */ #ifdef O_SYNC /* We let O_SYNC only affect log files; note that we map O_DSYNC to @@ -1106,7 +1106,7 @@ try_again: if (type == OS_LOG_FILE && srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) { -/* printf("Using O_SYNC for file %s\n", name); */ +/* fprintf(stderr, "Using O_SYNC for file %s\n", name); */ create_flag = create_flag | O_SYNC; } @@ -1116,7 +1116,7 @@ try_again: if (type != OS_LOG_FILE && srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) { -/* printf("Using O_DIRECT for file %s\n", name); */ +/* fprintf(stderr, "Using O_DIRECT for file %s\n", name); */ create_flag = create_flag | O_DIRECT; } @@ -1585,7 +1585,7 @@ os_file_flush( #ifdef HAVE_FDATASYNC ret = fdatasync(file); #else -/* printf("Flushing to file %lu\n", (ulint)file); */ +/* fprintf(stderr, "Flushing to file %p\n", file); */ ret = fsync(file); #endif os_n_fsyncs++; @@ -2029,7 +2029,7 @@ retry: fprintf(stderr, " InnoDB: Error: File pointer positioning to file %s failed at\n" "InnoDB: offset %lu %lu. Operating system error number %lu.\n" -"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n" +"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.php\n" "InnoDB: what the error number means.\n", name, (ulong) offset_high, (ulong) offset, (ulong) GetLastError()); @@ -2087,7 +2087,7 @@ retry: } fprintf(stderr, -"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n" +"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" "InnoDB: about operating system error numbers.\n"); os_has_said_disk_full = TRUE; @@ -2122,7 +2122,7 @@ retry: } fprintf(stderr, -"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n" +"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n" "InnoDB: about operating system error numbers.\n"); os_has_said_disk_full = TRUE; @@ -2412,33 +2412,35 @@ os_aio_init( os_io_init_simple(); for (i = 0; i < n_segments; i++) { - srv_io_thread_op_info[i] = (char*)"not started yet"; + srv_set_io_thread_op_info(i, "not started yet"); } n_per_seg = n / n_segments; n_write_segs = (n_segments - 2) / 2; n_read_segs = n_segments - 2 - n_write_segs; - /* printf("Array n per seg %lu\n", n_per_seg); */ + /* fprintf(stderr, "Array n per seg %lu\n", n_per_seg); */ os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1); - srv_io_thread_function[0] = (char*)"insert buffer thread"; + srv_io_thread_function[0] = "insert buffer thread"; os_aio_log_array = os_aio_array_create(n_per_seg, 1); - srv_io_thread_function[1] = (char*)"log thread"; + srv_io_thread_function[1] = "log thread"; os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg, n_read_segs); for (i = 2; i < 2 + n_read_segs; i++) { - srv_io_thread_function[i] = (char*)"read thread"; + ut_a(i < SRV_MAX_N_IO_THREADS); + srv_io_thread_function[i] = "read thread"; } os_aio_write_array = os_aio_array_create(n_write_segs * n_per_seg, n_write_segs); for (i = 2 + n_read_segs; i < n_segments; i++) { - srv_io_thread_function[i] = (char*)"write thread"; + ut_a(i < SRV_MAX_N_IO_THREADS); + srv_io_thread_function[i] = "write thread"; } os_aio_sync_array = os_aio_array_create(n_slots_sync, 1); @@ -2768,7 +2770,8 @@ loop: SIGRTMIN + 1 + os_aio_get_array_no(array); /* TODO: How to choose the signal numbers? */ /* - printf("AIO signal number %lu\n", (ulint) control->aio_sigevent.sigev_signo); + fprintf(stderr, "AIO signal number %lu\n", + (ulint) control->aio_sigevent.sigev_signo); */ control->aio_sigevent.sigev_value.sival_ptr = slot; #endif @@ -3022,7 +3025,7 @@ try_again: #elif defined(POSIX_ASYNC_IO) slot->control.aio_lio_opcode = LIO_READ; err = (ulint) aio_read(&(slot->control)); - printf("Starting Posix aio read %lu\n", err); + fprintf(stderr, "Starting POSIX aio read %lu\n", err); #endif } else { if (!wake_later) { @@ -3039,7 +3042,7 @@ try_again: #elif defined(POSIX_ASYNC_IO) slot->control.aio_lio_opcode = LIO_WRITE; err = (ulint) aio_write(&(slot->control)); - printf("Starting Posix aio write %lu\n", err); + fprintf(stderr, "Starting POSIX aio write %lu\n", err); #endif } else { if (!wake_later) { @@ -3150,13 +3153,10 @@ os_aio_windows_handle( n = array->n_slots / array->n_segments; if (array == os_aio_sync_array) { - srv_io_thread_op_info[orig_seg] = - "wait Windows aio for 1 page"; os_event_wait(os_aio_array_get_nth_slot(array, pos)->event); i = pos; } else { - srv_io_thread_op_info[orig_seg] = - "wait Windows aio"; + srv_set_io_thread_op_info(orig_seg, "wait Windows aio"); i = os_event_wait_multiple(n, (array->native_events) + segment * n); } @@ -3167,7 +3167,11 @@ os_aio_windows_handle( ut_a(slot->reserved); - srv_io_thread_op_info[orig_seg] = "get windows aio return value"; + if (orig_seg != ULINT_UNDEFINED) { + srv_set_io_thread_op_info(orig_seg, + "get windows aio return value"); + } + ret = GetOverlappedResult(slot->file, &(slot->control), &len, TRUE); *message1 = slot->message1; @@ -3234,7 +3238,7 @@ os_aio_posix_handle( pthread_sigmask(0, NULL, &thr_sigset); for (i = 32 ; i < 40; i++) { - printf("%lu : %lu %lu\n", (ulint)i, + fprintf(stderr, "%lu : %lu %lu\n", (ulint)i, (ulint)sigismember(&proc_sigset, i), (ulint)sigismember(&thr_sigset, i)); } @@ -3249,7 +3253,7 @@ os_aio_posix_handle( return(FALSE); } - printf("Handling Posix aio\n"); + fputs("Handling POSIX aio\n", stderr); array = os_aio_get_array_from_no(array_no); @@ -3489,8 +3493,8 @@ consecutive_loop: offs += consecutive_ios[i]->len; } } - - srv_io_thread_op_info[global_segment] = (char*) "doing file i/o"; + + srv_set_io_thread_op_info(global_segment, "doing file i/o"); if (os_aio_print_debug) { fprintf(stderr, @@ -3541,11 +3545,11 @@ consecutive_loop: } ut_a(ret); - srv_io_thread_op_info[global_segment] = (char*) "file i/o done"; + srv_set_io_thread_op_info(global_segment, "file i/o done"); -/* printf("aio: %lu consecutive %lu:th segment, first offs %lu blocks\n", - n_consecutive, global_segment, slot->offset - / UNIV_PAGE_SIZE); */ +/* fprintf(stderr, + "aio: %lu consecutive %lu:th segment, first offs %lu blocks\n", + n_consecutive, global_segment, slot->offset / UNIV_PAGE_SIZE); */ if (slot->type == OS_FILE_READ && n_consecutive > 1) { /* Copy the combined buffer to individual buffers */ @@ -3599,8 +3603,7 @@ wait_for_io: os_mutex_exit(array->mutex); recommended_sleep: - srv_io_thread_op_info[global_segment] = - (char*)"waiting for i/o request"; + srv_set_io_thread_op_info(global_segment, "waiting for i/o request"); os_event_wait(os_aio_segment_wait_events[global_segment]); @@ -3672,8 +3675,7 @@ Prints info of the aio arrays. */ void os_aio_print( /*=========*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end)/* in: buffer end */ + FILE* file) /* in: file where to print */ { os_aio_array_t* array; os_aio_slot_t* slot; @@ -3683,19 +3685,13 @@ os_aio_print( double avg_bytes_read; ulint i; - if (buf_end - buf < 1200) { - - return; - } - for (i = 0; i < srv_n_file_io_threads; i++) { - buf += sprintf(buf, "I/O thread %lu state: %s (%s)\n", - (ulong) i, + fprintf(file, "I/O thread %lu state: %s (%s)\n", (ulong) i, srv_io_thread_op_info[i], srv_io_thread_function[i]); } - buf += sprintf(buf, "Pending normal aio reads:"); + fputs("Pending normal aio reads:", file); array = os_aio_read_array; loop: @@ -3713,21 +3709,20 @@ loop: if (slot->reserved) { n_reserved++; - /* printf("Reserved slot, messages %lx %lx\n", - (ulint)slot->message1, - (ulint)slot->message2); - */ ut_a(slot->len > 0); + /* fprintf(stderr, "Reserved slot, messages %p %p\n", + slot->message1, slot->message2); */ + ut_a(slot->len > 0); } } ut_a(array->n_reserved == n_reserved); - buf += sprintf(buf, " %lu", (ulong) n_reserved); + fprintf(file, " %lu", (ulong) n_reserved); os_mutex_exit(array->mutex); if (array == os_aio_read_array) { - buf += sprintf(buf, ", aio writes:"); + fputs(", aio writes:", file); array = os_aio_write_array; @@ -3735,42 +3730,40 @@ loop: } if (array == os_aio_write_array) { - buf += sprintf(buf, ",\n ibuf aio reads:"); + fputs(",\n ibuf aio reads:", file); array = os_aio_ibuf_array; goto loop; } if (array == os_aio_ibuf_array) { - buf += sprintf(buf, ", log i/o's:"); + fputs(", log i/o's:", file); array = os_aio_log_array; goto loop; } if (array == os_aio_log_array) { - buf += sprintf(buf, ", sync i/o's:"); + fputs(", sync i/o's:", file); array = os_aio_sync_array; goto loop; } - buf += sprintf(buf, "\n"); - + putc('\n', file); current_time = time(NULL); time_elapsed = 0.001 + difftime(current_time, os_last_printout); - buf += sprintf(buf, - "Pending flushes (fsync) log: %lu; buffer pool: %lu\n", - (ulong) fil_n_pending_log_flushes, - (ulong) fil_n_pending_tablespace_flushes); - buf += sprintf(buf, + fprintf(file, + "Pending flushes (fsync) log: %lu; buffer pool: %lu\n" "%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n", + (ulong) fil_n_pending_log_flushes, + (ulong) fil_n_pending_tablespace_flushes, (ulong) os_n_file_reads, (ulong) os_n_file_writes, (ulong) os_n_fsyncs); if (os_file_n_pending_preads != 0 || os_file_n_pending_pwrites != 0) { - buf += sprintf(buf, + fprintf(file, "%lu pending preads, %lu pending pwrites\n", (ulong) os_file_n_pending_preads, (ulong) os_file_n_pending_pwrites); @@ -3783,7 +3776,7 @@ loop: (os_n_file_reads - os_n_file_reads_old); } - buf += sprintf(buf, + fprintf(file, "%.2f reads/s, %lu avg bytes/read, %.2f writes/s, %.2f fsyncs/s\n", (os_n_file_reads - os_n_file_reads_old) / time_elapsed, diff --git a/innobase/os/os0proc.c b/innobase/os/os0proc.c index 85791c55348..2f155788420 100644 --- a/innobase/os/os0proc.c +++ b/innobase/os/os0proc.c @@ -539,9 +539,8 @@ os_process_set_priority_boost( /* Does not do anything currently! SetProcessPriorityBoost(GetCurrentProcess(), no_boost); */ - printf( - "Warning: process priority boost setting currently not functional!\n" - ); + fputs("Warning: process priority boost setting currently not functional!\n", + stderr); #else UT_NOT_USED(do_boost); #endif diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 1252cc5e4b7..59d0fdbd8c9 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -187,7 +187,7 @@ os_thread_exit( is cast as a DWORD */ { #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Thread exits, id %lu\n", + fprintf(stderr, "Thread exits, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif os_mutex_enter(os_sync_mutex); diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c index 5d26d12bf20..459ab986610 100644 --- a/innobase/page/page0cur.c +++ b/innobase/page/page0cur.c @@ -479,6 +479,7 @@ page_cur_insert_rec_write_log( ulint i; ut_a(rec_size < UNIV_PAGE_SIZE); + ut_ad(rec_size == rec_get_size(insert_rec)); log_ptr = mlog_open(mtr, 30 + MLOG_BUF_MARGIN); @@ -631,7 +632,7 @@ page_cur_parse_insert_rec( } extra_info_yes = end_seg_len & 0x1UL; - end_seg_len = end_seg_len / 2; + end_seg_len >>= 1; if (end_seg_len >= UNIV_PAGE_SIZE) { recv_sys->found_corrupt_log = TRUE; @@ -694,7 +695,7 @@ page_cur_parse_insert_rec( mismatch_index = rec_get_size(cursor_rec) - end_seg_len; } - if (mismatch_index + end_seg_len < 1024) { + if (mismatch_index + end_seg_len < sizeof buf1) { buf = buf1; } else { buf = mem_alloc(mismatch_index + end_seg_len); @@ -703,8 +704,9 @@ page_cur_parse_insert_rec( /* Build the inserted record to buf */ if (mismatch_index >= UNIV_PAGE_SIZE) { - printf( - "Is short %lu, info_bits %lu, offset %lu, o_offset %lu\n" + fprintf(stderr, + "Is short %lu, info_bits %lu, offset %lu, " + "o_offset %lu\n" "mismatch index %lu, end_seg_len %lu\n" "parsed len %lu\n", (ulong) is_short, (ulong) info_bits, (ulong) offset, @@ -712,8 +714,8 @@ page_cur_parse_insert_rec( (ulong) mismatch_index, (ulong) end_seg_len, (ulong) (ptr - ptr2)); - printf("Dump of 300 bytes of log:\n"); - ut_print_buf(ptr2, 300); + fputs("Dump of 300 bytes of log:\n", stderr); + ut_print_buf(stderr, ptr2, 300); buf_page_print(page); @@ -729,7 +731,7 @@ page_cur_parse_insert_rec( page_cur_rec_insert(&cursor, buf + origin_offset, mtr); - if (mismatch_index + end_seg_len >= 1024) { + if (buf != buf1) { mem_free(buf); } diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c index c64a7590b94..aecc2dc4fd2 100644 --- a/innobase/page/page0page.c +++ b/innobase/page/page0page.c @@ -75,7 +75,6 @@ page_dir_find_owner_slot( page_t* page; page_dir_slot_t* slot; rec_t* original_rec = rec; - char err_buf[1000]; ut_ad(page_rec_check(rec)); @@ -93,20 +92,20 @@ page_dir_find_owner_slot( if (i == 0) { fprintf(stderr, - "InnoDB: Probable data corruption on page %lu\n", + "InnoDB: Probable data corruption on page %lu\n" + "InnoDB: Original record ", (ulong) buf_frame_get_page_no(page)); - rec_sprintf(err_buf, 900, original_rec); + rec_print(stderr, original_rec); - fprintf(stderr, - "InnoDB: Original record %s\n" - "InnoDB: on that page. Steps %lu.\n", err_buf, (ulong) steps); - - rec_sprintf(err_buf, 900, rec); - - fprintf(stderr, - "InnoDB: Cannot find the dir slot for record %s\n" - "InnoDB: on that page!\n", err_buf); + fprintf(stderr, "\n" + "InnoDB: on that page. Steps %lu.\n", (ulong) steps); + fputs( + "InnoDB: Cannot find the dir slot for record ", + stderr); + rec_print(stderr, rec); + fputs("\n" + "InnoDB: on that page!\n", stderr); buf_page_print(page); @@ -1121,8 +1120,8 @@ page_rec_print( /*===========*/ rec_t* rec) { - rec_print(rec); - printf( + rec_print(stderr, rec); + fprintf(stderr, " n_owned: %lu; heap_no: %lu; next rec: %lu\n", (ulong) rec_get_n_owned(rec), (ulong) rec_get_heap_no(rec), @@ -1148,25 +1147,26 @@ page_dir_print( n = page_dir_get_n_slots(page); - printf("--------------------------------\n"); - printf("PAGE DIRECTORY\n"); - printf("Page address %lx\n", (ulong)page); - printf("Directory stack top at offs: %lu; number of slots: %lu\n", - (ulong)(page_dir_get_nth_slot(page, n - 1) - page), (ulong) n); + fprintf(stderr, "--------------------------------\n" + "PAGE DIRECTORY\n" + "Page address %p\n" + "Directory stack top at offs: %lu; number of slots: %lu\n", + page, (ulong)(page_dir_get_nth_slot(page, n - 1) - page), (ulong) n); for (i = 0; i < n; i++) { slot = page_dir_get_nth_slot(page, i); if ((i == pr_n) && (i < n - pr_n)) { - printf(" ... \n"); + fputs(" ... \n", stderr); } if ((i < pr_n) || (i >= n - pr_n)) { - printf( + fprintf(stderr, "Contents of slot: %lu: n_owned: %lu, rec offs: %lu\n", (ulong) i, (ulong) page_dir_slot_get_n_owned(slot), (ulong)(page_dir_slot_get_rec(slot) - page)); } } - printf("Total of %lu records\n", (ulong) (2 + page_get_n_recs(page))); - printf("--------------------------------\n"); + fprintf(stderr, "Total of %lu records\n" + "--------------------------------\n", + (ulong) (2 + page_get_n_recs(page))); } /******************************************************************* @@ -1180,21 +1180,20 @@ page_print_list( ulint pr_n) /* in: print n first and n last entries */ { page_cur_t cur; - rec_t* rec; ulint count; ulint n_recs; - printf("--------------------------------\n"); - printf("PAGE RECORD LIST\n"); - printf("Page address %lu\n", (ulong) page); + fprintf(stderr, + "--------------------------------\n" + "PAGE RECORD LIST\n" + "Page address %p\n", page); n_recs = page_get_n_recs(page); page_cur_set_before_first(page, &cur); count = 0; for (;;) { - rec = (&cur)->rec; - page_rec_print(rec); + page_rec_print(cur.rec); if (count == pr_n) { break; @@ -1207,24 +1206,22 @@ page_print_list( } if (n_recs > 2 * pr_n) { - printf(" ... \n"); + fputs(" ... \n", stderr); } - for (;;) { - if (page_cur_is_after_last(&cur)) { - break; - } + while (!page_cur_is_after_last(&cur)) { page_cur_move_to_next(&cur); if (count + pr_n >= n_recs) { - rec = (&cur)->rec; - page_rec_print(rec); + page_rec_print(cur.rec); } count++; } - printf("Total of %lu records \n", (ulong) (count + 1)); - printf("--------------------------------\n"); + fprintf(stderr, + "Total of %lu records \n" + "--------------------------------\n", + (ulong) (count + 1)); } /******************************************************************* @@ -1235,21 +1232,19 @@ page_header_print( /*==============*/ page_t* page) { - printf("--------------------------------\n"); - printf("PAGE HEADER INFO\n"); - printf("Page address %lx, n records %lu\n", (ulong) page, - (ulong) page_header_get_field(page, PAGE_N_RECS)); - - printf("n dir slots %lu, heap top %lu\n", + fprintf(stderr, + "--------------------------------\n" + "PAGE HEADER INFO\n" + "Page address %p, n records %lu\n" + "n dir slots %lu, heap top %lu\n" + "Page n heap %lu, free %lu, garbage %lu\n" + "Page last insert %lu, direction %lu, n direction %lu\n", + page, (ulong) page_header_get_field(page, PAGE_N_RECS), (ulong) page_header_get_field(page, PAGE_N_DIR_SLOTS), - (ulong) page_header_get_field(page, PAGE_HEAP_TOP)); - - printf("Page n heap %lu, free %lu, garbage %lu\n", + (ulong) page_header_get_field(page, PAGE_HEAP_TOP), (ulong) page_header_get_field(page, PAGE_N_HEAP), (ulong) page_header_get_field(page, PAGE_FREE), - (ulong) page_header_get_field(page, PAGE_GARBAGE)); - - printf("Page last insert %lu, direction %lu, n direction %lu\n", + (ulong) page_header_get_field(page, PAGE_GARBAGE), (ulong) page_header_get_field(page, PAGE_LAST_INSERT), (ulong) page_header_get_field(page, PAGE_DIRECTION), (ulong) page_header_get_field(page, PAGE_N_DIRECTION)); @@ -1559,17 +1554,9 @@ page_validate( ulint n_slots; ibool ret = FALSE; ulint i; - char err_buf[1000]; if (!page_simple_validate(page)) { - fprintf(stderr, -"InnoDB: Apparent corruption in page %lu in index %s in table %s\n", - (ulong) buf_frame_get_page_no(page), index->name, - index->table_name); - - buf_page_print(page); - - return(FALSE); + goto func_exit2; } heap = mem_heap_create(UNIV_PAGE_SIZE); @@ -1589,10 +1576,13 @@ page_validate( if (!(page_header_get_ptr(page, PAGE_HEAP_TOP) <= page_dir_get_nth_slot(page, n_slots - 1))) { - fprintf(stderr, -"InnoDB: Record heap and dir overlap on a page in index %s, %lu, %lu\n", - index->name, (ulong)page_header_get_ptr(page, PAGE_HEAP_TOP), - (ulong)page_dir_get_nth_slot(page, n_slots - 1)); + + fputs("InnoDB: Record heap and dir overlap on a page ", + stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, ", %p, %p\n", + page_header_get_ptr(page, PAGE_HEAP_TOP), + page_dir_get_nth_slot(page, n_slots - 1)); goto func_exit; } @@ -1608,7 +1598,7 @@ page_validate( page_cur_set_before_first(page, &cur); for (;;) { - rec = (&cur)->rec; + rec = cur.rec; if (!page_rec_validate(rec)) { goto func_exit; @@ -1618,18 +1608,14 @@ page_validate( if ((count >= 2) && (!page_cur_is_after_last(&cur))) { if (!(1 == cmp_rec_rec(rec, old_rec, index))) { fprintf(stderr, -"InnoDB: Records in wrong order on page %lu index %s table %s\n", - (ulong) buf_frame_get_page_no(page), - index->name, - index->table_name); - - rec_sprintf(err_buf, 900, old_rec); - fprintf(stderr, - "InnoDB: previous record %s\n", err_buf); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, - "InnoDB: record %s\n", err_buf); + "InnoDB: Records in wrong order on page %lu", + (ulong) buf_frame_get_page_no(page)); + dict_index_name_print(stderr, index); + fputs("\nInnoDB: previous record ", stderr); + rec_print(stderr, old_rec); + fputs("\nInnoDB: record ", stderr); + rec_print(stderr, rec); + putc('\n', stderr); goto func_exit; } @@ -1647,10 +1633,8 @@ page_validate( if (!buf[offs + i] == 0) { /* No other record may overlap this */ - fprintf(stderr, - "InnoDB: Record overlaps another in index %s \n", - index->name); - + fputs("InnoDB: Record overlaps another\n", + stderr); goto func_exit; } @@ -1661,19 +1645,16 @@ page_validate( /* This is a record pointed to by a dir slot */ if (rec_get_n_owned(rec) != own_count) { fprintf(stderr, - "InnoDB: Wrong owned count %lu, %lu, in index %s\n", + "InnoDB: Wrong owned count %lu, %lu\n", (ulong) rec_get_n_owned(rec), - (ulong) own_count, - index->name); - + (ulong) own_count); goto func_exit; } if (page_dir_slot_get_rec(slot) != rec) { - fprintf(stderr, - "InnoDB: Dir slot does not point to right rec in %s\n", - index->name); - + fputs( + "InnoDB: Dir slot does not point to right rec\n", + stderr); goto func_exit; } @@ -1693,9 +1674,8 @@ page_validate( if (rec_get_next_offs(rec) < FIL_PAGE_DATA || rec_get_next_offs(rec) >= UNIV_PAGE_SIZE) { fprintf(stderr, - "InnoDB: Next record offset wrong %lu in index %s\n", - (ulong) rec_get_next_offs(rec), index->name); - + "InnoDB: Next record offset wrong %lu\n", + (ulong) rec_get_next_offs(rec)); goto func_exit; } @@ -1706,24 +1686,20 @@ page_validate( } if (rec_get_n_owned(rec) == 0) { - fprintf(stderr, - "InnoDB: n owned is zero in index %s\n", index->name); - + fputs("InnoDB: n owned is zero\n", stderr); goto func_exit; } if (slot_no != n_slots - 1) { - fprintf(stderr, "InnoDB: n slots wrong %lu %lu in index %s\n", - (ulong) slot_no, (ulong) (n_slots - 1), index->name); + fprintf(stderr, "InnoDB: n slots wrong %lu %lu\n", + (ulong) slot_no, (ulong) (n_slots - 1)); goto func_exit; } if (page_header_get_field(page, PAGE_N_RECS) + 2 != count + 1) { - fprintf(stderr, "InnoDB: n recs wrong %lu %lu in index %s\n", + fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n", (ulong) page_header_get_field(page, PAGE_N_RECS) + 2, - (ulong) (count + 1), - index->name); - + (ulong) (count + 1)); goto func_exit; } @@ -1749,10 +1725,8 @@ page_validate( for (i = 0; i < rec_get_size(rec); i++) { if (buf[offs + i] != 0) { - fprintf(stderr, - "InnoDB: Record overlaps another in free list, index %s \n", - index->name); - + fputs( + "InnoDB: Record overlaps another in free list\n", stderr); goto func_exit; } @@ -1763,12 +1737,9 @@ page_validate( } if (page_header_get_field(page, PAGE_N_HEAP) != count + 1) { - - fprintf(stderr, - "InnoDB: N heap is wrong %lu %lu in index %s\n", + fprintf(stderr, "InnoDB: N heap is wrong %lu %lu\n", (ulong) page_header_get_field(page, PAGE_N_HEAP), - (ulong) count + 1, - index->name); + (ulong) count + 1); goto func_exit; } @@ -1778,11 +1749,11 @@ func_exit: mem_heap_free(heap); if (ret == FALSE) { - fprintf(stderr, -"InnoDB: Apparent corruption in page %lu in index %s in table %s\n", - (ulong) buf_frame_get_page_no(page), index->name, - index->table_name); - + func_exit2: + fprintf(stderr, "InnoDB: Apparent corruption in page %lu in ", + (ulong) buf_frame_get_page_no(page)); + dict_index_name_print(stderr, index); + putc('\n', stderr); buf_page_print(page); } @@ -1800,16 +1771,13 @@ page_find_rec_with_heap_no( ulint heap_no)/* in: heap number */ { page_cur_t cur; - rec_t* rec; page_cur_set_before_first(page, &cur); for (;;) { - rec = (&cur)->rec; - - if (rec_get_heap_no(rec) == heap_no) { + if (rec_get_heap_no(cur.rec) == heap_no) { - return(rec); + return(cur.rec); } if (page_cur_is_after_last(&cur)) { diff --git a/innobase/pars/lexyy.c b/innobase/pars/lexyy.c index f014200b2a6..638571ada97 100644 --- a/innobase/pars/lexyy.c +++ b/innobase/pars/lexyy.c @@ -8,7 +8,6 @@ #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 -#include "univ.i" #include <stdio.h> @@ -262,6 +261,9 @@ static void yy_flex_free YY_PROTO(( void * )); #define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +#define yywrap() 1 +#define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; @@ -285,48 +287,48 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); #define YY_NUM_RULES 107 #define YY_END_OF_BUFFER 108 -static yyconst short int yy_accept[366] = +static yyconst short int yy_accept[367] = { 0, - 0, 0, 100, 100, 108, 106, 105, 105, 95, 106, - 84, 90, 93, 91, 88, 92, 106, 94, 1, 106, - 89, 87, 85, 86, 98, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 96, 97, 100, 101, 102, 105, 0, - 3, 79, 99, 2, 1, 80, 81, 83, 82, 78, - 78, 78, 78, 78, 36, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 19, - 10, 16, 78, 78, 78, 78, 46, 53, 78, 7, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - - 78, 78, 78, 78, 78, 78, 78, 100, 101, 102, - 103, 102, 104, 2, 6, 37, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 18, 78, 78, 32, 78, 78, 78, - 12, 78, 78, 8, 78, 78, 78, 11, 78, 78, - 78, 78, 78, 72, 78, 78, 78, 43, 5, 78, - 27, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 15, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 38, 78, 78, 21, - 78, 78, 78, 30, 78, 78, 78, 78, 40, 78, - - 23, 78, 4, 56, 78, 78, 78, 34, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 20, 78, 78, - 78, 78, 78, 78, 78, 78, 77, 78, 17, 78, - 58, 78, 78, 78, 78, 28, 78, 78, 78, 78, - 78, 78, 78, 22, 57, 14, 49, 78, 67, 78, - 78, 78, 35, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 48, 78, 78, 78, 78, 78, 78, - 31, 24, 71, 78, 78, 75, 66, 78, 47, 78, - 55, 78, 44, 78, 78, 39, 78, 68, 78, 70, - 78, 78, 25, 78, 78, 78, 26, 64, 78, 78, - - 78, 78, 50, 42, 41, 78, 78, 78, 45, 54, - 78, 78, 13, 78, 78, 65, 73, 78, 78, 69, - 78, 60, 78, 78, 78, 78, 29, 78, 59, 78, - 76, 78, 78, 78, 78, 51, 78, 78, 9, 78, - 62, 61, 78, 33, 78, 74, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 63, 78, 78, 78, - 78, 78, 78, 52, 0 + 0, 0, 102, 102, 0, 0, 108, 106, 105, 105, + 97, 3, 86, 92, 95, 93, 90, 94, 106, 96, + 1, 106, 91, 89, 87, 88, 100, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 98, 99, 102, 103, 4, + 5, 105, 81, 101, 2, 1, 82, 83, 85, 84, + 80, 80, 80, 80, 80, 38, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 21, 12, 18, 80, 80, 80, 80, 48, 55, 80, + 9, 80, 80, 80, 80, 80, 80, 80, 80, 80, + + 80, 80, 80, 80, 80, 80, 80, 80, 102, 103, + 103, 104, 4, 5, 2, 8, 39, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 20, 80, 80, 34, 80, 80, + 80, 14, 80, 80, 10, 80, 80, 80, 13, 80, + 80, 80, 80, 80, 74, 80, 80, 80, 45, 7, + 80, 29, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 17, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 40, 80, 80, + 23, 80, 80, 80, 32, 80, 80, 80, 80, 42, + + 80, 25, 80, 6, 58, 80, 80, 80, 36, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 22, 80, + 80, 80, 80, 80, 80, 80, 80, 79, 80, 19, + 80, 60, 80, 80, 80, 80, 30, 80, 80, 80, + 80, 80, 80, 80, 24, 59, 16, 51, 80, 69, + 80, 80, 80, 37, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 50, 80, 80, 80, 80, 80, + 80, 33, 26, 73, 80, 80, 77, 68, 80, 49, + 80, 57, 80, 46, 80, 80, 41, 80, 70, 80, + 72, 80, 80, 27, 80, 80, 80, 28, 66, 80, + + 80, 80, 80, 52, 44, 43, 80, 80, 80, 47, + 56, 80, 80, 15, 80, 80, 67, 75, 80, 80, + 71, 80, 62, 80, 80, 80, 80, 31, 80, 61, + 80, 78, 80, 80, 80, 80, 53, 80, 80, 11, + 80, 64, 63, 80, 35, 80, 76, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 65, 80, 80, + 80, 80, 80, 80, 54, 0 } ; static yyconst int yy_ec[256] = @@ -363,205 +365,207 @@ static yyconst int yy_ec[256] = static yyconst int yy_meta[49] = { 0, - 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, - 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 1, 1 + 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, + 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 1, 1 } ; -static yyconst short int yy_base[371] = +static yyconst short int yy_base[373] = { 0, - 0, 0, 46, 47, 393, 394, 49, 54, 394, 387, - 394, 394, 394, 394, 394, 394, 379, 382, 46, 371, - 394, 43, 394, 370, 394, 25, 38, 37, 41, 39, - 49, 0, 51, 54, 45, 62, 349, 57, 68, 73, - 61, 365, 71, 394, 394, 382, 394, 99, 108, 379, - 394, 394, 394, 369, 102, 394, 394, 394, 394, 0, - 358, 81, 354, 346, 0, 358, 80, 84, 353, 339, - 96, 337, 350, 335, 349, 332, 336, 332, 334, 0, - 98, 0, 334, 332, 326, 333, 0, 0, 339, 339, - 322, 94, 103, 337, 98, 94, 328, 109, 320, 336, - - 332, 310, 326, 330, 321, 107, 314, 348, 394, 137, - 394, 141, 394, 336, 0, 0, 324, 319, 326, 308, - 306, 305, 310, 123, 308, 320, 109, 308, 314, 315, - 297, 297, 126, 0, 312, 313, 0, 300, 307, 28, - 128, 304, 294, 303, 296, 293, 301, 0, 291, 301, - 299, 290, 280, 274, 287, 272, 292, 0, 0, 277, - 0, 291, 282, 279, 134, 275, 290, 269, 271, 276, - 276, 268, 271, 266, 0, 278, 262, 272, 279, 270, - 258, 257, 271, 260, 273, 253, 0, 263, 245, 0, - 264, 261, 248, 0, 243, 248, 247, 257, 0, 243, - - 0, 247, 0, 0, 243, 240, 254, 0, 239, 239, - 237, 253, 238, 250, 232, 250, 245, 0, 240, 240, - 226, 225, 225, 239, 238, 237, 0, 221, 0, 215, - 0, 234, 218, 217, 217, 0, 230, 220, 215, 214, - 226, 216, 215, 0, 0, 0, 0, 208, 0, 222, - 218, 204, 0, 218, 219, 202, 207, 200, 218, 200, - 197, 198, 195, 0, 200, 212, 199, 206, 205, 190, - 0, 0, 0, 182, 189, 0, 0, 186, 0, 185, - 0, 199, 0, 200, 187, 0, 183, 0, 186, 0, - 178, 180, 0, 179, 193, 186, 0, 0, 189, 192, - - 174, 189, 0, 0, 0, 170, 184, 183, 0, 0, - 167, 166, 0, 181, 166, 0, 0, 172, 168, 0, - 163, 0, 175, 164, 174, 163, 0, 150, 0, 170, - 0, 154, 148, 154, 145, 0, 150, 163, 0, 162, - 0, 0, 153, 0, 157, 0, 144, 144, 150, 136, - 159, 147, 142, 132, 127, 118, 0, 128, 135, 126, - 123, 114, 88, 0, 394, 168, 171, 124, 174, 177 + 0, 0, 387, 386, 388, 387, 391, 396, 47, 49, + 396, 396, 396, 396, 396, 396, 396, 396, 378, 381, + 41, 370, 396, 38, 396, 369, 396, 20, 33, 32, + 36, 34, 44, 0, 46, 49, 40, 57, 348, 52, + 63, 68, 56, 364, 66, 396, 396, 0, 89, 0, + 379, 103, 396, 396, 369, 95, 396, 396, 396, 396, + 0, 358, 76, 354, 346, 0, 358, 75, 78, 353, + 339, 90, 337, 350, 335, 349, 332, 336, 332, 334, + 0, 93, 0, 334, 332, 326, 333, 0, 0, 339, + 339, 322, 85, 100, 337, 91, 86, 328, 102, 320, + + 336, 332, 310, 326, 330, 321, 102, 314, 0, 117, + 129, 396, 0, 346, 336, 0, 0, 324, 319, 326, + 308, 306, 305, 310, 105, 308, 320, 100, 308, 314, + 315, 297, 297, 116, 0, 312, 313, 0, 300, 307, + 118, 121, 304, 294, 303, 296, 293, 301, 0, 291, + 301, 299, 290, 280, 274, 287, 272, 292, 0, 0, + 277, 0, 291, 282, 279, 125, 275, 290, 269, 271, + 276, 276, 268, 271, 266, 0, 278, 262, 272, 279, + 270, 258, 257, 271, 260, 273, 253, 0, 263, 245, + 0, 264, 261, 248, 0, 243, 248, 247, 257, 0, + + 243, 0, 247, 0, 0, 243, 240, 254, 0, 239, + 239, 237, 253, 238, 250, 232, 250, 245, 0, 240, + 240, 226, 225, 225, 239, 238, 237, 0, 221, 0, + 215, 0, 234, 218, 217, 217, 0, 230, 220, 215, + 214, 226, 216, 215, 0, 0, 0, 0, 208, 0, + 222, 218, 204, 0, 218, 219, 202, 207, 200, 218, + 200, 197, 198, 195, 0, 200, 212, 199, 206, 205, + 190, 0, 0, 0, 182, 189, 0, 0, 186, 0, + 185, 0, 199, 0, 200, 187, 0, 183, 0, 186, + 0, 178, 180, 0, 179, 193, 186, 0, 0, 189, + + 192, 174, 189, 0, 0, 0, 170, 184, 183, 0, + 0, 167, 166, 0, 181, 166, 0, 0, 172, 168, + 0, 163, 0, 175, 164, 174, 163, 0, 150, 0, + 170, 0, 154, 148, 154, 145, 0, 150, 163, 0, + 162, 0, 0, 153, 0, 157, 0, 144, 144, 150, + 136, 159, 151, 152, 136, 119, 109, 0, 121, 128, + 119, 116, 112, 104, 0, 396, 159, 163, 59, 167, + 171, 175 } ; -static yyconst short int yy_def[371] = +static yyconst short int yy_def[373] = { 0, - 365, 1, 366, 366, 365, 365, 365, 365, 365, 367, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365, 365, 365, 365, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 365, 365, 369, 365, 370, 365, 367, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - - 368, 368, 368, 368, 368, 368, 368, 369, 365, 370, - 365, 370, 365, 365, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, - 368, 368, 368, 368, 0, 365, 365, 365, 365, 365 + 366, 1, 367, 367, 368, 368, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 366, 366, 370, 371, 372, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + + 369, 369, 369, 369, 369, 369, 369, 369, 370, 371, + 371, 366, 372, 366, 366, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, + 369, 369, 369, 369, 369, 0, 366, 366, 366, 366, + 366, 366 } ; -static yyconst short int yy_nxt[443] = +static yyconst short int yy_nxt[445] = { 0, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 32, 33, 32, - 32, 34, 32, 35, 36, 37, 32, 38, 39, 40, - 41, 42, 43, 32, 32, 32, 44, 45, 47, 47, - 49, 49, 196, 48, 48, 49, 49, 54, 61, 55, - 57, 58, 63, 62, 66, 71, 64, 197, 67, 72, - 74, 68, 75, 76, 69, 73, 80, 70, 83, 85, - 77, 93, 65, 78, 81, 86, 79, 87, 84, 82, - 94, 95, 96, 100, 103, 88, 104, 89, 106, 90, - - 101, 111, 91, 116, 97, 107, 112, 102, 98, 49, - 49, 113, 99, 54, 121, 55, 123, 124, 128, 117, - 122, 139, 149, 151, 125, 157, 60, 129, 150, 155, - 160, 169, 364, 158, 130, 170, 140, 141, 152, 111, - 156, 161, 153, 111, 365, 179, 183, 184, 112, 365, - 190, 363, 198, 113, 191, 219, 220, 362, 361, 360, - 359, 180, 199, 358, 357, 356, 355, 221, 46, 46, - 46, 50, 50, 50, 108, 354, 108, 110, 110, 110, - 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, - 343, 342, 341, 340, 339, 338, 337, 336, 335, 334, - - 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, - 323, 322, 321, 320, 319, 318, 317, 316, 315, 314, - 313, 312, 311, 310, 309, 308, 307, 306, 305, 304, - 303, 302, 301, 300, 299, 298, 297, 296, 295, 294, - 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, - 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, - 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, - 263, 262, 261, 260, 259, 258, 257, 256, 255, 254, - 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, - 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, - - 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, - 223, 222, 218, 217, 216, 215, 214, 213, 212, 211, - 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, - 200, 195, 194, 193, 192, 189, 188, 187, 186, 185, - 182, 181, 178, 177, 176, 175, 174, 173, 172, 114, - 109, 171, 168, 167, 166, 165, 164, 163, 162, 159, - 154, 148, 147, 146, 145, 144, 143, 142, 138, 137, - 136, 135, 134, 133, 132, 131, 127, 126, 120, 119, - 118, 115, 114, 51, 109, 105, 92, 59, 56, 53, - 52, 51, 365, 5, 365, 365, 365, 365, 365, 365, - - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365 + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 34, 35, 34, + 34, 36, 34, 37, 38, 39, 34, 40, 41, 42, + 43, 44, 45, 34, 34, 34, 46, 47, 52, 52, + 52, 52, 55, 62, 56, 58, 59, 64, 63, 67, + 72, 65, 61, 68, 73, 75, 69, 76, 77, 70, + 74, 81, 71, 84, 86, 78, 94, 66, 79, 82, + 87, 80, 88, 85, 83, 95, 96, 97, 101, 104, + 89, 105, 90, 107, 91, 102, 111, 92, 117, 98, + + 108, 112, 103, 99, 52, 52, 55, 100, 56, 122, + 124, 125, 129, 150, 118, 123, 140, 158, 126, 151, + 152, 130, 156, 161, 366, 159, 170, 180, 131, 366, + 171, 141, 142, 157, 162, 153, 111, 184, 185, 154, + 191, 112, 197, 181, 192, 199, 220, 221, 365, 364, + 363, 362, 361, 360, 359, 200, 358, 198, 222, 48, + 48, 48, 48, 50, 50, 50, 50, 109, 109, 357, + 109, 110, 110, 110, 110, 113, 356, 113, 113, 355, + 354, 353, 352, 351, 350, 349, 348, 347, 346, 345, + 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, + + 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, + 324, 323, 322, 321, 320, 319, 318, 317, 316, 315, + 314, 313, 312, 311, 310, 309, 308, 307, 306, 305, + 304, 303, 302, 301, 300, 299, 298, 297, 296, 295, + 294, 293, 292, 291, 290, 289, 288, 287, 286, 285, + 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, + 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, + 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, + 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, + 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, + + 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, + 224, 223, 219, 218, 217, 216, 215, 214, 213, 212, + 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, + 201, 196, 195, 194, 193, 190, 189, 188, 187, 186, + 183, 182, 179, 178, 177, 176, 175, 174, 173, 115, + 114, 172, 169, 168, 167, 166, 165, 164, 163, 160, + 155, 149, 148, 147, 146, 145, 144, 143, 139, 138, + 137, 136, 135, 134, 133, 132, 128, 127, 121, 120, + 119, 116, 115, 114, 106, 93, 60, 57, 54, 53, + 366, 51, 51, 49, 49, 7, 366, 366, 366, 366, + + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366 } ; -static yyconst short int yy_chk[443] = +static yyconst short int yy_chk[445] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, - 7, 7, 140, 3, 4, 8, 8, 19, 26, 19, - 22, 22, 27, 26, 28, 29, 27, 140, 28, 29, - 30, 28, 30, 31, 28, 29, 33, 28, 34, 35, - 31, 38, 27, 31, 33, 35, 31, 36, 34, 33, - 38, 38, 39, 40, 41, 36, 41, 36, 43, 36, - - 40, 48, 36, 62, 39, 43, 48, 40, 39, 49, - 49, 48, 39, 55, 67, 55, 68, 68, 71, 62, - 67, 81, 92, 93, 68, 96, 368, 71, 92, 95, - 98, 106, 363, 96, 71, 106, 81, 81, 93, 110, - 95, 98, 93, 112, 110, 124, 127, 127, 112, 110, - 133, 362, 141, 112, 133, 165, 165, 361, 360, 359, - 358, 124, 141, 356, 355, 354, 353, 165, 366, 366, - 366, 367, 367, 367, 369, 352, 369, 370, 370, 370, - 351, 350, 349, 348, 347, 345, 343, 340, 338, 337, - 335, 334, 333, 332, 330, 328, 326, 325, 324, 323, - - 321, 319, 318, 315, 314, 312, 311, 308, 307, 306, - 302, 301, 300, 299, 296, 295, 294, 292, 291, 289, - 287, 285, 284, 282, 280, 278, 275, 274, 270, 269, - 268, 267, 266, 265, 263, 262, 261, 260, 259, 258, - 257, 256, 255, 254, 252, 251, 250, 248, 243, 242, - 241, 240, 239, 238, 237, 235, 234, 233, 232, 230, - 228, 226, 225, 224, 223, 222, 221, 220, 219, 217, - 216, 215, 214, 213, 212, 211, 210, 209, 207, 206, - 205, 202, 200, 198, 197, 196, 195, 193, 192, 191, - 189, 188, 186, 185, 184, 183, 182, 181, 180, 179, - - 178, 177, 176, 174, 173, 172, 171, 170, 169, 168, - 167, 166, 164, 163, 162, 160, 157, 156, 155, 154, - 153, 152, 151, 150, 149, 147, 146, 145, 144, 143, - 142, 139, 138, 136, 135, 132, 131, 130, 129, 128, - 126, 125, 123, 122, 121, 120, 119, 118, 117, 114, - 108, 107, 105, 104, 103, 102, 101, 100, 99, 97, - 94, 91, 90, 89, 86, 85, 84, 83, 79, 78, - 77, 76, 75, 74, 73, 72, 70, 69, 66, 64, - 63, 61, 54, 50, 46, 42, 37, 24, 20, 18, - 17, 10, 5, 365, 365, 365, 365, 365, 365, 365, - - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365, 365, 365, 365, 365, 365, 365, 365, 365, - 365, 365 + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, + 10, 10, 21, 28, 21, 24, 24, 29, 28, 30, + 31, 29, 369, 30, 31, 32, 30, 32, 33, 30, + 31, 35, 30, 36, 37, 33, 40, 29, 33, 35, + 37, 33, 38, 36, 35, 40, 40, 41, 42, 43, + 38, 43, 38, 45, 38, 42, 49, 38, 63, 41, + + 45, 49, 42, 41, 52, 52, 56, 41, 56, 68, + 69, 69, 72, 93, 63, 68, 82, 97, 69, 93, + 94, 72, 96, 99, 110, 97, 107, 125, 72, 110, + 107, 82, 82, 96, 99, 94, 111, 128, 128, 94, + 134, 111, 141, 125, 134, 142, 166, 166, 364, 363, + 362, 361, 360, 359, 357, 142, 356, 141, 166, 367, + 367, 367, 367, 368, 368, 368, 368, 370, 370, 355, + 370, 371, 371, 371, 371, 372, 354, 372, 372, 353, + 352, 351, 350, 349, 348, 346, 344, 341, 339, 338, + 336, 335, 334, 333, 331, 329, 327, 326, 325, 324, + + 322, 320, 319, 316, 315, 313, 312, 309, 308, 307, + 303, 302, 301, 300, 297, 296, 295, 293, 292, 290, + 288, 286, 285, 283, 281, 279, 276, 275, 271, 270, + 269, 268, 267, 266, 264, 263, 262, 261, 260, 259, + 258, 257, 256, 255, 253, 252, 251, 249, 244, 243, + 242, 241, 240, 239, 238, 236, 235, 234, 233, 231, + 229, 227, 226, 225, 224, 223, 222, 221, 220, 218, + 217, 216, 215, 214, 213, 212, 211, 210, 208, 207, + 206, 203, 201, 199, 198, 197, 196, 194, 193, 192, + 190, 189, 187, 186, 185, 184, 183, 182, 181, 180, + + 179, 178, 177, 175, 174, 173, 172, 171, 170, 169, + 168, 167, 165, 164, 163, 161, 158, 157, 156, 155, + 154, 153, 152, 151, 150, 148, 147, 146, 145, 144, + 143, 140, 139, 137, 136, 133, 132, 131, 130, 129, + 127, 126, 124, 123, 122, 121, 120, 119, 118, 115, + 114, 108, 106, 105, 104, 103, 102, 101, 100, 98, + 95, 92, 91, 90, 87, 86, 85, 84, 80, 79, + 78, 77, 76, 75, 74, 73, 71, 70, 67, 65, + 64, 62, 55, 51, 44, 39, 26, 22, 20, 19, + 7, 6, 5, 4, 3, 366, 366, 366, 366, 366, + + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366, 366, 366, 366, 366, 366, 366, + 366, 366, 366, 366 } ; static yy_state_type yy_last_accepting_state; @@ -613,7 +617,13 @@ How to make the InnoDB parser and lexer C files: These instructions seem to work at least with bison-1.28 and flex-2.5.4 on Linux. *******************************************************/ -#line 36 "pars0lex.l" +#define YY_NEVER_INTERACTIVE 1 +#define YY_NO_INPUT 1 +#define YY_NO_UNPUT 1 +#define YY_NO_SCAN_BUFFER 1 +#define YY_NO_SCAN_BYTES 1 +#define YY_NO_SCAN_STRING 1 +#line 52 "pars0lex.l" #define YYSTYPE que_node_t* #include "univ.i" @@ -623,16 +633,46 @@ Linux. #include "mem0mem.h" #include "os0proc.h" -#define isatty(A) 0 #define malloc(A) mem_alloc(A) #define free(A) mem_free(A) #define realloc(P, A) mem_realloc(P, A, __FILE__, __LINE__) #define exit(A) ut_error #define YY_INPUT(buf, result, max_size) pars_get_lex_chars(buf, &result, max_size) + +/* String buffer for removing quotes */ +static ulint stringbuf_len_alloc = 0; /* Allocated length */ +static ulint stringbuf_len = 0; /* Current length */ +static char* stringbuf; /* Start of buffer */ +/* Appends a string to the buffer. */ +static +void +string_append( +/*==========*/ + const char* str, /* in: string to be appended */ + ulint len) /* in: length of the string */ +{ + if (stringbuf_len + len > stringbuf_len_alloc) { + if (stringbuf_len_alloc == 0) { + stringbuf_len_alloc++; + } + while (stringbuf_len + len > stringbuf_len_alloc) { + stringbuf_len_alloc <<= 1; + } + stringbuf = stringbuf + ? realloc(stringbuf, stringbuf_len_alloc) + : malloc(stringbuf_len_alloc); + } + + memcpy(stringbuf + stringbuf_len, str, len); + stringbuf_len += len; +} + #define comment 1 -#line 632 "lex.yy.c" +#define quoted 2 + +#line 676 "lex.yy.c" /* Macros after this point can all be overridden by user definitions in * section 1. @@ -783,10 +823,10 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; -#line 57 "pars0lex.l" +#line 102 "pars0lex.l" -#line 786 "lex.yy.c" +#line 830 "lex.yy.c" if ( yy_init ) { @@ -837,13 +877,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 366 ) + if ( yy_current_state >= 367 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 394 ); + while ( yy_base[yy_current_state] != 396 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -871,7 +911,7 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 59 "pars0lex.l" +#line 104 "pars0lex.l" { yylval = sym_tab_add_int_lit(pars_sym_tab_global, atoi(yytext)); @@ -880,7 +920,7 @@ YY_RULE_SETUP YY_BREAK case 2: YY_RULE_SETUP -#line 65 "pars0lex.l" +#line 110 "pars0lex.l" { ut_error; /* not implemented */ @@ -889,542 +929,556 @@ YY_RULE_SETUP YY_BREAK case 3: YY_RULE_SETUP -#line 71 "pars0lex.l" +#line 116 "pars0lex.l" { - /* Remove the single quotes around the string */ - - yylval = sym_tab_add_str_lit(pars_sym_tab_global, - (byte*)yytext, - ut_strlen(yytext)); - return(PARS_STR_LIT); + BEGIN(quoted); + stringbuf_len = 0; } YY_BREAK case 4: YY_RULE_SETUP -#line 80 "pars0lex.l" +#line 120 "pars0lex.l" +string_append(yytext, yyleng); + YY_BREAK +case 5: +YY_RULE_SETUP +#line 121 "pars0lex.l" +{ string_append(yytext, yyleng / 2); + if (yyleng % 2) { + BEGIN(INITIAL); + yylval = sym_tab_add_str_lit( + pars_sym_tab_global, + stringbuf, stringbuf_len); + return(PARS_STR_LIT); + } +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 131 "pars0lex.l" { yylval = sym_tab_add_null_lit(pars_sym_tab_global); return(PARS_NULL_LIT); } YY_BREAK -case 5: +case 7: YY_RULE_SETUP -#line 86 "pars0lex.l" +#line 137 "pars0lex.l" { /* Implicit cursor name */ yylval = sym_tab_add_str_lit(pars_sym_tab_global, - (byte*)"\'SQL\'", 5); + yytext, yyleng); return(PARS_SQL_TOKEN); } YY_BREAK -case 6: +case 8: YY_RULE_SETUP -#line 93 "pars0lex.l" +#line 144 "pars0lex.l" { return(PARS_AND_TOKEN); } YY_BREAK -case 7: +case 9: YY_RULE_SETUP -#line 97 "pars0lex.l" +#line 148 "pars0lex.l" { return(PARS_OR_TOKEN); } YY_BREAK -case 8: +case 10: YY_RULE_SETUP -#line 101 "pars0lex.l" +#line 152 "pars0lex.l" { return(PARS_NOT_TOKEN); } YY_BREAK -case 9: +case 11: YY_RULE_SETUP -#line 105 "pars0lex.l" +#line 156 "pars0lex.l" { return(PARS_PROCEDURE_TOKEN); } YY_BREAK -case 10: +case 12: YY_RULE_SETUP -#line 109 "pars0lex.l" +#line 160 "pars0lex.l" { return(PARS_IN_TOKEN); } YY_BREAK -case 11: +case 13: YY_RULE_SETUP -#line 113 "pars0lex.l" +#line 164 "pars0lex.l" { return(PARS_OUT_TOKEN); } YY_BREAK -case 12: +case 14: YY_RULE_SETUP -#line 117 "pars0lex.l" +#line 168 "pars0lex.l" { return(PARS_INT_TOKEN); } YY_BREAK -case 13: +case 15: YY_RULE_SETUP -#line 121 "pars0lex.l" +#line 172 "pars0lex.l" { return(PARS_INT_TOKEN); } YY_BREAK -case 14: +case 16: YY_RULE_SETUP -#line 125 "pars0lex.l" +#line 176 "pars0lex.l" { return(PARS_FLOAT_TOKEN); } YY_BREAK -case 15: +case 17: YY_RULE_SETUP -#line 129 "pars0lex.l" +#line 180 "pars0lex.l" { return(PARS_CHAR_TOKEN); } YY_BREAK -case 16: +case 18: YY_RULE_SETUP -#line 133 "pars0lex.l" +#line 184 "pars0lex.l" { return(PARS_IS_TOKEN); } YY_BREAK -case 17: +case 19: YY_RULE_SETUP -#line 137 "pars0lex.l" +#line 188 "pars0lex.l" { return(PARS_BEGIN_TOKEN); } YY_BREAK -case 18: +case 20: YY_RULE_SETUP -#line 141 "pars0lex.l" +#line 192 "pars0lex.l" { return(PARS_END_TOKEN); } YY_BREAK -case 19: +case 21: YY_RULE_SETUP -#line 145 "pars0lex.l" +#line 196 "pars0lex.l" { return(PARS_IF_TOKEN); } YY_BREAK -case 20: +case 22: YY_RULE_SETUP -#line 149 "pars0lex.l" +#line 200 "pars0lex.l" { return(PARS_THEN_TOKEN); } YY_BREAK -case 21: +case 23: YY_RULE_SETUP -#line 153 "pars0lex.l" +#line 204 "pars0lex.l" { return(PARS_ELSE_TOKEN); } YY_BREAK -case 22: +case 24: YY_RULE_SETUP -#line 157 "pars0lex.l" +#line 208 "pars0lex.l" { return(PARS_ELSIF_TOKEN); } YY_BREAK -case 23: +case 25: YY_RULE_SETUP -#line 161 "pars0lex.l" +#line 212 "pars0lex.l" { return(PARS_LOOP_TOKEN); } YY_BREAK -case 24: +case 26: YY_RULE_SETUP -#line 165 "pars0lex.l" +#line 216 "pars0lex.l" { return(PARS_WHILE_TOKEN); } YY_BREAK -case 25: +case 27: YY_RULE_SETUP -#line 169 "pars0lex.l" +#line 220 "pars0lex.l" { return(PARS_RETURN_TOKEN); } YY_BREAK -case 26: +case 28: YY_RULE_SETUP -#line 173 "pars0lex.l" +#line 224 "pars0lex.l" { return(PARS_SELECT_TOKEN); } YY_BREAK -case 27: +case 29: YY_RULE_SETUP -#line 177 "pars0lex.l" +#line 228 "pars0lex.l" { return(PARS_SUM_TOKEN); } YY_BREAK -case 28: +case 30: YY_RULE_SETUP -#line 181 "pars0lex.l" +#line 232 "pars0lex.l" { return(PARS_COUNT_TOKEN); } YY_BREAK -case 29: +case 31: YY_RULE_SETUP -#line 185 "pars0lex.l" +#line 236 "pars0lex.l" { return(PARS_DISTINCT_TOKEN); } YY_BREAK -case 30: +case 32: YY_RULE_SETUP -#line 189 "pars0lex.l" +#line 240 "pars0lex.l" { return(PARS_FROM_TOKEN); } YY_BREAK -case 31: +case 33: YY_RULE_SETUP -#line 193 "pars0lex.l" +#line 244 "pars0lex.l" { return(PARS_WHERE_TOKEN); } YY_BREAK -case 32: +case 34: YY_RULE_SETUP -#line 197 "pars0lex.l" +#line 248 "pars0lex.l" { return(PARS_FOR_TOKEN); } YY_BREAK -case 33: +case 35: YY_RULE_SETUP -#line 201 "pars0lex.l" +#line 252 "pars0lex.l" { return(PARS_CONSISTENT_TOKEN); } YY_BREAK -case 34: +case 36: YY_RULE_SETUP -#line 205 "pars0lex.l" +#line 256 "pars0lex.l" { return(PARS_READ_TOKEN); } YY_BREAK -case 35: +case 37: YY_RULE_SETUP -#line 209 "pars0lex.l" +#line 260 "pars0lex.l" { return(PARS_ORDER_TOKEN); } YY_BREAK -case 36: +case 38: YY_RULE_SETUP -#line 213 "pars0lex.l" +#line 264 "pars0lex.l" { return(PARS_BY_TOKEN); } YY_BREAK -case 37: +case 39: YY_RULE_SETUP -#line 217 "pars0lex.l" +#line 268 "pars0lex.l" { return(PARS_ASC_TOKEN); } YY_BREAK -case 38: +case 40: YY_RULE_SETUP -#line 221 "pars0lex.l" +#line 272 "pars0lex.l" { return(PARS_DESC_TOKEN); } YY_BREAK -case 39: +case 41: YY_RULE_SETUP -#line 225 "pars0lex.l" +#line 276 "pars0lex.l" { return(PARS_INSERT_TOKEN); } YY_BREAK -case 40: +case 42: YY_RULE_SETUP -#line 229 "pars0lex.l" +#line 280 "pars0lex.l" { return(PARS_INTO_TOKEN); } YY_BREAK -case 41: +case 43: YY_RULE_SETUP -#line 233 "pars0lex.l" +#line 284 "pars0lex.l" { return(PARS_VALUES_TOKEN); } YY_BREAK -case 42: +case 44: YY_RULE_SETUP -#line 237 "pars0lex.l" +#line 288 "pars0lex.l" { return(PARS_UPDATE_TOKEN); } YY_BREAK -case 43: +case 45: YY_RULE_SETUP -#line 241 "pars0lex.l" +#line 292 "pars0lex.l" { return(PARS_SET_TOKEN); } YY_BREAK -case 44: +case 46: YY_RULE_SETUP -#line 245 "pars0lex.l" +#line 296 "pars0lex.l" { return(PARS_DELETE_TOKEN); } YY_BREAK -case 45: +case 47: YY_RULE_SETUP -#line 249 "pars0lex.l" +#line 300 "pars0lex.l" { return(PARS_CURRENT_TOKEN); } YY_BREAK -case 46: +case 48: YY_RULE_SETUP -#line 253 "pars0lex.l" +#line 304 "pars0lex.l" { return(PARS_OF_TOKEN); } YY_BREAK -case 47: +case 49: YY_RULE_SETUP -#line 257 "pars0lex.l" +#line 308 "pars0lex.l" { return(PARS_CREATE_TOKEN); } YY_BREAK -case 48: +case 50: YY_RULE_SETUP -#line 261 "pars0lex.l" +#line 312 "pars0lex.l" { return(PARS_TABLE_TOKEN); } YY_BREAK -case 49: +case 51: YY_RULE_SETUP -#line 265 "pars0lex.l" +#line 316 "pars0lex.l" { return(PARS_INDEX_TOKEN); } YY_BREAK -case 50: +case 52: YY_RULE_SETUP -#line 269 "pars0lex.l" +#line 320 "pars0lex.l" { return(PARS_UNIQUE_TOKEN); } YY_BREAK -case 51: +case 53: YY_RULE_SETUP -#line 273 "pars0lex.l" +#line 324 "pars0lex.l" { return(PARS_CLUSTERED_TOKEN); } YY_BREAK -case 52: +case 54: YY_RULE_SETUP -#line 277 "pars0lex.l" +#line 328 "pars0lex.l" { return(PARS_DOES_NOT_FIT_IN_MEM_TOKEN); } YY_BREAK -case 53: +case 55: YY_RULE_SETUP -#line 281 "pars0lex.l" +#line 332 "pars0lex.l" { return(PARS_ON_TOKEN); } YY_BREAK -case 54: +case 56: YY_RULE_SETUP -#line 285 "pars0lex.l" +#line 336 "pars0lex.l" { return(PARS_DECLARE_TOKEN); } YY_BREAK -case 55: +case 57: YY_RULE_SETUP -#line 289 "pars0lex.l" +#line 340 "pars0lex.l" { return(PARS_CURSOR_TOKEN); } YY_BREAK -case 56: +case 58: YY_RULE_SETUP -#line 293 "pars0lex.l" +#line 344 "pars0lex.l" { return(PARS_OPEN_TOKEN); } YY_BREAK -case 57: +case 59: YY_RULE_SETUP -#line 297 "pars0lex.l" +#line 348 "pars0lex.l" { return(PARS_FETCH_TOKEN); } YY_BREAK -case 58: +case 60: YY_RULE_SETUP -#line 301 "pars0lex.l" +#line 352 "pars0lex.l" { return(PARS_CLOSE_TOKEN); } YY_BREAK -case 59: +case 61: YY_RULE_SETUP -#line 305 "pars0lex.l" +#line 356 "pars0lex.l" { return(PARS_NOTFOUND_TOKEN); } YY_BREAK -case 60: +case 62: YY_RULE_SETUP -#line 309 "pars0lex.l" +#line 360 "pars0lex.l" { return(PARS_TO_CHAR_TOKEN); } YY_BREAK -case 61: +case 63: YY_RULE_SETUP -#line 313 "pars0lex.l" +#line 364 "pars0lex.l" { return(PARS_TO_NUMBER_TOKEN); } YY_BREAK -case 62: +case 64: YY_RULE_SETUP -#line 317 "pars0lex.l" +#line 368 "pars0lex.l" { return(PARS_TO_BINARY_TOKEN); } YY_BREAK -case 63: +case 65: YY_RULE_SETUP -#line 321 "pars0lex.l" +#line 372 "pars0lex.l" { return(PARS_BINARY_TO_NUMBER_TOKEN); } YY_BREAK -case 64: +case 66: YY_RULE_SETUP -#line 325 "pars0lex.l" +#line 376 "pars0lex.l" { return(PARS_SUBSTR_TOKEN); } YY_BREAK -case 65: +case 67: YY_RULE_SETUP -#line 329 "pars0lex.l" +#line 380 "pars0lex.l" { return(PARS_REPLSTR_TOKEN); } YY_BREAK -case 66: +case 68: YY_RULE_SETUP -#line 333 "pars0lex.l" +#line 384 "pars0lex.l" { return(PARS_CONCAT_TOKEN); } YY_BREAK -case 67: +case 69: YY_RULE_SETUP -#line 337 "pars0lex.l" +#line 388 "pars0lex.l" { return(PARS_INSTR_TOKEN); } YY_BREAK -case 68: +case 70: YY_RULE_SETUP -#line 341 "pars0lex.l" +#line 392 "pars0lex.l" { return(PARS_LENGTH_TOKEN); } YY_BREAK -case 69: +case 71: YY_RULE_SETUP -#line 345 "pars0lex.l" +#line 396 "pars0lex.l" { return(PARS_SYSDATE_TOKEN); } YY_BREAK -case 70: +case 72: YY_RULE_SETUP -#line 349 "pars0lex.l" +#line 400 "pars0lex.l" { return(PARS_PRINTF_TOKEN); } YY_BREAK -case 71: +case 73: YY_RULE_SETUP -#line 353 "pars0lex.l" +#line 404 "pars0lex.l" { return(PARS_ASSERT_TOKEN); } YY_BREAK -case 72: +case 74: YY_RULE_SETUP -#line 357 "pars0lex.l" +#line 408 "pars0lex.l" { return(PARS_RND_TOKEN); } YY_BREAK -case 73: +case 75: YY_RULE_SETUP -#line 361 "pars0lex.l" +#line 412 "pars0lex.l" { return(PARS_RND_STR_TOKEN); } YY_BREAK -case 74: +case 76: YY_RULE_SETUP -#line 365 "pars0lex.l" +#line 416 "pars0lex.l" { return(PARS_ROW_PRINTF_TOKEN); } YY_BREAK -case 75: +case 77: YY_RULE_SETUP -#line 369 "pars0lex.l" +#line 420 "pars0lex.l" { return(PARS_COMMIT_TOKEN); } YY_BREAK -case 76: +case 78: YY_RULE_SETUP -#line 373 "pars0lex.l" +#line 424 "pars0lex.l" { return(PARS_ROLLBACK_TOKEN); } YY_BREAK -case 77: +case 79: YY_RULE_SETUP -#line 377 "pars0lex.l" +#line 428 "pars0lex.l" { return(PARS_WORK_TOKEN); } YY_BREAK -case 78: +case 80: YY_RULE_SETUP -#line 381 "pars0lex.l" +#line 432 "pars0lex.l" { yylval = sym_tab_add_id(pars_sym_tab_global, (byte*)yytext, @@ -1432,60 +1486,44 @@ YY_RULE_SETUP return(PARS_ID_TOKEN); } YY_BREAK -case 79: -YY_RULE_SETUP -#line 388 "pars0lex.l" -{ - return(PARS_DDOT_TOKEN); -} - YY_BREAK -case 80: -YY_RULE_SETUP -#line 392 "pars0lex.l" -{ - return(PARS_ASSIGN_TOKEN); -} - YY_BREAK case 81: YY_RULE_SETUP -#line 396 "pars0lex.l" +#line 439 "pars0lex.l" { - return(PARS_LE_TOKEN); + return(PARS_DDOT_TOKEN); } YY_BREAK case 82: YY_RULE_SETUP -#line 400 "pars0lex.l" +#line 443 "pars0lex.l" { - return(PARS_GE_TOKEN); + return(PARS_ASSIGN_TOKEN); } YY_BREAK case 83: YY_RULE_SETUP -#line 404 "pars0lex.l" +#line 447 "pars0lex.l" { - return(PARS_NE_TOKEN); + return(PARS_LE_TOKEN); } YY_BREAK case 84: YY_RULE_SETUP -#line 408 "pars0lex.l" +#line 451 "pars0lex.l" { - - return((int)(*yytext)); + return(PARS_GE_TOKEN); } YY_BREAK case 85: YY_RULE_SETUP -#line 413 "pars0lex.l" +#line 455 "pars0lex.l" { - - return((int)(*yytext)); + return(PARS_NE_TOKEN); } YY_BREAK case 86: YY_RULE_SETUP -#line 418 "pars0lex.l" +#line 459 "pars0lex.l" { return((int)(*yytext)); @@ -1493,7 +1531,7 @@ YY_RULE_SETUP YY_BREAK case 87: YY_RULE_SETUP -#line 423 "pars0lex.l" +#line 464 "pars0lex.l" { return((int)(*yytext)); @@ -1501,7 +1539,7 @@ YY_RULE_SETUP YY_BREAK case 88: YY_RULE_SETUP -#line 428 "pars0lex.l" +#line 469 "pars0lex.l" { return((int)(*yytext)); @@ -1509,7 +1547,7 @@ YY_RULE_SETUP YY_BREAK case 89: YY_RULE_SETUP -#line 433 "pars0lex.l" +#line 474 "pars0lex.l" { return((int)(*yytext)); @@ -1517,7 +1555,7 @@ YY_RULE_SETUP YY_BREAK case 90: YY_RULE_SETUP -#line 438 "pars0lex.l" +#line 479 "pars0lex.l" { return((int)(*yytext)); @@ -1525,7 +1563,7 @@ YY_RULE_SETUP YY_BREAK case 91: YY_RULE_SETUP -#line 443 "pars0lex.l" +#line 484 "pars0lex.l" { return((int)(*yytext)); @@ -1533,7 +1571,7 @@ YY_RULE_SETUP YY_BREAK case 92: YY_RULE_SETUP -#line 448 "pars0lex.l" +#line 489 "pars0lex.l" { return((int)(*yytext)); @@ -1541,7 +1579,7 @@ YY_RULE_SETUP YY_BREAK case 93: YY_RULE_SETUP -#line 453 "pars0lex.l" +#line 494 "pars0lex.l" { return((int)(*yytext)); @@ -1549,7 +1587,7 @@ YY_RULE_SETUP YY_BREAK case 94: YY_RULE_SETUP -#line 458 "pars0lex.l" +#line 499 "pars0lex.l" { return((int)(*yytext)); @@ -1557,7 +1595,7 @@ YY_RULE_SETUP YY_BREAK case 95: YY_RULE_SETUP -#line 463 "pars0lex.l" +#line 504 "pars0lex.l" { return((int)(*yytext)); @@ -1565,7 +1603,7 @@ YY_RULE_SETUP YY_BREAK case 96: YY_RULE_SETUP -#line 468 "pars0lex.l" +#line 509 "pars0lex.l" { return((int)(*yytext)); @@ -1573,7 +1611,7 @@ YY_RULE_SETUP YY_BREAK case 97: YY_RULE_SETUP -#line 473 "pars0lex.l" +#line 514 "pars0lex.l" { return((int)(*yytext)); @@ -1581,7 +1619,7 @@ YY_RULE_SETUP YY_BREAK case 98: YY_RULE_SETUP -#line 478 "pars0lex.l" +#line 519 "pars0lex.l" { return((int)(*yytext)); @@ -1589,44 +1627,51 @@ YY_RULE_SETUP YY_BREAK case 99: YY_RULE_SETUP -#line 483 "pars0lex.l" -BEGIN(comment); /* eat up comment */ +#line 524 "pars0lex.l" +{ + + return((int)(*yytext)); +} YY_BREAK case 100: YY_RULE_SETUP -#line 485 "pars0lex.l" +#line 529 "pars0lex.l" +{ + return((int)(*yytext)); +} YY_BREAK case 101: YY_RULE_SETUP -#line 486 "pars0lex.l" - +#line 534 "pars0lex.l" +BEGIN(comment); /* eat up comment */ YY_BREAK case 102: YY_RULE_SETUP -#line 487 "pars0lex.l" +#line 536 "pars0lex.l" YY_BREAK case 103: YY_RULE_SETUP -#line 488 "pars0lex.l" +#line 537 "pars0lex.l" YY_BREAK case 104: YY_RULE_SETUP -#line 489 "pars0lex.l" +#line 538 "pars0lex.l" BEGIN(INITIAL); YY_BREAK case 105: YY_RULE_SETUP -#line 491 "pars0lex.l" +#line 540 "pars0lex.l" /* eat up whitespace */ YY_BREAK case 106: YY_RULE_SETUP -#line 494 "pars0lex.l" +#line 543 "pars0lex.l" { - printf("Unrecognized character: %s\n", yytext); + fprintf(stderr,"Unrecognized character: %02x\n", + *yytext); ut_error; @@ -1635,12 +1680,13 @@ YY_RULE_SETUP YY_BREAK case 107: YY_RULE_SETUP -#line 502 "pars0lex.l" -ECHO; +#line 552 "pars0lex.l" +YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK -#line 1638 "lex.yy.c" +#line 1687 "lex.yy.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(comment): +case YY_STATE_EOF(quoted): yyterminate(); case YY_END_OF_BUFFER: @@ -1931,7 +1977,7 @@ static yy_state_type yy_get_previous_state() while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 366 ) + if ( yy_current_state >= 367 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1966,11 +2012,11 @@ yy_state_type yy_current_state; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 366 ) + if ( yy_current_state >= 367 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 365); + yy_is_jam = (yy_current_state == 366); return yy_is_jam ? 0 : yy_current_state; } @@ -2205,7 +2251,7 @@ YY_BUFFER_STATE b; #ifndef YY_ALWAYS_INTERACTIVE #ifndef YY_NEVER_INTERACTIVE - +extern int isatty YY_PROTO(( int )); #endif #endif @@ -2525,5 +2571,5 @@ int main() return 0; } #endif -#line 502 "pars0lex.l" +#line 552 "pars0lex.l" diff --git a/innobase/pars/pars0lex.l b/innobase/pars/pars0lex.l index 97875ffcc45..7b65770b3da 100644 --- a/innobase/pars/pars0lex.l +++ b/innobase/pars/pars0lex.l @@ -35,6 +35,19 @@ These instructions seem to work at least with bison-1.28 and flex-2.5.4 on Linux. *******************************************************/ +%option nostdinit +%option 8bit +%option warn +%option pointer +%option never-interactive +%option nodefault +%option noinput +%option nounput +%option noyywrap +%option noyy_scan_buffer +%option noyy_scan_bytes +%option noyy_scan_string + %{ #define YYSTYPE que_node_t* @@ -45,18 +58,47 @@ Linux. #include "mem0mem.h" #include "os0proc.h" -#define isatty(A) 0 #define malloc(A) mem_alloc(A) #define free(A) mem_free(A) #define realloc(P, A) mem_realloc(P, A, __FILE__, __LINE__) -#define exit(A) ut_a(0) +#define exit(A) ut_error #define YY_INPUT(buf, result, max_size) pars_get_lex_chars(buf, &result, max_size) + +/* String buffer for removing quotes */ +static ulint stringbuf_len_alloc = 0; /* Allocated length */ +static ulint stringbuf_len = 0; /* Current length */ +static char* stringbuf; /* Start of buffer */ +/* Appends a string to the buffer. */ +static +void +string_append( +/*==========*/ + const char* str, /* in: string to be appended */ + ulint len) /* in: length of the string */ +{ + if (stringbuf_len + len > stringbuf_len_alloc) { + if (stringbuf_len_alloc == 0) { + stringbuf_len_alloc++; + } + while (stringbuf_len + len > stringbuf_len_alloc) { + stringbuf_len_alloc <<= 1; + } + stringbuf = stringbuf + ? realloc(stringbuf, stringbuf_len_alloc) + : malloc(stringbuf_len_alloc); + } + + memcpy(stringbuf + stringbuf_len, str, len); + stringbuf_len += len; +} + %} DIGIT [0-9] ID [a-z_A-Z][a-z_A-Z0-9]* %x comment +%x quoted %% {DIGIT}+ { @@ -71,13 +113,19 @@ ID [a-z_A-Z][a-z_A-Z0-9]* return(PARS_FLOAT_LIT); } -"\'"[^\']*"\'" { - /* Remove the single quotes around the string */ - - yylval = sym_tab_add_str_lit(pars_sym_tab_global, - (byte*)yytext, - ut_strlen(yytext)); - return(PARS_STR_LIT); +"'" { + BEGIN(quoted); + stringbuf_len = 0; +} +<quoted>[^\']+ string_append(yytext, yyleng); +<quoted>"'"+ { string_append(yytext, yyleng / 2); + if (yyleng % 2) { + BEGIN(INITIAL); + yylval = sym_tab_add_str_lit( + pars_sym_tab_global, + stringbuf, stringbuf_len); + return(PARS_STR_LIT); + } } "NULL" { @@ -89,7 +137,7 @@ ID [a-z_A-Z][a-z_A-Z0-9]* "SQL" { /* Implicit cursor name */ yylval = sym_tab_add_str_lit(pars_sym_tab_global, - (byte*)"\'SQL\'", 5); + yytext, yyleng); return(PARS_SQL_TOKEN); } @@ -485,17 +533,16 @@ ID [a-z_A-Z][a-z_A-Z0-9]* "/*" BEGIN(comment); /* eat up comment */ -<comment>[^*\n]* -<comment>[^*\n]*\n -<comment>"*"+[^*/\n]* -<comment>"*"+[^*/\n]*\n +<comment>[^*]* +<comment>"*"+[^*/]* <comment>"*"+"/" BEGIN(INITIAL); [ \t\n]+ /* eat up whitespace */ . { - printf("Unrecognized character: %s\n", yytext); + fprintf(stderr,"Unrecognized character: %02x\n", + *yytext); ut_error; diff --git a/innobase/pars/pars0opt.c b/innobase/pars/pars0opt.c index 9b0495a01cd..4fb0c937f1e 100644 --- a/innobase/pars/pars0opt.c +++ b/innobase/pars/pars0opt.c @@ -532,8 +532,8 @@ opt_search_plan_for_table( ulint best_goodness; ulint best_last_op = 0; /* remove warning */ ulint mix_id_pos; - que_node_t* index_plan[128]; - que_node_t* best_index_plan[128]; + que_node_t* index_plan[256]; + que_node_t* best_index_plan[256]; plan = sel_node_get_nth_plan(sel_node, i); @@ -1190,6 +1190,7 @@ opt_search_plan( #endif } +#ifdef UNIV_SQL_DEBUG /************************************************************************ Prints info of a query plan. */ @@ -1202,26 +1203,22 @@ opt_print_query_plan( ulint n_fields; ulint i; - printf("QUERY PLAN FOR A SELECT NODE\n"); + fputs("QUERY PLAN FOR A SELECT NODE\n", stderr); - if (sel_node->asc) { - printf("Asc. search; "); - } else { - printf("Desc. search; "); - } + fputs(sel_node->asc ? "Asc. search; " : "Desc. search; ", stderr); if (sel_node->set_x_locks) { - printf("sets row x-locks; "); + fputs("sets row x-locks; ", stderr); ut_a(sel_node->row_lock_mode == LOCK_X); ut_a(!sel_node->consistent_read); } else if (sel_node->consistent_read) { - printf("consistent read; "); + fputs("consistent read; ", stderr); } else { ut_a(sel_node->row_lock_mode == LOCK_S); - printf("sets row s-locks; "); + fputs("sets row s-locks; ", stderr); } - printf("\n"); + putc('\n', stderr); for (i = 0; i < sel_node->n_tables; i++) { plan = sel_node_get_nth_plan(sel_node, i); @@ -1232,11 +1229,12 @@ opt_print_query_plan( n_fields = 0; } - printf( - "Table %s index %s; exact m. %lu, match %lu, end conds %lu\n", - plan->table->name, plan->index->name, + fputs("Table ", stderr); + dict_index_name_print(stderr, plan->index); + fprintf(stderr,"; exact m. %lu, match %lu, end conds %lu\n", (unsigned long) plan->n_exact_match, (unsigned long) n_fields, (unsigned long) UT_LIST_GET_LEN(plan->end_conds)); } } +#endif /* UNIV_SQL_DEBUG */ diff --git a/innobase/pars/pars0pars.c b/innobase/pars/pars0pars.c index 5bbfca831f2..a4124672df0 100644 --- a/innobase/pars/pars0pars.c +++ b/innobase/pars/pars0pars.c @@ -1708,17 +1708,6 @@ pars_get_lex_chars( } /***************************************************************** -Instructs the lexical analyzer to stop when it receives the EOF integer. */ - -int -yywrap(void) -/*========*/ - /* out: returns TRUE */ -{ - return(1); -} - -/***************************************************************** Called by yyparse on error. */ void @@ -1745,8 +1734,6 @@ pars_sql( sym_node_t* sym_node; mem_heap_t* heap; que_t* graph; - ulint len; - char* buf; ut_ad(str); @@ -1758,12 +1745,8 @@ pars_sql( #endif /* UNIV_SYNC_DEBUG */ pars_sym_tab_global = sym_tab_create(heap); - len = ut_strlen(str); - buf = mem_heap_alloc(heap, len + 1); - ut_memcpy(buf, str, len + 1); - - pars_sym_tab_global->sql_string = buf; - pars_sym_tab_global->string_len = len; + pars_sym_tab_global->sql_string = mem_heap_strdup(heap, str); + pars_sym_tab_global->string_len = strlen(str); pars_sym_tab_global->next_char_pos = 0; yyparse(); diff --git a/innobase/pars/pars0sym.c b/innobase/pars/pars0sym.c index 5d8fa306b2d..1a0608ed142 100644 --- a/innobase/pars/pars0sym.c +++ b/innobase/pars/pars0sym.c @@ -127,19 +127,13 @@ sym_tab_add_str_lit( /*================*/ /* out: symbol table node */ sym_tab_t* sym_tab, /* in: symbol table */ - byte* str, /* in: string starting with a single - quote; the string literal will - extend to the next single quote, but - the quotes are not included in it */ + byte* str, /* in: string with no quotes around + it */ ulint len) /* in: string length */ { sym_node_t* node; byte* data; - ulint i; - ut_a(len > 1); - ut_a(str[0] == '\''); - node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t)); node->common.type = QUE_NODE_SYMBOL; @@ -151,23 +145,14 @@ sym_tab_add_str_lit( dtype_set(&(node->common.val.type), DATA_VARCHAR, DATA_ENGLISH, 0, 0); - for (i = 1;; i++) { - ut_a(i < len); - - if (str[i] == '\'') { - - break; - } - } - - if (i > 1) { - data = mem_heap_alloc(sym_tab->heap, i - 1); - ut_memcpy(data, str + 1, i - 1); + if (len) { + data = mem_heap_alloc(sym_tab->heap, len); + ut_memcpy(data, str, len); } else { data = NULL; } - dfield_set_data(&(node->common.val), data, i - 1); + dfield_set_data(&(node->common.val), data, len); node->common.val_buf_size = 0; node->prefetch_buf = NULL; diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c index 3d0b997db85..1db89241dff 100644 --- a/innobase/rem/rem0rec.c +++ b/innobase/rem/rem0rec.c @@ -112,7 +112,7 @@ rec_get_nth_field( } if (rec == NULL) { - fprintf(stderr, "Error: rec is NULL pointer\n"); + fputs("Error: rec is NULL pointer\n", stderr); ut_error; } @@ -518,110 +518,47 @@ Prints a physical record. */ void rec_print( /*======*/ + FILE* file, /* in: file where to print */ rec_t* rec) /* in: physical record */ { byte* data; ulint len; - char* offs; ulint n; ulint i; ut_ad(rec); - if (rec_get_1byte_offs_flag(rec)) { - offs = (char *) "TRUE"; - } else { - offs = (char *) "FALSE"; - } - n = rec_get_n_fields(rec); - printf( - "PHYSICAL RECORD: n_fields %lu; 1-byte offs %s; info bits %lu\n", - (ulong) n, offs, (ulong) rec_get_info_bits(rec)); + fprintf(file, "PHYSICAL RECORD: n_fields %lu;" + " 1-byte offs %s; info bits %lu\n", + (ulong) n, rec_get_1byte_offs_flag(rec) ? "TRUE" : "FALSE", + (ulong) rec_get_info_bits(rec)); for (i = 0; i < n; i++) { data = rec_get_nth_field(rec, i, &len); - printf(" %lu:", (ulong) i); + fprintf(file, " %lu:", (ulong) i); if (len != UNIV_SQL_NULL) { if (len <= 30) { - ut_print_buf(data, len); + ut_print_buf(file, data, len); } else { - ut_print_buf(data, 30); + ut_print_buf(file, data, 30); - printf("...(truncated)"); + fputs("...(truncated)", file); } } else { - printf(" SQL NULL, size %lu ", + fprintf(file, " SQL NULL, size %lu ", (ulong) rec_get_nth_field_size(rec, i)); } - printf(";"); + putc(';', file); } - printf("\n"); + putc('\n', file); rec_validate(rec); } - -/******************************************************************* -Prints a physical record to a buffer. */ - -ulint -rec_sprintf( -/*========*/ - /* out: printed length in bytes */ - char* buf, /* in: buffer to print to */ - ulint buf_len,/* in: buffer length */ - rec_t* rec) /* in: physical record */ -{ - byte* data; - ulint len; - ulint k; - ulint n; - ulint i; - - ut_ad(rec); - - n = rec_get_n_fields(rec); - k = 0; - - if (k + 30 > buf_len) { - - return(k); - } - - k += sprintf(buf + k, "RECORD: info bits %lu", - (ulong) rec_get_info_bits(rec)); - - for (i = 0; i < n; i++) { - - if (k + 30 > buf_len) { - - return(k); - } - - data = rec_get_nth_field(rec, i, &len); - - k += sprintf(buf + k, " %lu:", (ulong) i); - - if (len != UNIV_SQL_NULL) { - if (k + 30 + 5 * len > buf_len) { - - return(k); - } - - k += ut_sprintf_buf(buf + k, data, len); - } else { - k += sprintf(buf + k, " SQL NULL"); - } - - k += sprintf(buf + k, ";"); - } - - return(k); -} diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index fc1f7a19d53..a3f883b49c6 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -528,34 +528,37 @@ row_ins_foreign_report_err( dtuple_t* entry) /* in: index entry in the parent table */ { - char* buf = dict_foreign_err_buf; + FILE* ef = dict_foreign_err_file; mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), " Transaction:\n"); - trx_print(buf + strlen(buf), thr_get_trx(thr)); - - sprintf(buf + strlen(buf), -"Foreign key constraint fails for table %.500s:\n", - foreign->foreign_table_name); - dict_print_info_on_foreign_key_in_create_format( - foreign, buf + strlen(buf)); - sprintf(buf + strlen(buf), "\n%s", errstr); - sprintf(buf + strlen(buf), -" in parent table, in index %.500s tuple:\n", - foreign->referenced_index->name); + rewind(ef); + ut_print_timestamp(ef); + fputs(" Transaction:\n", ef); + trx_print(ef, thr_get_trx(thr)); + + fputs("Foreign key constraint fails for table ", ef); + ut_print_name(ef, foreign->foreign_table_name); + fputs(":\n", ef); + dict_print_info_on_foreign_key_in_create_format(ef, foreign); + putc('\n', ef); + fputs(errstr, ef); + fputs(" in parent table, in index ", ef); + ut_print_name(ef, foreign->referenced_index->name); if (entry) { - dtuple_sprintf(buf + strlen(buf), 1000, entry); + fputs(" tuple:\n", ef); + dtuple_print(ef, entry); } - sprintf(buf + strlen(buf), -"\nBut in child table %.500s, in index %.500s, there is a record:\n", - foreign->foreign_table_name, foreign->foreign_index->name); + fputs("\nBut in child table ", ef); + ut_print_name(ef, foreign->foreign_table_name); + fputs(", in index ", ef); + ut_print_name(ef, foreign->foreign_index->name); if (rec) { - rec_sprintf(buf + strlen(buf), 1000, rec); + fputs(", there is a record:\n", ef); + rec_print(ef, rec); + } else { + fputs(", the record is not available\n", ef); } - sprintf(buf + strlen(buf), "\n"); - - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + putc('\n', ef); mutex_exit(&dict_foreign_err_mutex); } @@ -568,8 +571,7 @@ static void row_ins_foreign_report_add_err( /*===========================*/ - que_thr_t* thr, /* in: query thread whose run_node - is an insert node */ + trx_t* trx, /* in: transaction */ dict_foreign_t* foreign, /* in: foreign key constraint */ rec_t* rec, /* in: a record in the parent table: it does not match entry because we @@ -577,28 +579,28 @@ row_ins_foreign_report_add_err( dtuple_t* entry) /* in: index entry to insert in the child table */ { - char* buf = dict_foreign_err_buf; + FILE* ef = dict_foreign_err_file; mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), " Transaction:\n"); - trx_print(buf + strlen(buf), thr_get_trx(thr)); - sprintf(buf + strlen(buf), -"Foreign key constraint fails for table %.500s:\n", - foreign->foreign_table_name); - dict_print_info_on_foreign_key_in_create_format( - foreign, buf + strlen(buf)); - sprintf(buf + strlen(buf), -"\nTrying to add in child table, in index %.500s tuple:\n", - foreign->foreign_index->name); + rewind(ef); + ut_print_timestamp(ef); + fputs(" Transaction:\n", ef); + trx_print(ef, trx); + fputs("Foreign key constraint fails for table ", ef); + ut_print_name(ef, foreign->foreign_table_name); + fputs(":\n", ef); + dict_print_info_on_foreign_key_in_create_format(ef, foreign); + fputs("\nTrying to add in child table, in index ", ef); + ut_print_name(ef, foreign->foreign_index->name); if (entry) { - dtuple_sprintf(buf + strlen(buf), 1000, entry); + fputs(" tuple:\n", ef); + dtuple_print(ef, entry); } - sprintf(buf + strlen(buf), -"\nBut in parent table %.500s, in index %.500s,\n" -"the closest match we can find is record:\n", - foreign->referenced_table_name, - foreign->referenced_index->name); + fputs("\nBut in parent table ", ef); + ut_print_name(ef, foreign->referenced_table_name); + fputs(", in index ", ef); + ut_print_name(ef, foreign->referenced_index->name); + fputs(",\nthe closest match we can find is record:\n", ef); if (rec && page_rec_is_supremum(rec)) { /* If the cursor ended on a supremum record, it is better to report the previous record in the error message, so that @@ -607,11 +609,9 @@ row_ins_foreign_report_add_err( } if (rec) { - rec_sprintf(buf + strlen(buf), 1000, rec); + rec_print(ef, rec); } - sprintf(buf + strlen(buf), "\n"); - - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + putc('\n', ef); mutex_exit(&dict_foreign_err_mutex); } @@ -653,7 +653,6 @@ row_ins_foreign_check_on_constraint( ulint i; char* ptr; char table_name_buf[1000]; - char err_buf[1000]; ut_a(thr && foreign && pcur && mtr); @@ -661,15 +660,10 @@ row_ins_foreign_check_on_constraint( the MySQL query cache for table */ ut_a(ut_strlen(table->name) < 998); - - ut_memcpy(table_name_buf, table->name, ut_strlen(table->name) + 1); - - ptr = table_name_buf; - - while (*ptr != '/') { - ptr++; - } + strcpy(table_name_buf, table->name); + ptr = strchr(table_name_buf, '/'); + ut_a(ptr); *ptr = '\0'; /* We call a function in ha_innodb.cc */ @@ -797,20 +791,20 @@ row_ins_foreign_check_on_constraint( || btr_pcur_get_low_match(cascade->pcur) < dict_index_get_n_unique(clust_index)) { - fprintf(stderr, + fputs( "InnoDB: error in cascade of a foreign key op\n" - "InnoDB: index %s table %s\n", index->name, - index->table->name); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clustered record %s\n", - err_buf); - fprintf(stderr, - "InnoDB: Make a detailed bug report and send it\n"); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + "InnoDB: ", stderr); + dict_index_name_print(stderr, index); + + fputs("\n" + "InnoDB: record ", stderr); + rec_print(stderr, rec); + fputs("\n" + "InnoDB: clustered record ", stderr); + rec_print(stderr, clust_rec); + fputs("\n" + "InnoDB: Make a detailed bug report and send it\n" + "InnoDB: to mysql@lists.mysql.com\n", stderr); err = DB_SUCCESS; @@ -840,24 +834,6 @@ row_ins_foreign_check_on_constraint( /* This can happen if there is a circular reference of rows such that cascading delete comes to delete a row already in the process of being delete marked */ -/* - fprintf(stderr, - "InnoDB: error 2 in cascade of a foreign key op\n" - "InnoDB: index %s table %s\n", index->name, - index->table->name); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clustered record %s\n", err_buf); - - fprintf(stderr, - "InnoDB: Make a detailed bug report and send it\n"); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); - - ut_error; -*/ err = DB_SUCCESS; goto nonstandard_exit_func; @@ -1028,7 +1004,6 @@ row_ins_check_foreign_constraint( int cmp; ulint err; ulint i; - char* buf = dict_foreign_err_buf; mtr_t mtr; run_again: @@ -1091,23 +1066,24 @@ run_again: if (check_table == NULL) { if (check_ref) { + FILE* ef = dict_foreign_err_file; mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - sprintf(buf + strlen(buf), " Transaction:\n"); - trx_print(buf + strlen(buf), thr_get_trx(thr)); - sprintf(buf + strlen(buf), -"Foreign key constraint fails for table %.500s:\n", - foreign->foreign_table_name); - dict_print_info_on_foreign_key_in_create_format( - foreign, buf + strlen(buf)); - sprintf(buf + strlen(buf), -"\nTrying to add to index %.500s tuple:\n", foreign->foreign_index->name); - dtuple_sprintf(buf + strlen(buf), 1000, entry); - sprintf(buf + strlen(buf), -"\nBut the parent table %.500s does not currently exist!\n", - foreign->referenced_table_name); - - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + rewind(ef); + ut_print_timestamp(ef); + fputs(" Transaction:\n", ef); + trx_print(ef, thr_get_trx(thr)); + fputs("Foreign key constraint fails for table ", ef); + ut_print_name(ef, foreign->foreign_table_name); + fputs(":\n", ef); + dict_print_info_on_foreign_key_in_create_format(ef, + foreign); + fputs("\nTrying to add to index ", ef); + ut_print_name(ef, foreign->foreign_index->name); + fputs(" tuple:\n", ef); + dtuple_print(ef, entry); + fputs("\nBut the parent table ", ef); + ut_print_name(ef, foreign->referenced_table_name); + fputs(" does not currently exist!\n", ef); mutex_exit(&dict_foreign_err_mutex); return(DB_NO_REFERENCED_ROW); @@ -1200,11 +1176,6 @@ run_again: break; } -/* printf( -"FOREIGN: Found matching record from %s %s\n", - check_index->table_name, check_index->name); - rec_print(rec); -*/ if (check_ref) { err = DB_SUCCESS; @@ -1244,7 +1215,7 @@ run_again: if (check_ref) { err = DB_NO_REFERENCED_ROW; row_ins_foreign_report_add_err( - thr, foreign, rec, entry); + thr_get_trx(thr), foreign, rec, entry); } else { err = DB_SUCCESS; } @@ -1260,7 +1231,7 @@ next_rec: if (check_ref) { rec = btr_pcur_get_rec(&pcur); row_ins_foreign_report_add_err( - thr, foreign, rec, entry); + thr_get_trx(thr), foreign, rec, entry); err = DB_NO_REFERENCED_ROW; } else { err = DB_SUCCESS; @@ -2176,15 +2147,8 @@ row_ins_step( error_handling: trx->error_state = err; - if (err == DB_SUCCESS) { - /* Ok: do nothing */ - - } else if (err == DB_LOCK_WAIT) { - - return(NULL); - } else { - /* SQL error detected */ - + if (err != DB_SUCCESS) { + /* err == DB_LOCK_WAIT or SQL error detected */ return(NULL); } diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 49e5aeac2e4..4da27bca1a9 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -47,6 +47,51 @@ struct row_mysql_drop_struct{ UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list; ibool row_mysql_drop_list_inited = FALSE; +/* Magic table names for invoking various monitor threads */ +static const char S_innodb_monitor[] = "innodb_monitor"; +static const char S_innodb_lock_monitor[] = "innodb_lock_monitor"; +static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor"; +static const char S_innodb_table_monitor[] = "innodb_table_monitor"; +static const char S_innodb_mem_validate[] = "innodb_mem_validate"; + +/* Name suffix for recovered orphaned temporary tables */ +static const char S_recover_innodb_tmp_table[] = "_recover_innodb_tmp_table"; +/*********************************************************************** +Determine if the given name ends in the suffix reserved for recovered +orphaned temporary tables. */ +static +ibool +row_mysql_is_recovered_tmp_table( +/*=============================*/ + /* out: TRUE if table name ends in + the reserved suffix */ + const char* name) +{ + ulint namelen = strlen(name) + 1; + return(namelen >= sizeof S_recover_innodb_tmp_table + && !memcmp(name + namelen - + sizeof S_recover_innodb_tmp_table, + S_recover_innodb_tmp_table, + sizeof S_recover_innodb_tmp_table)); +} + +/*********************************************************************** +Determine if the given name is a name reserved for MySQL system tables. */ +static +ibool +row_mysql_is_system_table( +/*======================*/ + /* out: TRUE if name is a MySQL + system table name */ + const char* name) +{ + if (memcmp(name, "mysql/", 6)) { + return(FALSE); + } + return(0 == strcmp(name + 6, "host") + || 0 == strcmp(name + 6, "user") + || 0 == strcmp(name + 6, "db")); +} /*********************************************************************** Reads a MySQL format variable-length field (like VARCHAR) length and returns pointer to the field data. */ @@ -267,22 +312,22 @@ handle_new_error: } else if (err == DB_MUST_GET_MORE_FILE_SPACE) { - fprintf(stderr, + fputs( "InnoDB: The database cannot continue operation because of\n" "InnoDB: lack of space. You must add a new data file to\n" - "InnoDB: my.cnf and restart the database.\n"); + "InnoDB: my.cnf and restart the database.\n", stderr); exit(1); } else if (err == DB_CORRUPTION) { - fprintf(stderr, + fputs( "InnoDB: We detected index corruption in an InnoDB type table.\n" "InnoDB: You have to dump + drop + reimport the table or, in\n" "InnoDB: a case of widespread corruption, dump all InnoDB\n" "InnoDB: tables and recreate the whole InnoDB tablespace.\n" "InnoDB: If the mysqld server crashes after the startup or when\n" "InnoDB: you dump the tables, look at section 6.1 of\n" - "InnoDB: http://www.innodb.com/ibman.html for help.\n"); + "InnoDB: http://www.innodb.com/ibman.html for help.\n", stderr); } else { fprintf(stderr, "InnoDB: unknown error code %lu\n", @@ -395,10 +440,11 @@ row_prebuilt_free( || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" -"InnoDB: table handle. Magic n %lu, magic n2 %lu, table name %s\n", +"InnoDB: table handle. Magic n %lu, magic n2 %lu, table name", (ulong) prebuilt->magic_n, - (ulong) prebuilt->magic_n2, - prebuilt->table->name); + (ulong) prebuilt->magic_n2); + ut_print_name(stderr, prebuilt->table->name); + putc('\n', stderr); mem_analyze_corruption((byte*)prebuilt); @@ -443,9 +489,9 @@ row_prebuilt_free( || (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4((prebuilt->fetch_cache[i]) + prebuilt->mysql_row_len))) { - fprintf(stderr, + fputs( "InnoDB: Error: trying to free a corrupt\n" - "InnoDB: fetch buffer.\n"); + "InnoDB: fetch buffer.\n", stderr); mem_analyze_corruption( prebuilt->fetch_cache[i]); @@ -488,8 +534,10 @@ row_update_prebuilt_trx( if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to use a corrupt\n" - "InnoDB: table handle. Magic n %lu, table name %s\n", - (ulong) prebuilt->magic_n, prebuilt->table->name); + "InnoDB: table handle. Magic n %lu, table name", + (ulong) prebuilt->magic_n); + ut_print_name(stderr, prebuilt->table->name); + putc('\n', stderr); mem_analyze_corruption((byte*)prebuilt); @@ -715,8 +763,10 @@ row_insert_for_mysql( if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" - "InnoDB: table handle. Magic n %lu, table name %s\n", - (ulong) prebuilt->magic_n, prebuilt->table->name); + "InnoDB: table handle. Magic n %lu, table name", + (ulong) prebuilt->magic_n); + ut_print_name(stderr, prebuilt->table->name); + putc('\n', stderr); mem_analyze_corruption((byte*)prebuilt); @@ -724,12 +774,13 @@ row_insert_for_mysql( } if (srv_created_new_raw || srv_force_recovery) { - fprintf(stderr, + fputs( "InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n"); + "InnoDB: with raw, and innodb_force_... is removed.\n", + stderr); return(DB_ERROR); } @@ -919,11 +970,7 @@ row_update_for_mysql( upd_node_t* node; dict_table_t* table = prebuilt->table; trx_t* trx = prebuilt->trx; -/* mem_heap_t* heap; - dtuple_t* search_tuple; - dtuple_t* row_tuple; - mtr_t mtr; */ - + ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); UT_NOT_USED(mysql_rec); @@ -931,8 +978,10 @@ row_update_for_mysql( if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" - "InnoDB: table handle. Magic n %lu, table name %s\n", - (ulong) prebuilt->magic_n, prebuilt->table->name); + "InnoDB: table handle. Magic n %lu, table name", + (ulong) prebuilt->magic_n); + ut_print_name(stderr, prebuilt->table->name); + putc('\n', stderr); mem_analyze_corruption((byte*)prebuilt); @@ -940,12 +989,13 @@ row_update_for_mysql( } if (srv_created_new_raw || srv_force_recovery) { - fprintf(stderr, + fputs( "InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n"); + "InnoDB: with raw, and innodb_force_... is removed.\n", + stderr); return(DB_ERROR); } @@ -1166,36 +1216,30 @@ row_mysql_recover_tmp_table( dict_table_t* table, /* in: table definition */ trx_t* trx) /* in: transaction handle */ { - char* ptr; - char old_name[OS_FILE_MAX_PATH]; - - ut_a(ut_strlen(table->name) + 10 < OS_FILE_MAX_PATH); - - ut_memcpy(old_name, table->name, ut_strlen(table->name) + 1); - - ptr = old_name; - - for (;;) { - if (ptr >= old_name + ut_strlen(table->name) - 6) { - trx_commit_for_mysql(trx); + const char* ptr = strstr(table->name, "/rsql"); - return(DB_ERROR); - } - - if (0 == ut_memcmp(ptr, (char*)"/rsql", 5)) { - ptr++; - *ptr = '#'; - - break; - } - - ptr++; + if (!ptr) { + /* table name does not begin with "/rsql" */ + trx_commit_for_mysql(trx); + return(DB_ERROR); + } + else { + int status; + int namelen = strlen(table->name); + char* old_name = mem_strdupl(table->name, namelen); + /* replace "rsql" with "#sql" */ + old_name[ptr - table->name + 1] = '#'; + /* remove "_recover_innodb_tmp_table" suffix */ + ut_ad(namelen > (int) sizeof S_recover_innodb_tmp_table); + ut_ad(!strcmp(old_name + namelen + 1 - + sizeof S_recover_innodb_tmp_table, + S_recover_innodb_tmp_table)); + old_name[namelen + 1 - sizeof S_recover_innodb_tmp_table] = 0; + status = row_rename_table_for_mysql(old_name, + table->name, trx); + mem_free(old_name); + return(status); } - - old_name[ut_strlen(table->name) - - ut_strlen("_recover_innodb_tmp_table")] = '\0'; - - return(row_rename_table_for_mysql(old_name, table->name, trx)); } /************************************************************************* @@ -1270,9 +1314,10 @@ row_mysql_unlock_data_dictionary( } /************************************************************************* -Does a table creation operation for MySQL. If the name of the created -table ends to characters INNODB_MONITOR, then this also starts -printing of monitor output by the master thread. */ +Does a table creation operation for MySQL. If the name of the table +to be created is equal with one of the predefined magic table names, +then this also starts printing the corresponding monitor output by +the master thread. */ int row_create_table_for_mysql( @@ -1285,7 +1330,6 @@ row_create_table_for_mysql( mem_heap_t* heap; que_thr_t* thr; ulint namelen; - ulint keywordlen; ulint err; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); @@ -1296,12 +1340,13 @@ row_create_table_for_mysql( ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH); if (srv_created_new_raw) { - fprintf(stderr, + fputs( "InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n"); + "InnoDB: with raw, and innodb_force_... is removed.\n", + stderr); trx_commit_for_mysql(trx); @@ -1310,10 +1355,8 @@ row_create_table_for_mysql( trx->op_info = (char *) "creating table"; - if (0 == ut_strcmp(table->name, (char*)"mysql/host") - || 0 == ut_strcmp(table->name, (char*)"mysql/user") - || 0 == ut_strcmp(table->name, (char*)"mysql/db")) { - + if (row_mysql_is_system_table(table->name)) { + fprintf(stderr, "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n" "InnoDB: MySQL system tables must be of the MyISAM type!\n", @@ -1326,13 +1369,7 @@ row_create_table_for_mysql( trx_start_if_not_started(trx); - namelen = ut_strlen(table->name); - - keywordlen = ut_strlen("_recover_innodb_tmp_table"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(table->name + namelen - keywordlen, - (char*)"_recover_innodb_tmp_table", keywordlen)) { + if (row_mysql_is_recovered_tmp_table(table->name)) { /* MySQL prevents accessing of tables whose name begins with #sql, that is temporary tables. If mysqld crashes in @@ -1344,15 +1381,13 @@ row_create_table_for_mysql( return(row_mysql_recover_tmp_table(table, trx)); } - namelen = ut_strlen(table->name); + namelen = strlen(table->name) + 1; - keywordlen = ut_strlen((char *) "innodb_monitor"); + if (namelen == sizeof S_innodb_monitor + && !memcmp(table->name, S_innodb_monitor, + sizeof S_innodb_monitor)) { - if (namelen >= keywordlen - && 0 == ut_memcmp(table->name + namelen - keywordlen, - (char *) "innodb_monitor", keywordlen)) { - - /* Table name ends to characters innodb_monitor: + /* Table equals "innodb_monitor": start monitor prints */ srv_print_innodb_monitor = TRUE; @@ -1361,60 +1396,42 @@ row_create_table_for_mysql( of InnoDB monitor prints */ os_event_set(srv_lock_timeout_thread_event); - } - - keywordlen = ut_strlen((char *) "innodb_lock_monitor"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(table->name + namelen - keywordlen, - (char *) "innodb_lock_monitor", keywordlen)) { + } else if (namelen == sizeof S_innodb_lock_monitor + && !memcmp(table->name, S_innodb_lock_monitor, + sizeof S_innodb_lock_monitor)) { srv_print_innodb_monitor = TRUE; srv_print_innodb_lock_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); - } - - keywordlen = ut_strlen((char *) "innodb_tablespace_monitor"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(table->name + namelen - keywordlen, - (char *) "innodb_tablespace_monitor", - keywordlen)) { + } else if (namelen == sizeof S_innodb_tablespace_monitor + && !memcmp(table->name, S_innodb_tablespace_monitor, + sizeof S_innodb_tablespace_monitor)) { srv_print_innodb_tablespace_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); - } - - keywordlen = ut_strlen((char *) "innodb_table_monitor"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(table->name + namelen - keywordlen, - (char *) "innodb_table_monitor", - keywordlen)) { + } else if (namelen == sizeof S_innodb_table_monitor + && !memcmp(table->name, S_innodb_table_monitor, + sizeof S_innodb_table_monitor)) { srv_print_innodb_table_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); - } - - keywordlen = ut_strlen("innodb_mem_validate"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(table->name + namelen - keywordlen, - (char*)"innodb_mem_validate", keywordlen)) { - + } else if (namelen == sizeof S_innodb_mem_validate + && !memcmp(table->name, S_innodb_mem_validate, + sizeof S_innodb_mem_validate)) { /* We define here a debugging feature intended for developers */ - printf("Validating InnoDB memory:\n" + fputs("Validating InnoDB memory:\n" "to use this feature you must compile InnoDB with\n" "UNIV_MEM_DEBUG defined in univ.i and the server must be\n" "quiet because allocation from a mem heap is not protected\n" - "by any semaphore.\n"); + "by any semaphore.\n", stderr); #ifdef UNIV_MEM_DEBUG ut_a(mem_validate()); - printf("Memory validated\n"); + fputs("Memory validated\n", stderr); #else /* UNIV_MEM_DEBUG */ - puts("Memory NOT validated (recompile with UNIV_MEM_DEBUG)"); + fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n", + stderr); #endif /* UNIV_MEM_DEBUG */ } @@ -1439,29 +1456,28 @@ row_create_table_for_mysql( trx_general_rollback_for_mysql(trx, FALSE, NULL); if (err == DB_OUT_OF_FILE_SPACE) { - fprintf(stderr, - "InnoDB: Warning: cannot create table %s because tablespace full\n", - table->name); - row_drop_table_for_mysql(table->name, trx); + fputs("InnoDB: Warning: cannot create table ", stderr); + ut_print_name(stderr, table->name); + fputs(" because tablespace full\n", stderr); + row_drop_table_for_mysql(table->name, trx, FALSE); } else if (err == DB_DUPLICATE_KEY) { ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: table %s already exists in InnoDB internal\n" + fputs(" InnoDB: Error: table ", stderr); + ut_print_name(stderr, table->name); + fputs(" already exists in InnoDB internal\n" "InnoDB: data dictionary. Have you deleted the .frm file\n" "InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n" "InnoDB: for InnoDB tables in MySQL version <= 3.23.43?\n" - "InnoDB: See the Restrictions section of the InnoDB manual.\n", - table->name); - fprintf(stderr, + "InnoDB: See the Restrictions section of the InnoDB manual.\n" "InnoDB: You can drop the orphaned table inside InnoDB by\n" "InnoDB: creating an InnoDB table with the same name in another\n" "InnoDB: database and moving the .frm file to the current database.\n" "InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n" "InnoDB: succeed.\n" "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.html\n"); + "InnoDB: http://www.innodb.com/ibman.php\n", stderr); } /* We may also get err == DB_ERROR if the .ibd file for the @@ -1492,8 +1508,6 @@ row_create_index_for_mysql( ind_node_t* node; mem_heap_t* heap; que_thr_t* thr; - ulint namelen; - ulint keywordlen; ulint err; ulint i, j; @@ -1517,11 +1531,14 @@ row_create_index_for_mysql( ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: column %s appears twice in index %s of table %s\n" -"InnoDB: This is not allowed in InnoDB.\n", - dict_index_get_nth_field(index, i)->name, - index->name, index->table_name); + fputs(" InnoDB: Error: column ", stderr); + ut_print_name(stderr, + dict_index_get_nth_field(index, i)->name); + fputs(" appears twice in ", stderr); + dict_index_name_print(stderr, index); + fputs("\n" + "InnoDB: This is not allowed in InnoDB.\n", + stderr); err = DB_COL_APPEARS_TWICE_IN_INDEX; @@ -1532,14 +1549,7 @@ row_create_index_for_mysql( trx_start_if_not_started(trx); - namelen = ut_strlen(index->table_name); - - keywordlen = ut_strlen("_recover_innodb_tmp_table"); - - if (namelen >= keywordlen - && 0 == ut_memcmp( - index->table_name + namelen - keywordlen, - (char*)"_recover_innodb_tmp_table", keywordlen)) { + if (row_mysql_is_recovered_tmp_table(index->table_name)) { return(DB_SUCCESS); } @@ -1570,7 +1580,7 @@ error_handling: trx_general_rollback_for_mysql(trx, FALSE, NULL); - row_drop_table_for_mysql(index->table_name, trx); + row_drop_table_for_mysql(index->table_name, trx, FALSE); trx->error_state = DB_SUCCESS; } @@ -1602,8 +1612,6 @@ row_table_add_foreign_constraints( char* name) /* in: table full name in the normalized form database_name/table_name */ { - ulint namelen; - ulint keywordlen; ulint err; #ifdef UNIV_SYNC_DEBUG @@ -1616,14 +1624,7 @@ row_table_add_foreign_constraints( trx_start_if_not_started(trx); - namelen = ut_strlen(name); - - keywordlen = ut_strlen("_recover_innodb_tmp_table"); - - if (namelen >= keywordlen - && 0 == ut_memcmp( - name + namelen - keywordlen, - (char*)"_recover_innodb_tmp_table", keywordlen)) { + if (row_mysql_is_recovered_tmp_table(name)) { return(DB_SUCCESS); } @@ -1644,7 +1645,7 @@ row_table_add_foreign_constraints( trx_general_rollback_for_mysql(trx, FALSE, NULL); - row_drop_table_for_mysql(name, trx); + row_drop_table_for_mysql(name, trx, FALSE); trx->error_state = DB_SUCCESS; } @@ -1671,16 +1672,19 @@ row_drop_table_for_mysql_in_background( trx = trx_allocate_for_background(); -/* fprintf(stderr, "InnoDB: Dropping table %s in background drop list\n", - name); */ +/* fputs("InnoDB: Error: Dropping table ", stderr); + ut_print_name(stderr, name); + fputs(" in background drop list\n", stderr); */ + /* Drop the table in InnoDB */ - error = row_drop_table_for_mysql(name, trx); + error = row_drop_table_for_mysql(name, trx, FALSE); if (error != DB_SUCCESS) { - fprintf(stderr, - "InnoDB: Error: Dropping table %s in background drop list failed\n", - name); + ut_print_timestamp(stderr); + fputs(" InnoDB: Error: Dropping table ", stderr); + ut_print_name(stderr, name); + fputs(" in background drop list failed\n", stderr); } /* Flush the log to reduce probability that the .frm files and @@ -1758,9 +1762,9 @@ already_dropped: UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop); ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Dropped table %s in background drop queue.\n", - drop->table_name); + fputs(" InnoDB: Dropped table ", stderr); + ut_print_name(stderr, drop->table_name); + fputs(" in background drop queue.\n", stderr); mem_free(drop->table_name); @@ -1807,9 +1811,7 @@ row_add_table_to_background_drop_list( drop = mem_alloc(sizeof(row_mysql_drop_t)); - drop->table_name = mem_alloc(1 + ut_strlen(table->name)); - - ut_memcpy(drop->table_name, table->name, 1 + ut_strlen(table->name)); + drop->table_name = mem_strdup(table->name); mutex_enter(&kernel_mutex); @@ -1821,8 +1823,10 @@ row_add_table_to_background_drop_list( UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop); -/* fprintf(stderr, "InnoDB: Adding table %s to background drop list\n", - drop->table_name); */ +/* fputs("InnoDB: Adding table ", stderr); + ut_print_name(stderr, drop->table_name); + fputs(" to background drop list\n", stderr); */ + mutex_exit(&kernel_mutex); } @@ -2082,16 +2086,17 @@ funct_exit: } /************************************************************************* -Drops a table for MySQL. If the name of the dropped table ends to -characters INNODB_MONITOR, then this also stops printing of monitor -output by the master thread. */ +Drops a table for MySQL. If the name of the table to be dropped is equal +with one of the predefined magic table names, then this also stops printing +the corresponding monitor output by the master thread. */ int row_drop_table_for_mysql( /*=====================*/ /* out: error code or DB_SUCCESS */ char* name, /* in: table name */ - trx_t* trx) /* in: transaction handle */ + trx_t* trx, /* in: transaction handle */ + ibool drop_db)/* in: TRUE=dropping whole database */ { dict_foreign_t* foreign; dict_table_t* table; @@ -2099,84 +2104,16 @@ row_drop_table_for_mysql( que_thr_t* thr; que_t* graph; ulint err; - char* str1; - char* str2; - ulint len; ulint namelen; - ulint keywordlen; ibool success; ibool locked_dictionary = FALSE; - char buf[OS_FILE_MAX_PATH + 2000]; - - ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); - ut_a(name != NULL); - - if (srv_created_new_raw) { - fprintf(stderr, - "InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" - "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n"); - - return(DB_ERROR); - } - - trx->op_info = (char *) "dropping table"; - - trx_start_if_not_started(trx); - - namelen = ut_strlen(name); - keywordlen = ut_strlen((char *) "innodb_monitor"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(name + namelen - keywordlen, - (char *) "innodb_monitor", keywordlen)) { - - /* Table name ends to characters innodb_monitor: - stop monitor prints */ - - srv_print_innodb_monitor = FALSE; - srv_print_innodb_lock_monitor = FALSE; - } - - keywordlen = ut_strlen((char *) "innodb_lock_monitor"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(name + namelen - keywordlen, - (char *) "innodb_lock_monitor", - keywordlen)) { - - srv_print_innodb_monitor = FALSE; - srv_print_innodb_lock_monitor = FALSE; - } - - keywordlen = ut_strlen((char *) "innodb_tablespace_monitor"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(name + namelen - keywordlen, - (char *) "innodb_tablespace_monitor", - keywordlen)) { - - srv_print_innodb_tablespace_monitor = FALSE; - } - - keywordlen = ut_strlen((char *) "innodb_table_monitor"); - - if (namelen >= keywordlen - && 0 == ut_memcmp(name + namelen - keywordlen, - (char *) "innodb_table_monitor", - keywordlen)) { - - srv_print_innodb_table_monitor = FALSE; - } - + char* quoted_name; + char* sql; /* We use the private SQL parser of Innobase to generate the query graphs needed in deleting the dictionary data from system tables in Innobase. Deleting a row from SYS_INDEXES table also frees the file segments of the B-tree associated with the index. */ - - str1 = (char *) + static const char str1[] = "PROCEDURE DROP_TABLE_PROC () IS\n" "table_name CHAR;\n" "sys_foreign_id CHAR;\n" @@ -2185,10 +2122,9 @@ row_drop_table_for_mysql( "foreign_id CHAR;\n" "found INT;\n" "BEGIN\n" - "table_name := '"; - - str2 = (char *) - "';\n" + "table_name := "; + static const char str2[] = + ";\n" "SELECT ID INTO table_id\n" "FROM SYS_TABLES\n" "WHERE NAME = table_name;\n" @@ -2238,16 +2174,74 @@ row_drop_table_for_mysql( "COMMIT WORK;\n" "END;\n"; - len = ut_strlen(str1); + ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); + ut_a(name != NULL); - ut_memcpy(buf, str1, len); - ut_memcpy(buf + len, name, ut_strlen(name)); + if (srv_created_new_raw) { + fputs( + "InnoDB: A new raw disk partition was initialized or\n" + "InnoDB: innodb_force_recovery is on: we do not allow\n" + "InnoDB: database modifications by the user. Shut down\n" + "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" + "InnoDB: with raw, and innodb_force_... is removed.\n", + stderr); - len += ut_strlen(name); + return(DB_ERROR); + } - ut_memcpy(buf + len, str2, ut_strlen(str2) + 1); + trx->op_info = (char *) "dropping table"; - ut_a(strlen(buf) < OS_FILE_MAX_PATH + 2000); + trx_start_if_not_started(trx); + + namelen = strlen(name) + 1; + + if (namelen == sizeof S_innodb_monitor + && !memcmp(name, S_innodb_monitor, + sizeof S_innodb_monitor)) { + + /* Table name equals "innodb_monitor": + stop monitor prints */ + + srv_print_innodb_monitor = FALSE; + srv_print_innodb_lock_monitor = FALSE; + } else if (namelen == sizeof S_innodb_lock_monitor + && !memcmp(name, S_innodb_lock_monitor, + sizeof S_innodb_lock_monitor)) { + srv_print_innodb_monitor = FALSE; + srv_print_innodb_lock_monitor = FALSE; + } else if (namelen == sizeof S_innodb_tablespace_monitor + && !memcmp(name, S_innodb_tablespace_monitor, + sizeof S_innodb_tablespace_monitor)) { + + srv_print_innodb_tablespace_monitor = FALSE; + } else if (namelen == sizeof S_innodb_table_monitor + && !memcmp(name, S_innodb_table_monitor, + sizeof S_innodb_table_monitor)) { + + srv_print_innodb_table_monitor = FALSE; + } + + ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); + ut_a(name != NULL); + + if (srv_created_new_raw) { + fputs( + "InnoDB: A new raw disk partition was initialized or\n" + "InnoDB: innodb_force_recovery is on: we do not allow\n" + "InnoDB: database modifications by the user. Shut down\n" + "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" + "InnoDB: with raw, and innodb_force_... is removed.\n", + stderr); + + return(DB_ERROR); + } + + quoted_name = mem_strdupq(name, '\''); + namelen = strlen(quoted_name); + sql = mem_alloc((sizeof str1) + (sizeof str2) - 2 + 1 + namelen); + memcpy(sql, str1, (sizeof str1) - 1); + memcpy(sql + (sizeof str1) - 1, quoted_name, namelen); + memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2); /* Serialize data dictionary operations with dictionary mutex: no deadlocks can occur then in these operations */ @@ -2266,9 +2260,10 @@ row_drop_table_for_mysql( ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - graph = pars_sql(buf); + graph = pars_sql(sql); ut_a(graph); + mem_free(sql); graph->trx = trx; trx->graph = NULL; @@ -2281,15 +2276,14 @@ row_drop_table_for_mysql( err = DB_TABLE_NOT_FOUND; ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: table %s\n" - "InnoDB: does not exist in the InnoDB internal\n" + fputs(" InnoDB: Error: table ", stderr); + ut_print_name(stderr, name); + fputs(" does not exist in the InnoDB internal\n" "InnoDB: data dictionary though MySQL is trying to drop it.\n" "InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: MySQL database directory from another database?\n" "InnoDB: You can look for further help from section 15.1 of\n" - "InnoDB: http://www.innodb.com/ibman.html\n", - name); + "InnoDB: http://www.innodb.com/ibman.php\n", stderr); goto funct_exit; } @@ -2302,8 +2296,10 @@ row_drop_table_for_mysql( foreign = UT_LIST_GET_NEXT(referenced_list, foreign); } - if (foreign && trx->check_foreigns) { - char* buf = dict_foreign_err_buf; + if (foreign && trx->check_foreigns && + !(drop_db && dict_tables_have_same_db( + name, foreign->foreign_table_name))) { + FILE* ef = dict_foreign_err_file; /* We only allow dropping a referenced table if FOREIGN_KEY_CHECKS is set to 0 */ @@ -2311,28 +2307,30 @@ row_drop_table_for_mysql( err = DB_CANNOT_DROP_CONSTRAINT; mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(buf); - - sprintf(buf + strlen(buf), - " Cannot drop table %.500s\n", name); - sprintf(buf + strlen(buf), -"because it is referenced by %.500s\n", foreign->foreign_table_name); - - ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); - + rewind(ef); + ut_print_timestamp(ef); + + fputs(" Cannot drop table ", ef); + ut_print_name(ef, name); + fputs("\n" + "because it is referenced by ", ef); + ut_print_name(ef, foreign->foreign_table_name); + putc('\n', ef); mutex_exit(&dict_foreign_err_mutex); goto funct_exit; } if (table->n_mysql_handles_opened > 0) { - + ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: MySQL is trying to drop table %s\n" + fputs(" InnoDB: Warning: MySQL is trying to drop table ", + stderr); + ut_print_name(stderr, table->name); + fputs("\n" "InnoDB: though there are still open handles to it.\n" "InnoDB: Adding the table to the background drop queue.\n", - table->name); + stderr); row_add_table_to_background_drop_list(table); @@ -2342,13 +2340,14 @@ row_drop_table_for_mysql( } if (table->n_foreign_key_checks_running > 0) { - + ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: You are trying to drop table %s\n" + fputs(" InnoDB: You are trying to drop table ", stderr); + ut_print_name(stderr, table->name); + fputs("\n" "InnoDB: though there are foreign key check running on it.\n" "InnoDB: Adding the table to the background drop queue.\n", - table->name); + stderr); row_add_table_to_background_drop_list(table); @@ -2384,9 +2383,10 @@ row_drop_table_for_mysql( if (dict_load_table(name) != NULL) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: not able to remove table %s from the dictionary cache!\n", - name); + fputs(" InnoDB: Error: not able to remove table ", + stderr); + ut_print_name(stderr, name); + fputs(" from the dictionary cache!\n", stderr); err = DB_ERROR; } @@ -2454,7 +2454,7 @@ loop: row_mysql_lock_data_dictionary(trx); while ((table_name = dict_get_first_table_name_in_db(name))) { - ut_a(memcmp(table_name, name, strlen(name)) == 0); + ut_a(strcmp(table_name, name) == 0); table = dict_table_get_low(table_name); @@ -2467,10 +2467,13 @@ loop: row_mysql_unlock_data_dictionary(trx); ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: MySQL is trying to drop database %s\n" - "InnoDB: though there are still open handles to table %s.\n", - name, table_name); + fputs( + " InnoDB: Warning: MySQL is trying to drop database ", stderr); + ut_print_name(stderr, name); + fputs("\n" + "InnoDB: though there are still open handles to table ", stderr); + ut_print_name(stderr, table_name); + fputs(".\n", stderr); os_thread_sleep(1000000); @@ -2479,14 +2482,17 @@ loop: goto loop; } - err = row_drop_table_for_mysql(table_name, trx); + err = row_drop_table_for_mysql(table_name, trx, TRUE); mem_free(table_name); if (err != DB_SUCCESS) { - fprintf(stderr, - "InnoDB: DROP DATABASE %s failed with error %lu for table %s\n", - name, (ulong) err, table_name); + fputs("InnoDB: DROP DATABASE ", stderr); + ut_print_name(stderr, name); + fprintf(stderr, " failed with error %lu for table ", + (ulint) err); + ut_print_name(stderr, table_name); + putc('\n', stderr); break; } } @@ -2507,19 +2513,11 @@ static ibool row_is_mysql_tmp_table_name( /*========================*/ - /* out: TRUE if temporary table */ - char* name) /* in: table name in the form 'database/tablename' */ + /* out: TRUE if temporary table */ + const char* name) /* in: table name in the form + 'database/tablename' */ { - ulint i; - - for (i = 0; i + 5 <= ut_strlen(name); i++) { - if (ut_memcmp(name + i, (char*)"/#sql", 5) == 0) { - - return(TRUE); - } - } - - return(FALSE); + return(strstr(name, "/#sql") != NULL); } /************************************************************************* @@ -2537,40 +2535,113 @@ row_rename_table_for_mysql( que_thr_t* thr; que_t* graph = NULL; ulint err; - char* str1; - char* str2; - char* str3; + /* We use the private SQL parser of Innobase to generate the + query graphs needed in deleting the dictionary data from system + tables in Innobase. Deleting a row from SYS_INDEXES table also + frees the file segments of the B-tree associated with the index. */ + static const char str1[] = + "PROCEDURE RENAME_TABLE_PROC () IS\n" + "new_table_name CHAR;\n" + "old_table_name CHAR;\n" + "gen_constr_prefix CHAR;\n" + "new_db_name CHAR;\n" + "foreign_id CHAR;\n" + "new_foreign_id CHAR;\n" + "old_db_name_len INT;\n" + "old_t_name_len INT;\n" + "new_db_name_len INT;\n" + "id_len INT;\n" + "found INT;\n" + "BEGIN\n" + "new_table_name := '"; + static const char str2[] = + "';\nold_table_name := '"; + static const char str3[] = + "';\n" + "UPDATE SYS_TABLES SET NAME = new_table_name\n" + "WHERE NAME = old_table_name;\n"; + static const char str4a1[] = /* drop some constraints of tmp tables */ + "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '"; + static const char str4a2[] = "';\n" + "DELETE FROM SYS_FOREIGN WHERE ID = '"; + static const char str4a3[] = "';\n"; + static const char str4b[] = /* rename all constraints */ + "found := 1;\n" + "old_db_name_len := INSTR(old_table_name, '/') - 1;\n" + "new_db_name_len := INSTR(new_table_name, '/') - 1;\n" + "new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);\n" + "old_t_name_len := LENGTH(old_table_name);\n" + "gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO foreign_id\n" + " FROM SYS_FOREIGN\n" + " WHERE FOR_NAME = old_table_name;\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE\n" + " UPDATE SYS_FOREIGN\n" + " SET FOR_NAME = new_table_name\n" + " WHERE ID = foreign_id;\n" + " id_len := LENGTH(foreign_id);\n" + " IF (INSTR(foreign_id, '/') > 0) THEN\n" + " IF (INSTR(foreign_id,\n" + " gen_constr_prefix) > 0)\n" + " THEN\n" + " new_foreign_id :=\n" + " CONCAT(new_table_name,\n" + " SUBSTR(foreign_id, old_t_name_len,\n" + " id_len - old_t_name_len));\n" + " ELSE\n" + " new_foreign_id :=\n" + " CONCAT(new_db_name,\n" + " SUBSTR(foreign_id,\n" + " old_db_name_len,\n" + " id_len - old_db_name_len));\n" + " END IF;\n" + " UPDATE SYS_FOREIGN\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " UPDATE SYS_FOREIGN_COLS\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " END IF;\n" + " END IF;\n" + "END LOOP;\n" + "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" + "WHERE REF_NAME = old_table_name;\n"; + static const char str5[] = + "END;\n"; + mem_heap_t* heap = NULL; - char** constraints_to_drop = NULL; + const char** constraints_to_drop = NULL; ulint n_constraints_to_drop = 0; - ibool recovering_temp_table = FALSE; - ulint namelen; - ulint keywordlen; + ibool recovering_temp_table = FALSE; ulint len; ulint i; - char* db_name; - ibool success; - char buf[2 * OS_FILE_MAX_PATH]; + ibool success; + /* length of database name; 0 if not renaming to a temporary table */ + ulint db_name_len; + char* sql; + char* sqlend; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_a(old_name != NULL); ut_a(new_name != NULL); if (srv_created_new_raw || srv_force_recovery) { - fprintf(stderr, + fputs( "InnoDB: A new raw disk partition was initialized or\n" "InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" "InnoDB: mysqld and edit my.cnf so that newraw is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n"); + "InnoDB: with raw, and innodb_force_... is removed.\n", + stderr); trx_commit_for_mysql(trx); return(DB_ERROR); } - if (0 == ut_strcmp(new_name, (char*)"mysql/host") - || 0 == ut_strcmp(new_name, (char*)"mysql/user") - || 0 == ut_strcmp(new_name, (char*)"mysql/db")) { + if (row_mysql_is_system_table(new_name)) { fprintf(stderr, "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n" @@ -2584,21 +2655,13 @@ row_rename_table_for_mysql( trx->op_info = (char *) "renaming table"; trx_start_if_not_started(trx); - namelen = ut_strlen(new_name); - - keywordlen = ut_strlen("_recover_innodb_tmp_table"); + if (row_mysql_is_recovered_tmp_table(new_name)) { - if (namelen >= keywordlen - && 0 == ut_memcmp(new_name + namelen - keywordlen, - (char*)"_recover_innodb_tmp_table", keywordlen)) { + recovering_temp_table = TRUE; + } else { + /* Serialize data dictionary operations with dictionary mutex: + no deadlocks can occur then in these operations */ - recovering_temp_table = TRUE; - } - - /* Serialize data dictionary operations with dictionary mutex: - no deadlocks can occur then in these operations */ - - if (!recovering_temp_table) { row_mysql_lock_data_dictionary(trx); } @@ -2633,26 +2696,12 @@ row_rename_table_for_mysql( goto funct_exit; } - str1 = (char *) - "PROCEDURE RENAME_TABLE_PROC () IS\n" - "new_table_name CHAR;\n" - "old_table_name CHAR;\n" - "gen_constr_prefix CHAR;\n" - "new_db_name CHAR;\n" - "foreign_id CHAR;\n" - "new_foreign_id CHAR;\n" - "old_db_name_len INT;\n" - "old_t_name_len INT;\n" - "new_db_name_len INT;\n" - "id_len INT;\n" - "found INT;\n" - "BEGIN\n" - "new_table_name :='"; - - str2 = (char *) - "';\nold_table_name := '"; + /* calculate the length of the SQL string */ + len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4 + + ut_strlenq(new_name, '\'') + ut_strlenq(old_name, '\''); if (row_is_mysql_tmp_table_name(new_name)) { + db_name_len = dict_get_db_name_len(old_name) + 1; /* MySQL is doing an ALTER TABLE command and it renames the original table to a temporary table name. We want to preserve @@ -2671,123 +2720,90 @@ row_rename_table_for_mysql( goto funct_exit; } - str3 = mem_heap_alloc(heap, - 1000 + 1000 * n_constraints_to_drop); - *str3 = '\0'; - sprintf(str3, - "';\n" - "UPDATE SYS_TABLES SET NAME = new_table_name\n" - "WHERE NAME = old_table_name;\n"); - - db_name = mem_heap_alloc(heap, 1 + dict_get_db_name_len( - old_name)); - ut_memcpy(db_name, old_name, dict_get_db_name_len(old_name)); - db_name[dict_get_db_name_len(old_name)] = '\0'; + /* reserve space for all database names */ + len += 2 * n_constraints_to_drop + * (ut_strlenq(old_name, '\'') + - ut_strlenq(old_name + db_name_len, '\'')); + + for (i = 0; i < n_constraints_to_drop; i++) { + ulint addlen + = 2 * ut_strlenq(constraints_to_drop[i], '\'') + + ((sizeof str4a1) + (sizeof str4a2) + + (sizeof str4a3) - 3); + if (!strchr(constraints_to_drop[i], '/')) { + addlen *= 2; + } + len += addlen; + } + } else { + db_name_len = 0; + len += (sizeof str4b) - 1; + } + + sql = sqlend = mem_alloc(len + 1); + memcpy(sql, str1, (sizeof str1) - 1); + sqlend += (sizeof str1) - 1; + sqlend = ut_strcpyq(sqlend, '\'', new_name); + memcpy(sqlend, str2, (sizeof str2) - 1); + sqlend += (sizeof str2) - 1; + sqlend = ut_strcpyq(sqlend, '\'', old_name); + memcpy(sqlend, str3, (sizeof str3) - 1); + sqlend += (sizeof str3) - 1; + if (db_name_len) { /* Internally, old format < 4.0.18 constraints have as the constraint id <number>_<number>, while new format constraints have <databasename>/<constraintname>. */ for (i = 0; i < n_constraints_to_drop; i++) { + memcpy(sqlend, str4a1, (sizeof str4a1) - 1); + sqlend += (sizeof str4a1) - 1; + sqlend = ut_memcpyq(sqlend, '\'', + old_name, db_name_len); + sqlend = ut_strcpyq(sqlend, '\'', + constraints_to_drop[i]); + memcpy(sqlend, str4a2, (sizeof str4a2) - 1); + sqlend += (sizeof str4a2) - 1; + sqlend = ut_memcpyq(sqlend, '\'', + old_name, db_name_len); + sqlend = ut_strcpyq(sqlend, '\'', + constraints_to_drop[i]); + memcpy(sqlend, str4a3, (sizeof str4a3) - 1); + sqlend += (sizeof str4a3) - 1; - sprintf(str3 + strlen(str3), - "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s/%s';\n" - "DELETE FROM SYS_FOREIGN WHERE ID = '%s/%s';\n", - db_name, constraints_to_drop[i], - db_name, constraints_to_drop[i]); - - if (!ut_str_contains(constraints_to_drop[i], '/')) { + if (!strchr(constraints_to_drop[i], '/')) { /* If this happens to be an old format constraint, let us delete it. Since all new format constraints contain '/', it does no harm to run these DELETEs anyway. */ - sprintf(str3 + strlen(str3), - "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s';\n" - "DELETE FROM SYS_FOREIGN WHERE ID = '%s';\n", - constraints_to_drop[i], - constraints_to_drop[i]); + memcpy(sqlend, str4a1, (sizeof str4a1) - 1); + sqlend += (sizeof str4a1) - 1; + sqlend = ut_strcpyq(sqlend, '\'', + constraints_to_drop[i]); + memcpy(sqlend, str4a2, (sizeof str4a2) - 1); + sqlend += (sizeof str4a2) - 1; + sqlend = ut_strcpyq(sqlend, '\'', + constraints_to_drop[i]); + memcpy(sqlend, str4a3, (sizeof str4a3) - 1); + sqlend += (sizeof str4a3) - 1; } } + } + else { + memcpy(sqlend, str4b, (sizeof str4b) - 1); + sqlend += (sizeof str4b) - 1; + } - sprintf(str3 + strlen(str3), - "END;\n"); + memcpy(sqlend, str5, sizeof str5); + sqlend += sizeof str5; - ut_a(strlen(str3) < 1000 + 1000 * n_constraints_to_drop); - } else { - str3 = (char*) - "';\n" - "UPDATE SYS_TABLES SET NAME = new_table_name\n" - "WHERE NAME = old_table_name;\n" - "found := 1;\n" - "old_db_name_len := INSTR(old_table_name, '/') - 1;\n" - "new_db_name_len := INSTR(new_table_name, '/') - 1;\n" - "new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);\n" - "old_t_name_len := LENGTH(old_table_name);\n" - "gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');\n" - "WHILE found = 1 LOOP\n" - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = old_table_name;\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE\n" - " UPDATE SYS_FOREIGN\n" - " SET FOR_NAME = new_table_name\n" - " WHERE ID = foreign_id;\n" - " id_len := LENGTH(foreign_id);\n" - " IF (INSTR(foreign_id, '/') > 0) THEN\n" - " IF (INSTR(foreign_id,\n" - " gen_constr_prefix) > 0)\n" - " THEN\n" - " new_foreign_id :=\n" - " CONCAT(new_table_name,\n" - " SUBSTR(foreign_id, old_t_name_len,\n" - " id_len - old_t_name_len));\n" - " ELSE\n" - " new_foreign_id :=\n" - " CONCAT(new_db_name,\n" - " SUBSTR(foreign_id,\n" - " old_db_name_len,\n" - " id_len - old_db_name_len));\n" - " END IF;\n" - " UPDATE SYS_FOREIGN\n" - " SET ID = new_foreign_id\n" - " WHERE ID = foreign_id;\n" - " UPDATE SYS_FOREIGN_COLS\n" - " SET ID = new_foreign_id\n" - " WHERE ID = foreign_id;\n" - " END IF;\n" - " END IF;\n" - "END LOOP;\n" - "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" - "WHERE REF_NAME = old_table_name;\n" - "END;\n"; - } - - len = ut_strlen(str1); - - ut_memcpy(buf, str1, len); - - ut_memcpy(buf + len, new_name, ut_strlen(new_name)); - - len += ut_strlen(new_name); - - ut_memcpy(buf + len, str2, ut_strlen(str2)); - - len += ut_strlen(str2); - - ut_memcpy(buf + len, old_name, ut_strlen(old_name)); - - len += ut_strlen(old_name); - - ut_memcpy(buf + len, str3, ut_strlen(str3) + 1); + ut_a(sqlend == sql + len + 1); - ut_a(strlen(buf) < 2 * OS_FILE_MAX_PATH); - - graph = pars_sql(buf); + graph = pars_sql(sql); ut_a(graph); + mem_free(sql); graph->trx = trx; trx->graph = NULL; @@ -2915,7 +2931,6 @@ row_scan_and_check_index( int cmp; ibool contains_null; ulint i; - char err_buf[1000]; *n_rows = 0; @@ -2952,7 +2967,7 @@ loop: template */ rec = buf + mach_read_from_4(buf); - + if (prev_entry != NULL) { matched_fields = 0; matched_bytes = 0; @@ -2976,32 +2991,25 @@ loop: } if (cmp > 0) { - fprintf(stderr, - "Error: index records in a wrong order in index %s\n", - index->name); - - dtuple_sprintf(err_buf, 900, prev_entry); - fprintf(stderr, "InnoDB: prev record %s\n", err_buf); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - + fputs("InnoDB: index records in a wrong order in ", + stderr); + not_ok: + dict_index_name_print(stderr, index); + fputs("\n" + "InnoDB: prev record ", stderr); + dtuple_print(stderr, prev_entry); + fputs("\n" + "InnoDB: record ", stderr); + rec_print(stderr, rec); + putc('\n', stderr); is_ok = FALSE; } else if ((index->type & DICT_UNIQUE) && !contains_null && matched_fields >= dict_index_get_n_ordering_defined_by_user(index)) { - fprintf(stderr, "Error: duplicate key in index %s\n", - index->name); - - dtuple_sprintf(err_buf, 900, prev_entry); - fprintf(stderr, "InnoDB: prev record %s\n", err_buf); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - - is_ok = FALSE; + fputs("InnoDB: duplicate key in ", stderr); + goto not_ok; } } @@ -3045,7 +3053,9 @@ row_check_table_for_mysql( index = dict_table_get_first_index(table); while (index != NULL) { - /* fprintf(stderr, "Validating index %s\n", index->name); */ + /* fputs("Validating index ", stderr); + ut_print_name(stderr, index->name); + putc('\n', stderr); */ if (!btr_validate_tree(index->tree)) { ret = DB_ERROR; diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c index a409b64f8e4..8f5f0831dc6 100644 --- a/innobase/row/row0purge.c +++ b/innobase/row/row0purge.c @@ -91,7 +91,6 @@ row_purge_remove_clust_if_poss_low( /* out: TRUE if success, or if not found, or if modified after the delete marking */ purge_node_t* node, /* in: row purge node */ - que_thr_t* thr, /* in: query thread */ ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { dict_index_t* index; @@ -101,8 +100,6 @@ row_purge_remove_clust_if_poss_low( ulint err; mtr_t mtr; - UT_NOT_USED(thr); - index = dict_table_get_first_index(node->table); pcur = &(node->pcur); @@ -156,23 +153,20 @@ static void row_purge_remove_clust_if_poss( /*===========================*/ - purge_node_t* node, /* in: row purge node */ - que_thr_t* thr) /* in: query thread */ + purge_node_t* node) /* in: row purge node */ { ibool success; ulint n_tries = 0; -/* printf("Purge: Removing clustered record\n"); */ +/* fputs("Purge: Removing clustered record\n", stderr); */ - success = row_purge_remove_clust_if_poss_low(node, thr, - BTR_MODIFY_LEAF); + success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_LEAF); if (success) { return; } retry: - success = row_purge_remove_clust_if_poss_low(node, thr, - BTR_MODIFY_TREE); + success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_TREE); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database and restart with more file space */ @@ -196,7 +190,6 @@ row_purge_remove_sec_if_poss_low( /*=============================*/ /* out: TRUE if success or if not found */ purge_node_t* node, /* in: row purge node */ - que_thr_t* thr, /* in: query thread */ dict_index_t* index, /* in: index */ dtuple_t* entry, /* in: index entry */ ulint mode) /* in: latch mode BTR_MODIFY_LEAF or @@ -211,8 +204,6 @@ row_purge_remove_sec_if_poss_low( mtr_t mtr; mtr_t* mtr_vers; - UT_NOT_USED(thr); - log_free_check(); mtr_start(&mtr); @@ -221,7 +212,7 @@ row_purge_remove_sec_if_poss_low( if (!found) { /* Not found */ - /* printf("PURGE:........sec entry not found\n"); */ + /* fputs("PURGE:........sec entry not found\n", stderr); */ /* dtuple_print(entry); */ btr_pcur_close(&pcur); @@ -284,23 +275,22 @@ void row_purge_remove_sec_if_poss( /*=========================*/ purge_node_t* node, /* in: row purge node */ - que_thr_t* thr, /* in: query thread */ dict_index_t* index, /* in: index */ dtuple_t* entry) /* in: index entry */ { ibool success; ulint n_tries = 0; -/* printf("Purge: Removing secondary record\n"); */ +/* fputs("Purge: Removing secondary record\n", stderr); */ - success = row_purge_remove_sec_if_poss_low(node, thr, index, entry, + success = row_purge_remove_sec_if_poss_low(node, index, entry, BTR_MODIFY_LEAF); if (success) { return; } retry: - success = row_purge_remove_sec_if_poss_low(node, thr, index, entry, + success = row_purge_remove_sec_if_poss_low(node, index, entry, BTR_MODIFY_TREE); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database @@ -324,14 +314,13 @@ static void row_purge_del_mark( /*===============*/ - purge_node_t* node, /* in: row purge node */ - que_thr_t* thr) /* in: query thread */ + purge_node_t* node) /* in: row purge node */ { mem_heap_t* heap; dtuple_t* entry; dict_index_t* index; - ut_ad(node && thr); + ut_ad(node); heap = mem_heap_create(1024); @@ -341,14 +330,14 @@ row_purge_del_mark( /* Build the index entry */ entry = row_build_index_entry(node->row, index, heap); - row_purge_remove_sec_if_poss(node, thr, index, entry); + row_purge_remove_sec_if_poss(node, index, entry); node->index = dict_table_get_next_index(node->index); } mem_heap_free(heap); - row_purge_remove_clust_if_poss(node, thr); + row_purge_remove_clust_if_poss(node); } /*************************************************************** @@ -358,8 +347,7 @@ static void row_purge_upd_exist_or_extern( /*==========================*/ - purge_node_t* node, /* in: row purge node */ - que_thr_t* thr) /* in: query thread */ + purge_node_t* node) /* in: row purge node */ { mem_heap_t* heap; dtuple_t* entry; @@ -375,7 +363,7 @@ row_purge_upd_exist_or_extern( ulint i; mtr_t mtr; - ut_ad(node && thr); + ut_ad(node); if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { @@ -392,7 +380,7 @@ row_purge_upd_exist_or_extern( /* Build the older version of the index entry */ entry = row_build_index_entry(node->row, index, heap); - row_purge_remove_sec_if_poss(node, thr, index, entry); + row_purge_remove_sec_if_poss(node, index, entry); } node->index = dict_table_get_next_index(node->index); @@ -519,7 +507,7 @@ row_purge_parse_undo_rec( mutex_enter(&(dict_sys->mutex)); - node->table = dict_table_get_on_id_low(table_id, thr_get_trx(thr)); + node->table = dict_table_get_on_id_low(table_id, trx); mutex_exit(&(dict_sys->mutex)); @@ -619,12 +607,12 @@ row_purge( dict_table_get_first_index(node->table)); if (node->rec_type == TRX_UNDO_DEL_MARK_REC) { - row_purge_del_mark(node, thr); + row_purge_del_mark(node); } else if (updated_extern || node->rec_type == TRX_UNDO_UPD_EXIST_REC) { - row_purge_upd_exist_or_extern(node, thr); + row_purge_upd_exist_or_extern(node); } if (node->found_clust) { diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c index 6820cb5bccd..680539764fd 100644 --- a/innobase/row/row0row.c +++ b/innobase/row/row0row.c @@ -390,7 +390,6 @@ row_build_row_ref_in_tuple( at least s-latched and the latch held as long as the row reference is used! */ { - dict_table_t* table; dict_index_t* clust_index; dfield_t* dfield; byte* field; @@ -401,21 +400,21 @@ row_build_row_ref_in_tuple( ut_a(ref && index && rec); - table = index->table; - - if (!table) { - fprintf(stderr, "InnoDB: table %s for index %s not found\n", - index->table_name, index->name); + if (!index->table) { + fputs("InnoDB: table ", stderr); + notfound: + ut_print_name(stderr, index->table_name); + fputs(" for index ", stderr); + ut_print_name(stderr, index->name); + fputs(" not found\n", stderr); ut_error; } - clust_index = dict_table_get_first_index(table); + clust_index = dict_table_get_first_index(index->table); if (!clust_index) { - fprintf(stderr, - "InnoDB: clust index for table %s for index %s not found\n", - index->table_name, index->name); - ut_error; + fputs("InnoDB: clust index for table ", stderr); + goto notfound; } ref_len = dict_index_get_n_unique(clust_index); @@ -568,7 +567,7 @@ row_get_clust_rec( found = row_search_on_row_ref(&pcur, mode, table, ref, mtr); - clust_rec = btr_pcur_get_rec(&pcur); + clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL; mem_heap_free(heap); @@ -576,11 +575,6 @@ row_get_clust_rec( *clust_index = dict_table_get_first_index(table); - if (!found) { - - return(NULL); - } - return(clust_rec); } diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 4f70cea2058..4c43f75125c 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -1756,7 +1756,7 @@ row_sel_step( return(NULL); } else { /* SQL error detected */ - printf("SQL error %lu\n", (ulong) err); + fprintf(stderr, "SQL error %lu\n", (ulong) err); que_thr_handle_error(thr, DB_ERROR, NULL, 0); @@ -1806,7 +1806,7 @@ fetch_step( if (sel_node->state == SEL_NODE_CLOSED) { /* SQL error detected */ - printf("SQL error %lu\n", (ulong) DB_ERROR); + fprintf(stderr, "SQL error %lu\n", (ulong)DB_ERROR); que_thr_handle_error(thr, DB_ERROR, NULL, 0); @@ -1867,12 +1867,12 @@ row_printf_step( while (arg) { dfield_print_also_hex(que_node_get_val(arg)); - printf(" ::: "); + fputs(" ::: ", stderr); arg = que_node_get_next(arg); } - printf("\n"); + putc('\n', stderr); /* Fetch next row to print */ @@ -1981,9 +1981,10 @@ row_sel_convert_mysql_key_to_innobase( MySQL */ if (key_ptr[data_offset + 1] != 0) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: BLOB or TEXT prefix > 255 bytes in query to table %s\n", - index->table_name); + fputs( +" InnoDB: Error: BLOB or TEXT prefix > 255 bytes in query to table ", stderr); + ut_print_name(stderr, index->table_name); + putc('\n', stderr); } data_len = key_ptr[data_offset]; @@ -2034,8 +2035,7 @@ row_sel_convert_mysql_key_to_innobase( (ulong) data_field_len, (ulong) (key_ptr - key_end)); fflush(stderr); - ut_print_buf(original_key_ptr, key_len); - fflush(stdout); + ut_print_buf(stderr, original_key_ptr, key_len); fprintf(stderr, "\n"); if (!is_null) { @@ -2068,20 +2068,18 @@ row_sel_store_row_id_to_prebuilt( { byte* data; ulint len; - char err_buf[1000]; - data = rec_get_nth_field(index_rec, dict_index_get_sys_col_pos(index, DATA_ROW_ID), &len); if (len != DATA_ROW_ID_LEN) { - rec_sprintf(err_buf, 900, index_rec); - fprintf(stderr, -"InnoDB: Error: Row id field is wrong length %lu in table %s index %s\n" -"InnoDB: Field number %lu, record:\n%s\n", - (ulong) len, index->table_name, index->name, - (ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID), - err_buf); +"InnoDB: Error: Row id field is wrong length %lu in ", (ulong) len); + dict_index_name_print(stderr, index); + fprintf(stderr, "\n" +"InnoDB: Field number %lu, record:\n", + (ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID)); + rec_print(stderr, index_rec); + putc('\n', stderr); ut_error; } @@ -2365,8 +2363,7 @@ row_sel_get_clust_rec_for_mysql( rec_t* old_vers; ulint err; trx_t* trx; - char err_buf[1000]; - + *out_rec = NULL; row_build_row_ref_in_tuple(prebuilt->clust_ref, sec_index, rec); @@ -2399,26 +2396,22 @@ row_sel_get_clust_rec_for_mysql( || prebuilt->select_lock_type != LOCK_NONE) { ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: error clustered record for sec rec not found\n" - "InnoDB: index %s table %s\n", sec_index->name, - sec_index->table->name); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, - "InnoDB: sec index record %s\n", err_buf); - - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, - "InnoDB: clust index record %s\n", err_buf); - - trx = thr_get_trx(thr); - trx_print(err_buf, trx); - - fprintf(stderr, - "%s\nInnoDB: Make a detailed bug report and send it\n", - err_buf); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + fputs(" InnoDB: error clustered record" + " for sec rec not found\n" + "InnoDB: ", stderr); + dict_index_name_print(stderr, sec_index); + fputs("\n" + "InnoDB: sec index record ", stderr); + rec_print(stderr, rec); + fputs("\n" + "InnoDB: clust index record ", stderr); + rec_print(stderr, clust_rec); + putc('\n', stderr); + trx_print(stderr, thr_get_trx(thr)); + + fputs("\n" + "InnoDB: Make a detailed bug report and send it\n" + "InnoDB: to mysql@lists.mysql.com\n", stderr); } clust_rec = NULL; @@ -2767,8 +2760,10 @@ row_search_for_mysql( if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" - "InnoDB: table handle. Magic n %lu, table name %s\n", - (ulong) prebuilt->magic_n, prebuilt->table->name); + "InnoDB: table handle. Magic n %lu, table name ", + (ulong) prebuilt->magic_n); + ut_print_name(stderr, prebuilt->table->name); + putc('\n', stderr); mem_analyze_corruption((byte*)prebuilt); @@ -2776,21 +2771,19 @@ row_search_for_mysql( } if (trx->n_mysql_tables_in_use == 0) { - char err_buf[1000]; - - trx_print(err_buf, trx); - - fprintf(stderr, + fputs( "InnoDB: Error: MySQL is trying to perform a SELECT\n" -"InnoDB: but it has not locked any tables in ::external_lock()!\n%s\n", - err_buf); +"InnoDB: but it has not locked any tables in ::external_lock()!\n", + stderr); + trx_print(stderr, trx); + fputc('\n', stderr); ut_a(0); } -/* printf("Match mode %lu\n search tuple ", match_mode); +/* fprintf(stderr, "Match mode %lu\n search tuple ", (ulong) match_mode); dtuple_print(search_tuple); - printf("N tables locked %lu\n", trx->mysql_n_tables_locked); + fprintf(stderr, "N tables locked %lu\n", trx->mysql_n_tables_locked); */ /*-------------------------------------------------------------*/ /* PHASE 0: Release a possible s-latch we are holding on the @@ -2974,7 +2967,8 @@ row_search_for_mysql( mtr_commit(&mtr); - /* printf("%s shortcut\n", index->name); */ + /* ut_print_name(stderr, index->name); + fputs(" shortcut\n", stderr); */ srv_n_rows_read++; @@ -2998,8 +2992,8 @@ row_search_for_mysql( mtr_commit(&mtr); - /* printf("%s record not found 2\n", - index->name); */ + /* ut_print_name(stderr, index->name); + fputs(" record not found 2\n", stderr); */ if (trx->search_latch_timeout > 0 && trx->has_search_latch) { @@ -3095,14 +3089,12 @@ shortcut_fails_too_big_rec: if (trx->read_view == NULL && prebuilt->select_lock_type == LOCK_NONE) { - char err_buf[1000]; - - trx_print(err_buf, trx); - fprintf(stderr, + fputs( "InnoDB: Error: MySQL is trying to perform a consistent read\n" -"InnoDB: but the read view is not assigned!\n%s\n", err_buf); - +"InnoDB: but the read view is not assigned!\n", stderr); + trx_print(stderr, trx); + fputc('\n', stderr); ut_a(0); } } else if (prebuilt->select_lock_type == LOCK_NONE) { @@ -3131,8 +3123,9 @@ rec_loop: rec = btr_pcur_get_rec(pcur); /* - printf("Using index %s cnt %lu ", index->name, cnt); - printf("; Page no %lu\n", + fputs("Using ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, " cnt %lu ; Page no %lu\n", cnt, buf_frame_get_page_no(buf_frame_align(rec))); rec_print(rec); */ @@ -3178,12 +3171,14 @@ rec_loop: ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n" -"InnoDB: index %s, table %s. Run CHECK TABLE to table. You may need to\n" +"InnoDB: ", + (ulong) (rec - buf_frame_align(rec)), + (ulong) next_offs, + (ulong) buf_frame_get_page_no(rec)); + dict_index_name_print(stderr, index); + fputs(". Run CHECK TABLE. You may need to\n" "InnoDB: restore from a backup, or dump + drop + reimport the table.\n", - (ulong) (rec - buf_frame_align(rec)), - (ulong) next_offs, - (ulong) buf_frame_get_page_no(rec), index->name, - index->table_name); + stderr); err = DB_CORRUPTION; @@ -3194,11 +3189,13 @@ rec_loop: fprintf(stderr, "InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n" -"InnoDB: index %s, table %s. We try to skip the rest of the page.\n", +"InnoDB: ", (ulong) (rec - buf_frame_align(rec)), (ulong) next_offs, - (ulong) buf_frame_get_page_no(rec), index->name, - index->table_name); + (ulong) buf_frame_get_page_no(rec)); + dict_index_name_print(stderr, index); + fputs(". We try to skip the rest of the page.\n", + stderr); btr_pcur_move_to_last_on_page(pcur, &mtr); @@ -3210,12 +3207,14 @@ rec_loop: if (!rec_validate(rec) || !btr_index_rec_validate(rec, index, FALSE)) { fprintf(stderr, -"InnoDB: Index record corruption: rec offs %lu next offs %lu, page no %lu,\n" -"InnoDB: index %s, table %s. We try to skip the record.\n", +"InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n" +"InnoDB: ", (ulong) (rec - buf_frame_align(rec)), (ulong) next_offs, - (ulong) buf_frame_get_page_no(rec), index->name, - index->table_name); + (ulong) buf_frame_get_page_no(rec)); + dict_index_name_print(stderr, index); + fputs(". We try to skip the record.\n", + stderr); goto next_rec; } @@ -3232,7 +3231,7 @@ rec_loop: /* Test if the index record matches completely to search_tuple in prebuilt: if not, then we return with DB_RECORD_NOT_FOUND */ - /* printf("Comparing rec and search tuple\n"); */ + /* fputs("Comparing rec and search tuple\n", stderr); */ if (0 != cmp_dtuple_rec(search_tuple, rec)) { @@ -3252,7 +3251,8 @@ rec_loop: btr_pcur_store_position(pcur, &mtr); ret = DB_RECORD_NOT_FOUND; - /* printf("%s record not found 3\n", index->name); */ + /* ut_print_name(stderr, index->name); + fputs(" record not found 3\n", stderr); */ goto normal_return; } @@ -3277,7 +3277,8 @@ rec_loop: btr_pcur_store_position(pcur, &mtr); ret = DB_RECORD_NOT_FOUND; - /* printf("%s record not found 4\n", index->name); */ + /* ut_print_name(stderr, index->name); + fputs(" record not found 4\n", stderr); */ goto normal_return; } @@ -3547,8 +3548,9 @@ lock_wait_or_error: goto rec_loop; } - /* printf("Using index %s cnt %lu ret value %lu err\n", index->name, - cnt, err); */ +/* fputs("Using ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */ trx->op_info = (char *) ""; return(err); @@ -3565,8 +3567,9 @@ normal_return: ret = DB_SUCCESS; } - /* printf("Using index %s cnt %lu ret value %lu\n", index->name, - cnt, err); */ +/* fputs("Using ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */ if (ret == DB_SUCCESS) { srv_n_rows_read++; } diff --git a/innobase/row/row0uins.c b/innobase/row/row0uins.c index 08f0e29c839..9dc860d70b1 100644 --- a/innobase/row/row0uins.c +++ b/innobase/row/row0uins.c @@ -37,8 +37,7 @@ ulint row_undo_ins_remove_clust_rec( /*==========================*/ /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ - undo_node_t* node, /* in: undo node */ - que_thr_t* thr) /* in: query thread */ + undo_node_t* node) /* in: undo node */ { btr_cur_t* btr_cur; ibool success; @@ -46,8 +45,6 @@ row_undo_ins_remove_clust_rec( ulint n_tries = 0; mtr_t mtr; - UT_NOT_USED(thr); - mtr_start(&mtr); success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur), @@ -126,8 +123,7 @@ row_undo_ins_remove_sec_low( depending on whether we wish optimistic or pessimistic descent down the index tree */ dict_index_t* index, /* in: index */ - dtuple_t* entry, /* in: index entry to remove */ - que_thr_t* thr) /* in: query thread */ + dtuple_t* entry) /* in: index entry to remove */ { btr_pcur_t pcur; btr_cur_t* btr_cur; @@ -136,8 +132,6 @@ row_undo_ins_remove_sec_low( ulint err; mtr_t mtr; - UT_NOT_USED(thr); - log_free_check(); mtr_start(&mtr); @@ -148,15 +142,6 @@ row_undo_ins_remove_sec_low( if (!found) { /* Not found */ - /* FIXME: remove printfs in the final version */ - - /* printf( - "--UNDO INS: Record not found from page %lu index %s\n", - buf_frame_get_page_no(btr_cur_get_rec(btr_cur)), - index->name); */ - - /* ibuf_print(); */ - btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -192,15 +177,14 @@ row_undo_ins_remove_sec( /*====================*/ /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ dict_index_t* index, /* in: index */ - dtuple_t* entry, /* in: index entry to insert */ - que_thr_t* thr) /* in: query thread */ + dtuple_t* entry) /* in: index entry to insert */ { ulint err; ulint n_tries = 0; /* Try first optimistic descent to the B-tree */ - err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry, thr); + err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry); if (err == DB_SUCCESS) { @@ -209,7 +193,7 @@ row_undo_ins_remove_sec( /* Try then pessimistic descent to the B-tree */ retry: - err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry, thr); + err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database @@ -233,8 +217,7 @@ static void row_undo_ins_parse_undo_rec( /*========================*/ - undo_node_t* node, /* in: row undo node */ - que_thr_t* thr __attribute__((unused))) /* in: query thread */ + undo_node_t* node) /* in: row undo node */ { dict_index_t* clust_index; byte* ptr; @@ -244,7 +227,7 @@ row_undo_ins_parse_undo_rec( ulint dummy; ibool dummy_extern; - ut_ad(node && thr); + ut_ad(node); ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy, &dummy_extern, &undo_no, &table_id); @@ -280,22 +263,21 @@ ulint row_undo_ins( /*=========*/ /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ - undo_node_t* node, /* in: row undo node */ - que_thr_t* thr) /* in: query thread */ + undo_node_t* node) /* in: row undo node */ { dtuple_t* entry; ibool found; ulint err; - - ut_ad(node && thr); + + ut_ad(node); ut_ad(node->state == UNDO_NODE_INSERT); - row_undo_ins_parse_undo_rec(node, thr); + row_undo_ins_parse_undo_rec(node); if (node->table == NULL) { found = FALSE; } else { - found = row_undo_search_clust_to_pcur(node, thr); + found = row_undo_search_clust_to_pcur(node); } if (!found) { @@ -310,7 +292,7 @@ row_undo_ins( while (node->index != NULL) { entry = row_build_index_entry(node->row, node->index, node->heap); - err = row_undo_ins_remove_sec(node->index, entry, thr); + err = row_undo_ins_remove_sec(node->index, entry); if (err != DB_SUCCESS) { @@ -320,7 +302,7 @@ row_undo_ins( node->index = dict_table_get_next_index(node->index); } - err = row_undo_ins_remove_clust_rec(node, thr); + err = row_undo_ins_remove_clust_rec(node); return(err); } diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c index 1bfd71f8c64..3c181ed5493 100644 --- a/innobase/row/row0umod.c +++ b/innobase/row/row0umod.c @@ -95,14 +95,11 @@ row_undo_mod_clust_low( ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { big_rec_t* dummy_big_rec; - dict_index_t* index; btr_pcur_t* pcur; btr_cur_t* btr_cur; ulint err; ibool success; - index = dict_table_get_first_index(node->table); - pcur = &(node->pcur); btr_cur = btr_pcur_get_btr_cur(pcur); @@ -317,13 +314,6 @@ row_undo_mod_del_mark_or_remove_sec_low( if (!found) { /* Not found */ - /* FIXME: remove printfs in the final version */ - - /* printf( - "--UNDO MOD: Record not found from page %lu index %s\n", - buf_frame_get_page_no(btr_cur_get_rec(btr_cur)), - index->name); */ - btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -421,49 +411,40 @@ row_undo_mod_del_unmark_sec_and_undo_update( DB_OUT_OF_FILE_SPACE */ ulint mode, /* in: search mode: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ - undo_node_t* node, /* in: row undo node */ que_thr_t* thr, /* in: query thread */ dict_index_t* index, /* in: index */ dtuple_t* entry) /* in: index entry */ { mem_heap_t* heap; btr_pcur_t pcur; - btr_cur_t* btr_cur; upd_t* update; - rec_t* rec; ulint err = DB_SUCCESS; ibool found; big_rec_t* dummy_big_rec; mtr_t mtr; - char err_buf[1000]; - UT_NOT_USED(node); - log_free_check(); mtr_start(&mtr); found = row_search_index_entry(index, entry, mode, &pcur, &mtr); if (!found) { - fprintf(stderr, - "InnoDB: error in sec index entry del undo in\n" - "InnoDB: index %s table %s\n", index->name, - index->table->name); - dtuple_sprintf(err_buf, 900, entry); - fprintf(stderr, "InnoDB: tuple %s\n", err_buf); - - rec_sprintf(err_buf, 900, btr_pcur_get_rec(&pcur)); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - - trx_print(err_buf, thr_get_trx(thr)); - fprintf(stderr, - "%s\nInnoDB: Make a detailed bug report and send it\n", - err_buf); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + fputs("InnoDB: error in sec index entry del undo in\n" + "InnoDB: ", stderr); + dict_index_name_print(stderr, index); + fputs("\n" + "InnoDB: tuple ", stderr); + dtuple_print(stderr, entry); + fputs("\n" + "InnoDB: record ", stderr); + rec_print(stderr, btr_pcur_get_rec(&pcur)); + putc('\n', stderr); + trx_print(stderr, thr_get_trx(thr)); + fputs("\n" + "InnoDB: Make a detailed bug report and send it\n" + "InnoDB: to mysql@lists.mysql.com\n", stderr); } else { - btr_cur = btr_pcur_get_btr_cur(&pcur); - - rec = btr_cur_get_rec(btr_cur); + btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG, btr_cur, FALSE, thr, &mtr); @@ -471,7 +452,7 @@ row_undo_mod_del_unmark_sec_and_undo_update( heap = mem_heap_create(100); update = row_upd_build_sec_rec_difference_binary(index, entry, - rec, heap); + btr_cur_get_rec(btr_cur), heap); if (upd_get_n_fields(update) == 0) { /* Do nothing */ @@ -566,11 +547,11 @@ row_undo_mod_del_mark_sec( err = row_undo_mod_del_unmark_sec_and_undo_update( BTR_MODIFY_LEAF, - node, thr, index, entry); + thr, index, entry); if (err == DB_FAIL) { err = row_undo_mod_del_unmark_sec_and_undo_update( BTR_MODIFY_TREE, - node, thr, index, entry); + thr, index, entry); } if (err != DB_SUCCESS) { @@ -649,12 +630,12 @@ row_undo_mod_upd_exist_sec( node->update, NULL); err = row_undo_mod_del_unmark_sec_and_undo_update( BTR_MODIFY_LEAF, - node, thr, index, entry); + thr, index, entry); if (err == DB_FAIL) { err = row_undo_mod_del_unmark_sec_and_undo_update( BTR_MODIFY_TREE, - node, thr, index, entry); + thr, index, entry); } if (err != DB_SUCCESS) { @@ -752,7 +733,7 @@ row_undo_mod( if (node->table == NULL) { found = FALSE; } else { - found = row_undo_search_clust_to_pcur(node, thr); + found = row_undo_search_clust_to_pcur(node); } if (!found) { diff --git a/innobase/row/row0undo.c b/innobase/row/row0undo.c index 613d0a3b890..bc3cc8ea9f3 100644 --- a/innobase/row/row0undo.c +++ b/innobase/row/row0undo.c @@ -144,8 +144,7 @@ row_undo_search_clust_to_pcur( /* out: TRUE if found; NOTE the node->pcur must be closed by the caller, regardless of the return value */ - undo_node_t* node, /* in: row undo node */ - que_thr_t* thr) /* in: query thread */ + undo_node_t* node) /* in: row undo node */ { dict_index_t* clust_index; ibool found; @@ -153,8 +152,6 @@ row_undo_search_clust_to_pcur( ibool ret; rec_t* rec; - UT_NOT_USED(thr); - mtr_start(&mtr); clust_index = dict_table_get_first_index(node->table); @@ -172,8 +169,8 @@ row_undo_search_clust_to_pcur( is to make sure that some thread will eventually undo the modification corresponding to node->roll_ptr. */ - /* printf("--------------------undoing a previous version\n"); - */ + /* fputs("--------------------undoing a previous version\n", + stderr); */ ret = FALSE; } else { @@ -269,7 +266,7 @@ row_undo( if (node->state == UNDO_NODE_INSERT) { - err = row_undo_ins(node, thr); + err = row_undo_ins(node); node->state = UNDO_NODE_FETCH_NEXT; } else { diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index f8739b65c2f..82eb112fc77 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -1202,7 +1202,6 @@ row_upd_sec_index_entry( rec_t* rec; ulint err = DB_SUCCESS; mtr_t mtr; - char err_buf[1000]; index = node->index; @@ -1223,21 +1222,22 @@ row_upd_sec_index_entry( rec = btr_cur_get_rec(btr_cur); if (!found) { - fprintf(stderr, "InnoDB: error in sec index entry update in\n" - "InnoDB: index %s table %s\n", index->name, - index->table->name); - dtuple_sprintf(err_buf, 900, entry); - fprintf(stderr, "InnoDB: tuple %s\n", err_buf); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - - trx_print(err_buf, thr_get_trx(thr)); - - fprintf(stderr, - "%s\nInnoDB: Make a detailed bug report and send it\n", - err_buf); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + fputs("InnoDB: error in sec index entry update in\n" + "InnoDB: ", stderr); + dict_index_name_print(stderr, index); + fputs("\n" + "InnoDB: tuple ", stderr); + dtuple_print(stderr, entry); + fputs("\n" + "InnoDB: record ", stderr); + rec_print(stderr, rec); + putc('\n', stderr); + + trx_print(stderr, thr_get_trx(thr)); + + fputs("\n" + "InnoDB: Make a detailed bug report and send it\n" + "InnoDB: to mysql@lists.mysql.com\n", stderr); } else { /* Delete mark the old index record; it can already be delete marked if we return after a lock wait in diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 838e63b3e25..73bbd145517 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -52,9 +52,6 @@ Created 10/8/1995 Heikki Tuuri affects only FOREIGN KEY definition parsing */ ibool srv_lower_case_table_names = FALSE; -/* Buffer which can be used in printing fatal error messages */ -char srv_fatal_errbuf[5000]; - /* The following counter is incremented whenever there is some user activity in the server */ ulint srv_activity_count = 0; @@ -303,12 +300,17 @@ ulint srv_test_n_mutexes = ULINT_MAX; /* Array of English strings describing the current state of an i/o handler thread */ -char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS]; -char* srv_io_thread_function[SRV_MAX_N_IO_THREADS]; +const char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS]; +const char* srv_io_thread_function[SRV_MAX_N_IO_THREADS]; time_t srv_last_monitor_time; -mutex_t srv_innodb_monitor_mutex; +mutex_t srv_innodb_monitor_mutex; + +/* Mutex for locking srv_monitor_file */ +mutex_t srv_monitor_file_mutex; +/* Temporary file for innodb monitor output */ +FILE* srv_monitor_file; ulint srv_main_thread_process_no = 0; ulint srv_main_thread_id = 0; @@ -532,6 +534,20 @@ are indexed by the type of the thread. */ ulint srv_n_threads_active[SRV_MASTER + 1]; ulint srv_n_threads[SRV_MASTER + 1]; +/************************************************************************* +Sets the info describing an i/o thread current state. */ + +void +srv_set_io_thread_op_info( +/*======================*/ + ulint i, /* in: the 'segment' of the i/o thread */ + const char* str) /* in: constant char string describing the + state */ +{ + ut_a(i < SRV_MAX_N_IO_THREADS); + + srv_io_thread_op_info[i] = str; +} /************************************************************************* Accessor function to get pointer to n'th slot in the server thread @@ -631,10 +647,10 @@ srv_suspend_thread(void) slot_no = thr_local_get_slot_no(os_thread_get_curr_id()); if (srv_print_thread_releases) { - - printf("Suspending thread %lu to slot %lu meter %lu\n", - (ulong) os_thread_get_curr_id(), (ulong) slot_no, - (ulong) srv_meter[SRV_RECOVERY]); + fprintf(stderr, + "Suspending thread %lu to slot %lu meter %lu\n", + (ulong) os_thread_get_curr_id(), (ulong) slot_no, + (ulong) srv_meter[SRV_RECOVERY]); } slot = srv_table_get_nth_slot(slot_no); @@ -694,7 +710,7 @@ srv_release_threads( os_event_set(slot->event); if (srv_print_thread_releases) { - printf( + fprintf(stderr, "Releasing thread %lu type %lu from slot %lu meter %lu\n", (ulong) slot->id, (ulong) type, (ulong) i, (ulong) srv_meter[SRV_RECOVERY]); @@ -853,7 +869,6 @@ srv_conc_enter_innodb( ibool has_slept = FALSE; srv_conc_slot_t* slot = NULL; ulint i; - char err_buf[1000]; if (srv_thread_concurrency >= 500) { /* Disable the concurrency check */ @@ -874,12 +889,11 @@ srv_conc_enter_innodb( retry: if (trx->declared_to_be_inside_innodb) { ut_print_timestamp(stderr); - - trx_print(err_buf, trx); - - fprintf(stderr, + fputs( " InnoDB: Error: trying to declare trx to enter InnoDB, but\n" -"InnoDB: it already is declared.\n%s\n", err_buf); +"InnoDB: it already is declared.\n", stderr); + trx_print(stderr, trx); + putc('\n', stderr); os_fast_mutex_unlock(&srv_conc_mutex); return; @@ -1420,15 +1434,13 @@ srv_refresh_innodb_monitor_stats(void) } /********************************************************************** -Sprintfs to a buffer the output of the InnoDB Monitor. */ +Outputs to a file the output of the InnoDB Monitor. */ void -srv_sprintf_innodb_monitor( -/*=======================*/ - char* buf, /* in/out: buffer which must be at least 4 kB */ - ulint len) /* in: length of the buffer */ +srv_printf_innodb_monitor( +/*======================*/ + FILE* file) /* in: output stream */ { - char* buf_end = buf + len - 2000; double time_elapsed; time_t current_time; ulint n_reserved; @@ -1446,28 +1458,20 @@ srv_sprintf_innodb_monitor( srv_last_monitor_time = time(NULL); - ut_a(len >= 4096); - - buf += sprintf(buf, "\n=====================================\n"); - - ut_sprintf_timestamp(buf); - buf = buf + strlen(buf); - ut_a(buf < buf_end + 1500); - - buf += sprintf(buf, " INNODB MONITOR OUTPUT\n" - "=====================================\n"); + rewind(file); + fputs("\n=====================================\n", file); - buf += sprintf(buf, -"Per second averages calculated from the last %lu seconds\n", - (ulong) time_elapsed); - - buf += sprintf(buf, "----------\n" - "SEMAPHORES\n" - "----------\n"); - sync_print(buf, buf_end); + ut_print_timestamp(file); + fprintf(file, + " INNODB MONITOR OUTPUT\n" + "=====================================\n" + "Per second averages calculated from the last %lu seconds\n", + (ulong)time_elapsed); - buf = buf + strlen(buf); - ut_a(buf < buf_end + 1500); + fputs("----------\n" + "SEMAPHORES\n" + "----------\n", file); + sync_print(file); /* Conceptually, srv_innodb_monitor_mutex has a very high latching order level in sync0sync.h, while dict_foreign_err_mutex has a very @@ -1476,43 +1480,29 @@ srv_sprintf_innodb_monitor( mutex_enter(&dict_foreign_err_mutex); - if (*dict_foreign_err_buf != '\0') { - buf += sprintf(buf, - "------------------------\n" - "LATEST FOREIGN KEY ERROR\n" - "------------------------\n"); - - if (buf_end - buf > 6000) { - buf+= sprintf(buf, "%.4000s", dict_foreign_err_buf); - } - } + if (ftell(dict_foreign_err_file) != 0L) { + fputs("------------------------\n" + "LATEST FOREIGN KEY ERROR\n" + "------------------------\n", file); + ut_copy_file(file, dict_foreign_err_file); + } mutex_exit(&dict_foreign_err_mutex); - ut_a(buf < buf_end + 1500); + lock_print_info(file); + fputs("--------\n" + "FILE I/O\n" + "--------\n", file); + os_aio_print(file); - lock_print_info(buf, buf_end); - buf = buf + strlen(buf); - - buf += sprintf(buf, "--------\n" - "FILE I/O\n" - "--------\n"); - os_aio_print(buf, buf_end); - buf = buf + strlen(buf); - ut_a(buf < buf_end + 1500); - - buf += sprintf(buf, "-------------------------------------\n" - "INSERT BUFFER AND ADAPTIVE HASH INDEX\n" - "-------------------------------------\n"); - ibuf_print(buf, buf_end); - buf = buf + strlen(buf); - ut_a(buf < buf_end + 1500); - - ha_print_info(buf, buf_end, btr_search_sys->hash_index); - buf = buf + strlen(buf); - ut_a(buf < buf_end + 1500); - - buf += sprintf(buf, + fputs("-------------------------------------\n" + "INSERT BUFFER AND ADAPTIVE HASH INDEX\n" + "-------------------------------------\n", file); + ibuf_print(file); + + ha_print_info(file, btr_search_sys->hash_index); + + fprintf(file, "%.2f hash searches/s, %.2f non-hash searches/s\n", (btr_cur_n_sea - btr_cur_n_sea_old) / time_elapsed, @@ -1521,74 +1511,66 @@ srv_sprintf_innodb_monitor( btr_cur_n_sea_old = btr_cur_n_sea; btr_cur_n_non_sea_old = btr_cur_n_non_sea; - buf += sprintf(buf,"---\n" + fputs("---\n" "LOG\n" - "---\n"); - log_print(buf, buf_end); - buf = buf + strlen(buf); - ut_a(buf < buf_end + 1500); - - buf += sprintf(buf, "----------------------\n" + "---\n", file); + log_print(file); + + fputs("----------------------\n" "BUFFER POOL AND MEMORY\n" - "----------------------\n"); - buf += sprintf(buf, + "----------------------\n", file); + fprintf(file, "Total memory allocated " ULINTPF "; in additional pool allocated " ULINTPF "\n", ut_total_allocated_memory, mem_pool_get_reserved(mem_comm_pool)); if (mem_out_of_mem_err_msg_count > 0) { - buf += sprintf(buf, + fprintf(file, "Mem allocation has spilled out of additional mem pool" ULINTPF "times\n", mem_out_of_mem_err_msg_count); } if (srv_use_awe) { - buf += sprintf(buf, + fprintf(file, "In addition to that %lu MB of AWE memory allocated\n", (ulong) (srv_pool_size / ((1024 * 1024) / UNIV_PAGE_SIZE))); } - buf_print_io(buf, buf_end); - buf = buf + strlen(buf); - ut_a(buf < buf_end + 1500); - - buf += sprintf(buf, "--------------\n" - "ROW OPERATIONS\n" - "--------------\n"); - buf += sprintf(buf, - "%ld queries inside InnoDB, %lu queries in queue\n", - (long) srv_conc_n_threads, - (ulong) srv_conc_n_waiting_threads); + buf_print_io(file); + fputs("--------------\n" + "ROW OPERATIONS\n" + "--------------\n", file); + fprintf(file, "%ld queries inside InnoDB, %lu queries in queue\n", + (long) srv_conc_n_threads, + (ulong) srv_conc_n_waiting_threads); n_reserved = fil_space_get_n_reserved_extents(0); if (n_reserved > 0) { - buf += sprintf(buf, + fprintf(file, "%lu tablespace extents now reserved for B-tree split operations\n", (ulong) n_reserved); } #ifdef UNIV_LINUX - buf += sprintf(buf, - "Main thread process no. %lu, id %lu, state: %.29s\n", + fprintf(file, "Main thread process no. %lu, id %lu, state: %s\n", (ulong) srv_main_thread_process_no, (ulong) srv_main_thread_id, srv_main_thread_op_info); #else - buf += sprintf(buf, - "Main thread id %lu, state: %.29s\n", + fprintf(file, "Main thread id %lu, state: %s\n", (ulong) srv_main_thread_id, srv_main_thread_op_info); #endif - buf += sprintf(buf, + fprintf(file, "Number of rows inserted " ULINTPF ", updated " ULINTPF ", deleted " ULINTPF ", read " ULINTPF "\n", srv_n_rows_inserted, srv_n_rows_updated, srv_n_rows_deleted, srv_n_rows_read); - buf += sprintf(buf, + fprintf(file, "%.2f inserts/s, %.2f updates/s, %.2f deletes/s, %.2f reads/s\n", (srv_n_rows_inserted - srv_n_rows_inserted_old) / time_elapsed, @@ -1604,12 +1586,12 @@ srv_sprintf_innodb_monitor( srv_n_rows_deleted_old = srv_n_rows_deleted; srv_n_rows_read_old = srv_n_rows_read; - buf += sprintf(buf, "----------------------------\n" + fputs("----------------------------\n" "END OF INNODB MONITOR OUTPUT\n" - "============================\n"); - ut_a(buf < buf_end + 1900); + "============================\n", file); mutex_exit(&srv_innodb_monitor_mutex); + fflush(file); } /************************************************************************* @@ -1624,7 +1606,8 @@ ulint srv_lock_timeout_and_monitor_thread( /*================================*/ /* out: a dummy parameter */ - void* arg) /* in: a dummy parameter required by + void* arg __attribute__((unused))) + /* in: a dummy parameter required by os_thread_create */ { srv_slot_t* slot; @@ -1634,11 +1617,10 @@ srv_lock_timeout_and_monitor_thread( time_t last_monitor_time; ibool some_waits; double wait_time; - char* buf; ulint i; #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Lock timeout thread starts, id %lu\n", + fprintf(stderr, "Lock timeout thread starts, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif UT_NOT_USED(arg); @@ -1667,55 +1649,56 @@ loop: last_monitor_time = time(NULL); if (srv_print_innodb_monitor) { + srv_printf_innodb_monitor(stderr); + } - buf = mem_alloc(100000); - - srv_sprintf_innodb_monitor(buf, 90000); - - ut_a(strlen(buf) < 99000); - - printf("%s", buf); - - mem_free(buf); - } + mutex_enter(&srv_monitor_file_mutex); + rewind(srv_monitor_file); + srv_printf_innodb_monitor(srv_monitor_file); + mutex_exit(&srv_monitor_file_mutex); - if (srv_print_innodb_tablespace_monitor - && difftime(current_time, last_table_monitor_time) > 60) { + if (srv_print_innodb_tablespace_monitor + && difftime(current_time, last_table_monitor_time) > 60) { last_table_monitor_time = time(NULL); - printf("================================================\n"); + fputs("================================================\n", + stderr); - ut_print_timestamp(stdout); + ut_print_timestamp(stderr); - printf(" INNODB TABLESPACE MONITOR OUTPUT\n" - "================================================\n"); + fputs(" INNODB TABLESPACE MONITOR OUTPUT\n" + "================================================\n", + stderr); fsp_print(0); - fprintf(stderr, "Validating tablespace\n"); + fputs("Validating tablespace\n", stderr); fsp_validate(0); - fprintf(stderr, "Validation ok\n"); - printf("---------------------------------------\n" + fputs("Validation ok\n" + "---------------------------------------\n" "END OF INNODB TABLESPACE MONITOR OUTPUT\n" - "=======================================\n"); + "=======================================\n", + stderr); } if (srv_print_innodb_table_monitor - && difftime(current_time, last_table_monitor_time) > 60) { + && difftime(current_time, last_table_monitor_time) > 60) { last_table_monitor_time = time(NULL); - printf("===========================================\n"); + fputs("===========================================\n", stderr); - ut_print_timestamp(stdout); + ut_print_timestamp(stderr); - printf(" INNODB TABLE MONITOR OUTPUT\n" - "===========================================\n"); + fputs(" INNODB TABLE MONITOR OUTPUT\n" + "===========================================\n", + stderr); dict_print(); - printf("-----------------------------------\n" + fputs("-----------------------------------\n" "END OF INNODB TABLE MONITOR OUTPUT\n" - "==================================\n"); + "==================================\n", + stderr); } } @@ -1774,8 +1757,11 @@ loop: srv_lock_timeout_and_monitor_active = FALSE; +#if 0 + /* The following synchronisation is disabled, since + the InnoDB monitor output is to be updated every 15 seconds. */ os_event_wait(srv_lock_timeout_thread_event); - +#endif goto loop; exit_func: @@ -1786,7 +1772,7 @@ exit_func: os_thread_exit(NULL); #ifndef __WIN__ - return(NULL); + return(NULL); #else return(0); #endif @@ -1804,19 +1790,18 @@ ulint srv_error_monitor_thread( /*=====================*/ /* out: a dummy parameter */ - void* arg) /* in: a dummy parameter required by + void* arg __attribute__((unused))) + /* in: a dummy parameter required by os_thread_create */ { ulint cnt = 0; dulint old_lsn; dulint new_lsn; - UT_NOT_USED(arg); - old_lsn = srv_start_lsn; #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Error monitor thread starts, id %lu\n", + fprintf(stderr, "Error monitor thread starts, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif loop: @@ -1852,11 +1837,10 @@ loop: sync_array_print_long_waits(); - /* Flush stdout and stderr so that a database user gets their output + /* Flush stderr so that a database user gets the output to possible MySQL error file */ fflush(stderr); - fflush(stdout); os_thread_sleep(2000000); @@ -1873,7 +1857,7 @@ loop: os_thread_exit(NULL); #ifndef __WIN__ - return(NULL); + return(NULL); #else return(0); #endif @@ -1929,7 +1913,8 @@ ulint srv_master_thread( /*==============*/ /* out: a dummy parameter */ - void* arg) /* in: a dummy parameter required by + void* arg __attribute__((unused))) + /* in: a dummy parameter required by os_thread_create */ { os_event_t event; @@ -1948,10 +1933,8 @@ srv_master_thread( ibool skip_sleep = FALSE; ulint i; - UT_NOT_USED(arg); - #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Master thread starts, id %lu\n", + fprintf(stderr, "Master thread starts, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif srv_main_thread_process_no = os_proc_get_number(); diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 7b50877709b..33d84cfaa8e 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -63,13 +63,13 @@ dulint srv_shutdown_lsn; ibool srv_start_raw_disk_in_use = FALSE; -ibool srv_start_has_been_called = FALSE; +static ibool srv_start_has_been_called = FALSE; ulint srv_sizeof_trx_t_in_ha_innodb_cc; ibool srv_startup_is_before_trx_rollback_phase = FALSE; ibool srv_is_being_started = FALSE; -ibool srv_was_started = FALSE; +static ibool srv_was_started = FALSE; /* At a shutdown the value first climbs to SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE */ @@ -77,19 +77,20 @@ ulint srv_shutdown_state = 0; ibool measure_cont = FALSE; -os_file_t files[1000]; +static os_file_t files[1000]; -mutex_t ios_mutex; -ulint ios; +static mutex_t ios_mutex; +static ulint ios; -ulint n[SRV_MAX_N_IO_THREADS + 5]; -os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5]; +static ulint n[SRV_MAX_N_IO_THREADS + 5]; +static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5]; /* We use this mutex to test the return value of pthread_mutex_trylock on successful locking. HP-UX does NOT return 0, though Linux et al do. */ -os_fast_mutex_t srv_os_test_mutex; +static os_fast_mutex_t srv_os_test_mutex; -ibool srv_os_test_mutex_is_locked = FALSE; +/* Name of srv_monitor_file */ +static char* srv_monitor_file_name; #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 @@ -161,17 +162,13 @@ srv_parse_data_file_paths_and_sizes( str++; } - if (strlen(str) >= ut_strlen(":autoextend") - && 0 == ut_memcmp(str, (char*)":autoextend", - ut_strlen(":autoextend"))) { + if (0 == memcmp(str, ":autoextend", (sizeof ":autoextend") - 1)) { - str += ut_strlen(":autoextend"); + str += (sizeof ":autoextend") - 1; - if (strlen(str) >= ut_strlen(":max:") - && 0 == ut_memcmp(str, (char*)":max:", - ut_strlen(":max:"))) { + if (0 == memcmp(str, ":max:", (sizeof ":max:") - 1)) { - str += ut_strlen(":max:"); + str += (sizeof ":max:") - 1; size = strtoul(str, &endp, 10); @@ -200,10 +197,7 @@ srv_parse_data_file_paths_and_sizes( str += 3; } - if (strlen(str) >= 3 - && *str == 'r' - && *(str + 1) == 'a' - && *(str + 2) == 'w') { + if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { str += 3; } @@ -269,19 +263,15 @@ srv_parse_data_file_paths_and_sizes( (*data_file_names)[i] = path; (*data_file_sizes)[i] = size; - if (strlen(str) >= ut_strlen(":autoextend") - && 0 == ut_memcmp(str, (char*)":autoextend", - ut_strlen(":autoextend"))) { + if (0 == memcmp(str, ":autoextend", (sizeof ":autoextend") - 1)) { *is_auto_extending = TRUE; - str += ut_strlen(":autoextend"); + str += (sizeof ":autoextend") - 1; - if (strlen(str) >= ut_strlen(":max:") - && 0 == ut_memcmp(str, (char*)":max:", - ut_strlen(":max:"))) { + if (0 == memcmp(str, ":max:", (sizeof ":max:") - 1)) { - str += ut_strlen(":max:"); + str += (sizeof ":max:") - 1; size = strtoul(str, &endp, 10); @@ -315,10 +305,7 @@ srv_parse_data_file_paths_and_sizes( (*data_file_is_raw_partition)[i] = SRV_NEW_RAW; } - if (strlen(str) >= 3 - && *str == 'r' - && *(str + 1) == 'a' - && *(str + 2) == 'w') { + if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { str += 3; if ((*data_file_is_raw_partition)[i] == 0) { @@ -420,8 +407,8 @@ io_handler_thread( segment = *((ulint*)arg); #ifdef UNIV_DEBUG_THREAD_CREATION - printf("Io handler thread %lu starts, id %lu\n", segment, - os_thread_pf(os_thread_get_curr_id())); + fprintf(stderr, "Io handler thread %lu starts, id %lu\n", segment, + os_thread_pf(os_thread_get_curr_id())); #endif for (i = 0;; i++) { fil_aio_wait(segment); @@ -461,12 +448,10 @@ srv_normalize_path_for_win( character string */ { #ifdef __WIN__ - ulint i; - - for (i = 0; i < ut_strlen(str); i++) { + for (; *str; str++) { - if (str[i] == '/') { - str[i] = '\\'; + if (*str == '/') { + *str = '\\'; } } #endif @@ -535,8 +520,8 @@ ulint open_or_create_log_file( /*====================*/ /* out: DB_SUCCESS or error code */ - ibool create_new_db, /* in: TRUE if we should create a - new database */ + ibool create_new_db, /* in: TRUE if we should create a + new database */ ibool* log_file_created, /* out: TRUE if new log file created */ ibool log_file_has_been_opened,/* in: TRUE if a log file has been @@ -558,6 +543,8 @@ open_or_create_log_file( srv_log_group_home_dirs[k] = srv_add_path_separator_if_needed( srv_log_group_home_dirs[k]); + ut_a(strlen(srv_log_group_home_dirs[k]) < + (sizeof name) - 10 - sizeof "ib_logfile"); sprintf(name, "%s%s%lu", srv_log_group_home_dirs[k], "ib_logfile", (ulong) i); files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL, @@ -709,6 +696,8 @@ open_or_create_data_files( for (i = 0; i < srv_n_data_files; i++) { srv_normalize_path_for_win(srv_data_file_names[i]); + ut_a(strlen(srv_data_home) + strlen(srv_data_file_names[i]) + < (sizeof name) - 1); sprintf(name, "%s%s", srv_data_home, srv_data_file_names[i]); if (srv_data_file_is_raw_partition[i] == 0) { @@ -1122,6 +1111,19 @@ NetWare. */ return((int) err); } + mutex_create(&srv_monitor_file_mutex); + srv_monitor_file_name = mem_alloc( + strlen(fil_path_to_mysql_datadir) + + 20 + sizeof "/innodb_status."); + sprintf(srv_monitor_file_name, "%s/innodb.status.%lu", + fil_path_to_mysql_datadir, os_proc_get_number()); + srv_monitor_file = fopen(srv_monitor_file_name, "w+"); + if (!srv_monitor_file) { + fprintf(stderr, "InnoDB: unable to create %s: %s\n", + srv_monitor_file_name, strerror(errno)); + return(DB_ERROR); + } + /* Restrict the maximum number of file i/o threads */ if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) { @@ -1457,7 +1459,9 @@ NetWare. */ os_thread_create(&srv_master_thread, NULL, thread_ids + 1 + SRV_MAX_N_IO_THREADS); +#ifdef UNIV_DEBUG /* buf_debug_prints = TRUE; */ +#endif /* UNIV_DEBUG */ sum_of_data_file_sizes = 0; @@ -1663,6 +1667,15 @@ innobase_shutdown_for_mysql(void) (ulong) os_thread_count); } + if (srv_monitor_file) { + fclose(srv_monitor_file); + srv_monitor_file = 0; + unlink(srv_monitor_file_name); + mem_free(srv_monitor_file_name); + } + + mutex_free(&srv_monitor_file_mutex); + /* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside them */ @@ -1689,6 +1702,13 @@ innobase_shutdown_for_mysql(void) (ulong) os_mutex_count, (ulong) os_fast_mutex_count); } + if (dict_foreign_err_file) { + fclose(dict_foreign_err_file); + } + if (lock_latest_err_file) { + fclose(lock_latest_err_file); + } + if (srv_print_verbose_log) { ut_print_timestamp(stderr); fprintf(stderr, diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 8082f598b0c..1268b22e2f8 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -425,7 +425,7 @@ sync_array_wait_event( if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) { - printf("########################################\n"); + fputs("########################################\n", stderr); ut_error; } @@ -444,8 +444,7 @@ static void sync_array_cell_print( /*==================*/ - char* buf, /* in: buffer where to print, must be - at least 400 characters */ + FILE* file, /* in: file where to print */ sync_cell_t* cell) /* in: sync cell */ { mutex_t* mutex; @@ -455,7 +454,7 @@ sync_array_cell_print( type = cell->request_type; - buf += sprintf(buf, + fprintf(file, "--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n", (ulong) os_thread_pf(cell->thread), cell->file, (ulong) cell->line, @@ -466,7 +465,7 @@ sync_array_cell_print( been freed meanwhile */ mutex = cell->old_wait_mutex; - buf += sprintf(buf, + fprintf(file, "Mutex at %p created file %s line %lu, lock var %lu\n" #ifdef UNIV_SYNC_DEBUG "Last time reserved in file %s line %lu, " @@ -481,51 +480,43 @@ sync_array_cell_print( } else if (type == RW_LOCK_EX || type == RW_LOCK_SHARED) { - if (type == RW_LOCK_EX) { - buf += sprintf(buf, "X-lock on"); - } else { - buf += sprintf(buf, "S-lock on"); - } + fputs(type == RW_LOCK_EX ? "X-lock on" : "S-lock on", file); rwlock = cell->old_wait_rw_lock; - buf += sprintf(buf, - " RW-latch at %lx created in file %s line %lu\n", - (ulong) rwlock, rwlock->cfile_name, + fprintf(file, + " RW-latch at %p created in file %s line %lu\n", + rwlock, rwlock->cfile_name, (ulong) rwlock->cline); if (rwlock->writer != RW_LOCK_NOT_LOCKED) { - buf += sprintf(buf, - "a writer (thread id %lu) has reserved it in mode", - (ulong) os_thread_pf(rwlock->writer_thread)); - if (rwlock->writer == RW_LOCK_EX) { - buf += sprintf(buf, " exclusive\n"); - } else { - buf += sprintf(buf, " wait exclusive\n"); - } + fprintf(file, + "a writer (thread id %lu) has reserved it in mode %s", + (ulong) os_thread_pf(rwlock->writer_thread), + rwlock->writer == RW_LOCK_EX + ? " exclusive\n" + : " wait exclusive\n"); } - buf += sprintf(buf, - "number of readers %lu, waiters flag %lu\n", - (ulong) rwlock->reader_count, - (ulong) rwlock->waiters); - - buf += sprintf(buf, - "Last time read locked in file %s line %lu\n", - rwlock->last_s_file_name, - (ulong) rwlock->last_s_line); - buf += sprintf(buf, + fprintf(file, + "number of readers %lu, waiters flag %lu\n" + "Last time read locked in file %s line %lu\n" "Last time write locked in file %s line %lu\n", - rwlock->last_x_file_name, (ulong) rwlock->last_x_line); + (ulong) rwlock->reader_count, + (ulong) rwlock->waiters, + rwlock->last_s_file_name, + (ulong) rwlock->last_s_line, + rwlock->last_x_file_name, + (ulong) rwlock->last_x_line); } else { ut_error; } if (!cell->waiting) { - buf += sprintf(buf, "wait has ended\n"); + fputs("wait has ended\n", file); } if (cell->event_set) { - buf += sprintf(buf, "wait is ending\n"); + fputs("wait is ending\n", file); } } @@ -594,8 +585,8 @@ sync_array_deadlock_step( ut_dbg_stop_threads = TRUE; /* Deadlock */ - printf("########################################\n"); - printf("DEADLOCK of threads detected!\n"); + fputs("########################################\n" + "DEADLOCK of threads detected!\n", stderr); return(TRUE); @@ -627,8 +618,8 @@ sync_array_detect_deadlock( rw_lock_t* lock; os_thread_id_t thread; ibool ret; - rw_lock_debug_t* debug; - char buf[500]; + rw_lock_t* lock; + rw_lock_debug_t*debug; ut_a(arr && start && cell); ut_ad(cell->wait_object); @@ -661,11 +652,11 @@ sync_array_detect_deadlock( ret = sync_array_deadlock_step(arr, start, thread, 0, depth); if (ret) { - sync_array_cell_print(buf, cell); - printf( - "Mutex %lx owned by thread %lu file %s line %lu\n%s", - (ulong) mutex, (ulong) os_thread_pf(mutex->thread_id), - mutex->file_name, (ulong) mutex->line, buf); + fprintf(stderr, + "Mutex %p owned by thread %lu file %s line %lu\n", + mutex, (ulong) os_thread_pf(mutex->thread_id), + mutex->file_name, (ulong) mutex->line); + sync_array_cell_print(stderr, cell); return(TRUE); } @@ -698,8 +689,9 @@ sync_array_detect_deadlock( debug->pass, depth); if (ret) { - sync_array_cell_print(buf, cell); - printf("rw-lock %lx %s ", (ulong) lock, buf); + print: + fprintf(stderr, "rw-lock %p ", lock); + sync_array_cell_print(stderr, cell); rw_lock_debug_print(debug); return(TRUE); } @@ -730,11 +722,7 @@ sync_array_detect_deadlock( debug->pass, depth); if (ret) { - sync_array_cell_print(buf, cell); - printf("rw-lock %lx %s ", (ulong) lock, buf); - rw_lock_debug_print(debug); - - return(TRUE); + goto print; } } @@ -918,7 +906,6 @@ sync_array_print_long_waits(void) sync_cell_t* cell; ibool old_val; ibool noticed = FALSE; - char buf[500]; ulint i; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { @@ -927,22 +914,19 @@ sync_array_print_long_waits(void) if (cell->wait_object != NULL && difftime(time(NULL), cell->reservation_time) > 240) { - - sync_array_cell_print(buf, cell); - - fprintf(stderr, - "InnoDB: Warning: a long semaphore wait:\n%s", buf); - + fputs("InnoDB: Warning: a long semaphore wait:\n", + stderr); + sync_array_cell_print(stderr, cell); noticed = TRUE; } if (cell->wait_object != NULL && difftime(time(NULL), cell->reservation_time) > 600) { - fprintf(stderr, + fputs( "InnoDB: Error: semaphore wait has lasted > 600 seconds\n" -"InnoDB: We intentionally crash the server, because it appears to be hung.\n" - ); +"InnoDB: We intentionally crash the server, because it appears to be hung.\n", + stderr); ut_error; } @@ -970,7 +954,7 @@ sync_array_print_long_waits(void) srv_print_innodb_monitor = old_val; fprintf(stderr, -"InnoDB: ###### Diagnostic info printed to the standard output\n"); +"InnoDB: ###### Diagnostic info printed to the standard error stream\n"); } } @@ -980,8 +964,7 @@ static void sync_array_output_info( /*===================*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end,/* in: buffer end */ + FILE* file, /* in: file where to print */ sync_array_t* arr) /* in: wait array; NOTE! caller must own the mutex */ { @@ -989,11 +972,7 @@ sync_array_output_info( ulint count; ulint i; - if (buf_end - buf < 500) { - return; - } - - buf += sprintf(buf, + fprintf(file, "OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n", (long) arr->res_count, (long) arr->sg_count); i = 0; @@ -1001,17 +980,11 @@ sync_array_output_info( while (count < arr->n_reserved) { - if (buf_end - buf < 500) { - return; - } - cell = sync_array_get_nth_cell(arr, i); if (cell->wait_object != NULL) { count++; - sync_array_cell_print(buf, cell); - - buf = buf + strlen(buf); + sync_array_cell_print(file, cell); } i++; @@ -1024,13 +997,12 @@ Prints info of the wait array. */ void sync_array_print_info( /*==================*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end,/* in: buffer end */ + FILE* file, /* in: file where to print */ sync_array_t* arr) /* in: wait array */ { sync_array_enter(arr); - sync_array_output_info(buf, buf_end, arr); + sync_array_output_info(file, arr); sync_array_exit(arr); } diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c index 93fd9f14575..43f8d646eaa 100644 --- a/innobase/sync/sync0rw.c +++ b/innobase/sync/sync0rw.c @@ -146,7 +146,9 @@ rw_lock_free( /*=========*/ rw_lock_t* lock) /* in: rw-lock */ { +#ifdef UNIV_DEBUG ut_a(rw_lock_validate(lock)); +#endif /* UNIV_DEBUG */ ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED); ut_a(rw_lock_get_waiters(lock) == 0); ut_a(rw_lock_get_reader_count(lock) == 0); @@ -169,6 +171,7 @@ rw_lock_free( mutex_exit(&rw_lock_list_mutex); } +#ifdef UNIV_DEBUG /********************************************************************** Checks that the rw-lock has been initialized and that there are no simultaneous shared and exclusive locks. */ @@ -196,6 +199,7 @@ rw_lock_validate( return(TRUE); } +#endif /* UNIV_DEBUG */ /********************************************************************** Lock an rw-lock in shared mode for the current thread. If the rw-lock is @@ -237,9 +241,9 @@ lock_loop: } if (srv_print_latch_waits) { - printf( - "Thread %lu spin wait rw-s-lock at %lx cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), (ulong) lock, + fprintf(stderr, + "Thread %lu spin wait rw-s-lock at %p cfile %s cline %lu rnds %lu\n", + (ulong) os_thread_pf(os_thread_get_curr_id()), lock, lock->cfile_name, (ulong) lock->cline, (ulong) i); } @@ -267,10 +271,10 @@ lock_loop: mutex_exit(rw_lock_get_mutex(lock)); if (srv_print_latch_waits) { - printf( - "Thread %lu OS wait rw-s-lock at %lx cfile %s cline %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), - (ulong) lock, lock->cfile_name, (ulong) lock->cline); + fprintf(stderr, + "Thread %lu OS wait rw-s-lock at %p cfile %s cline %lu\n", + os_thread_pf(os_thread_get_curr_id()), + lock, lock->cfile_name, (ulong) lock->cline); } rw_s_system_call_count++; @@ -486,9 +490,9 @@ lock_loop: } if (srv_print_latch_waits) { - printf( - "Thread %lu spin wait rw-x-lock at %lx cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), (ulong) lock, + fprintf(stderr, + "Thread %lu spin wait rw-x-lock at %p cfile %s cline %lu rnds %lu\n", + os_thread_pf(os_thread_get_curr_id()), lock, lock->cfile_name, (ulong) lock->cline, (ulong) i); } @@ -519,9 +523,9 @@ lock_loop: mutex_exit(rw_lock_get_mutex(lock)); if (srv_print_latch_waits) { - printf( - "Thread %lu OS wait for rw-x-lock at %lx cfile %s cline %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), (ulong) lock, + fprintf(stderr, + "Thread %lu OS wait for rw-x-lock at %p cfile %s cline %lu\n", + os_thread_pf(os_thread_get_curr_id()), lock, lock->cfile_name, (ulong) lock->cline); } @@ -764,9 +768,9 @@ rw_lock_list_print_info(void) mutex_enter(&rw_lock_list_mutex); - printf("-------------\n"); - printf("RW-LATCH INFO\n"); - printf("-------------\n"); + fputs("-------------\n" + "RW-LATCH INFO\n" + "-------------\n", stderr); lock = UT_LIST_GET_FIRST(rw_lock_list); @@ -780,12 +784,12 @@ rw_lock_list_print_info(void) || (rw_lock_get_reader_count(lock) != 0) || (rw_lock_get_waiters(lock) != 0)) { - printf("RW-LOCK: %lx ", (ulint)lock); + fprintf(stderr, "RW-LOCK: %p ", lock); if (rw_lock_get_waiters(lock)) { - printf(" Waiters for the lock exist\n"); + fputs(" Waiters for the lock exist\n", stderr); } else { - printf("\n"); + putc('\n', stderr); } info = UT_LIST_GET_FIRST(lock->debug_list); @@ -799,7 +803,7 @@ rw_lock_list_print_info(void) lock = UT_LIST_GET_NEXT(list, lock); } - printf("Total number of rw-locks %ld\n", count); + fprintf(stderr, "Total number of rw-locks %ld\n", count); mutex_exit(&rw_lock_list_mutex); } @@ -809,22 +813,23 @@ Prints debug info of an rw-lock. */ void rw_lock_print( /*==========*/ - rw_lock_t* lock __attribute__((unused))) /* in: rw-lock */ + rw_lock_t* lock) /* in: rw-lock */ { rw_lock_debug_t* info; - printf("-------------\n"); - printf("RW-LATCH INFO\n"); - printf("RW-LATCH: %lx ", (ulint)lock); + fprintf(stderr, + "-------------\n" + "RW-LATCH INFO\n" + "RW-LATCH: %p ", lock); if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) || (rw_lock_get_reader_count(lock) != 0) || (rw_lock_get_waiters(lock) != 0)) { if (rw_lock_get_waiters(lock)) { - printf(" Waiters for the lock exist\n"); + fputs(" Waiters for the lock exist\n", stderr); } else { - printf("\n"); + putc('\n', stderr); } info = UT_LIST_GET_FIRST(lock->debug_list); @@ -847,22 +852,22 @@ rw_lock_debug_print( rwt = info->lock_type; - printf("Locked: thread %ld file %s line %ld ", + fprintf(stderr, "Locked: thread %ld file %s line %ld ", (ulong) os_thread_pf(info->thread_id), info->file_name, (ulong) info->line); if (rwt == RW_LOCK_SHARED) { - printf("S-LOCK"); + fputs("S-LOCK", stderr); } else if (rwt == RW_LOCK_EX) { - printf("X-LOCK"); + fputs("X-LOCK", stderr); } else if (rwt == RW_LOCK_WAIT_EX) { - printf("WAIT X-LOCK"); + fputs("WAIT X-LOCK", stderr); } else { ut_error; } if (info->pass != 0) { - printf(" pass value %lu", (ulong) info->pass); + fprintf(stderr, " pass value %lu", (ulong) info->pass); } - printf("\n"); + putc('\n', stderr); } /******************************************************************* diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 64f76f5ee77..e711acbf84e 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -168,6 +168,30 @@ struct sync_level_struct{ }; /********************************************************************** +A noninlined function that reserves a mutex. In ha_innodb.cc we have disabled +inlining of InnoDB functions, and no inlined functions should be called from +there. That is why we need to duplicate the inlined function here. */ + +void +mutex_enter_noninline( +/*==================*/ + mutex_t* mutex) /* in: mutex */ +{ + mutex_enter(mutex); +} + +/********************************************************************** +Releases a mutex. */ + +void +mutex_exit_noninline( +/*=================*/ + mutex_t* mutex) /* in: mutex */ +{ + mutex_exit(mutex); +} + +/********************************************************************** Creates, or rather, initializes a mutex object in a specified memory location (which must be appropriately aligned). The mutex is initialized in the reset state. Explicit freeing of the mutex with mutex_free is @@ -227,7 +251,9 @@ mutex_free( /*=======*/ mutex_t* mutex) /* in: mutex */ { +#ifdef UNIV_DEBUG ut_a(mutex_validate(mutex)); +#endif /* UNIV_DEBUG */ ut_a(mutex_get_lock_word(mutex) == 0); ut_a(mutex_get_waiters(mutex) == 0); @@ -288,6 +314,7 @@ mutex_enter_nowait( return(1); } +#ifdef UNIV_DEBUG /********************************************************************** Checks that the mutex has been initialized. */ @@ -301,6 +328,7 @@ mutex_validate( return(TRUE); } +#endif /* UNIV_DEBUG */ /********************************************************************** Sets the waiters field in a mutex. */ @@ -365,9 +393,9 @@ spin_loop: } if (srv_print_latch_waits) { - printf( - "Thread %lu spin wait mutex at %lx cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), (ulong) mutex, + fprintf(stderr, + "Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n", + (ulong) os_thread_pf(os_thread_get_curr_id()), mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) i); } @@ -425,10 +453,11 @@ spin_loop: #endif if (srv_print_latch_waits) { - printf( - "Thread %lu spin wait succeeds at 2: mutex at %lx\n", + fprintf(stderr, + "Thread %lu spin wait succeeds at 2:" + " mutex at %p\n", (ulong) os_thread_pf(os_thread_get_curr_id()), - (ulong) mutex); + mutex); } return; @@ -444,9 +473,9 @@ spin_loop: Now there is no risk of infinite wait on the event. */ if (srv_print_latch_waits) { - printf( - "Thread %lu OS wait mutex at %lx cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), (ulong) mutex, + fprintf(stderr, + "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n", + (ulong) os_thread_pf(os_thread_get_curr_id()), mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) i); } @@ -566,9 +595,9 @@ mutex_list_print_info(void) os_thread_id_t thread_id; ulint count = 0; - printf("----------\n"); - printf("MUTEX INFO\n"); - printf("----------\n"); + fputs("----------\n" + "MUTEX INFO\n" + "----------\n", stderr); mutex_enter(&mutex_list_mutex); @@ -580,16 +609,16 @@ mutex_list_print_info(void) if (mutex_get_lock_word(mutex) != 0) { mutex_get_debug_info(mutex, &file_name, &line, &thread_id); - printf( - "Locked mutex: addr %lx thread %ld file %s line %ld\n", - (ulint)mutex, os_thread_pf(thread_id), + fprintf(stderr, + "Locked mutex: addr %p thread %ld file %s line %ld\n", + mutex, os_thread_pf(thread_id), file_name, line); } mutex = UT_LIST_GET_NEXT(list, mutex); } - printf("Total number of mutexes %ld\n", count); + fprintf(stderr, "Total number of mutexes %ld\n", count); mutex_exit(&mutex_list_mutex); } @@ -747,12 +776,14 @@ sync_thread_levels_g( lock = slot->latch; mutex = slot->latch; - printf( + fprintf(stderr, "InnoDB error: sync levels should be > %lu but a level is %lu\n", (ulong) limit, (ulong) slot->level); if (mutex->magic_n == MUTEX_MAGIC_N) { - printf("Mutex created at %s %lu\n", mutex->cfile_name, + fprintf(stderr, + "Mutex created at %s %lu\n", + mutex->cfile_name, (ulong) mutex->cline); if (mutex_get_lock_word(mutex) != 0) { @@ -833,9 +864,6 @@ sync_thread_levels_empty_gen( sync_level_t* arr; sync_thread_t* thread_slot; sync_level_t* slot; - rw_lock_t* lock; - mutex_t* mutex; - char* buf; ulint i; if (!sync_order_checks_on) { @@ -864,13 +892,7 @@ sync_thread_levels_empty_gen( (slot->level != SYNC_DICT && slot->level != SYNC_DICT_OPERATION))) { - lock = slot->latch; - mutex = slot->latch; mutex_exit(&sync_thread_mutex); - - buf = mem_alloc(20000); - - sync_print(buf, buf + 18000); ut_error; return(FALSE); @@ -1054,8 +1076,12 @@ sync_thread_add_level( } else if (level == SYNC_DICT_HEADER) { ut_a(sync_thread_levels_g(array, SYNC_DICT_HEADER)); } else if (level == SYNC_DICT) { - ut_a(buf_debug_prints - || sync_thread_levels_g(array, SYNC_DICT)); +#ifdef UNIV_DEBUG + ut_a(buf_debug_prints || + sync_thread_levels_g(array, SYNC_DICT)); +#else /* UNIV_DEBUG */ + ut_a(sync_thread_levels_g(array, SYNC_DICT)); +#endif /* UNIV_DEBUG */ } else { ut_error; } @@ -1225,19 +1251,14 @@ Prints wait info of the sync system. */ void sync_print_wait_info( /*=================*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end) /* in: buffer end */ + FILE* file) /* in: file where to print */ { #ifdef UNIV_SYNC_DEBUG - printf("Mutex exits %lu, rws exits %lu, rwx exits %lu\n", + fprintf(stderr, "Mutex exits %lu, rws exits %lu, rwx exits %lu\n", mutex_exit_count, rw_s_exit_count, rw_x_exit_count); #endif - if (buf_end - buf < 500) { - return; - } - - sprintf(buf, + fprintf(file, "Mutex spin waits %lu, rounds %lu, OS waits %lu\n" "RW-shared spins %lu, OS waits %lu; RW-excl spins %lu, OS waits %lu\n", (ulong) mutex_spin_wait_count, @@ -1255,8 +1276,7 @@ Prints info of the sync system. */ void sync_print( /*=======*/ - char* buf, /* in/out: buffer where to print */ - char* buf_end) /* in: buffer end */ + FILE* file) /* in: file where to print */ { #ifdef UNIV_SYNC_DEBUG mutex_list_print_info(); @@ -1264,9 +1284,7 @@ sync_print( rw_lock_list_print_info(); #endif /* UNIV_SYNC_DEBUG */ - sync_array_print_info(buf, buf_end, sync_primary_wait_array); - - buf = buf + strlen(buf); + sync_array_print_info(file, sync_primary_wait_array); - sync_print_wait_info(buf, buf_end); + sync_print_wait_info(file); } diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c index 558a0825fd7..3d5f0d3f03a 100644 --- a/innobase/trx/trx0purge.c +++ b/innobase/trx/trx0purge.c @@ -337,7 +337,7 @@ trx_purge_free_segment( ibool marked = FALSE; mtr_t mtr; -/* printf("Freeing an update undo log segment\n"); */ +/* fputs("Freeing an update undo log segment\n", stderr); */ #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(purge_sys->mutex))); @@ -918,7 +918,7 @@ trx_purge_fetch_next_rec( trx_purge_truncate_if_arr_empty(); if (srv_print_thread_releases) { - printf( + fprintf(stderr, "Purge: No logs left in the history list; pages handled %lu\n", (ulong) purge_sys->n_pages_handled); } @@ -951,7 +951,7 @@ trx_purge_fetch_next_rec( return(NULL); } -/* printf("Thread %lu purging trx %lu undo record %lu\n", +/* fprintf(stderr, "Thread %lu purging trx %lu undo record %lu\n", os_thread_get_curr_id(), ut_dulint_get_low(purge_sys->purge_trx_no), ut_dulint_get_low(purge_sys->purge_undo_no)); */ @@ -1064,14 +1064,14 @@ trx_purge(void) if (srv_print_thread_releases) { - printf("Starting purge\n"); + fputs("Starting purge\n", stderr); } que_run_threads(thr); if (srv_print_thread_releases) { - printf( + fprintf(stderr, "Purge ends; pages handled %lu\n", (ulong) purge_sys->n_pages_handled); } diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c index bd37a4b506b..7963bec7f33 100644 --- a/innobase/trx/trx0rec.c +++ b/innobase/trx/trx0rec.c @@ -823,18 +823,18 @@ trx_undo_update_rec_get_update( if (field_no >= dict_index_get_n_fields(index)) { fprintf(stderr, - "InnoDB: Error: trying to access update undo rec field %lu in table %s\n" - "InnoDB: index %s, but index has only %lu fields\n", - (ulong) field_no, index->table_name, index->name, - (ulong) dict_index_get_n_fields(index)); - fprintf(stderr, - "InnoDB: Send a detailed bug report to mysql@lists.mysql.com"); - - fprintf(stderr, - "InnoDB: Run also CHECK TABLE on table %s\n", index->table_name); - fprintf(stderr, - "InnoDB: n_fields = %lu, i = %lu, ptr %lx\n", (ulong) n_fields, (ulong) i, - (ulong) ptr); + "InnoDB: Error: trying to access" + " update undo rec field %lu in ", (ulong) field_no); + dict_index_name_print(stderr, index); + fprintf(stderr, "\n" + "InnoDB: but index has only %lu fields\n" + "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n" + "InnoDB: Run also CHECK TABLE ", + (ulong) dict_index_get_n_fields(index)); + ut_print_name(stderr, index->table_name); + fprintf(stderr, "\n" + "InnoDB: n_fields = %lu, i = %lu, ptr %p\n", + (ulong) n_fields, (ulong) i, ptr); return(NULL); } @@ -1259,8 +1259,6 @@ trx_undo_prev_version_build( byte* buf; ulint err; ulint i; - char err_buf[1000]; - #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ @@ -1269,19 +1267,18 @@ trx_undo_prev_version_build( mtr_memo_contains(index_mtr, buf_block_align(index_rec), MTR_MEMO_PAGE_X_FIX)); if (!(index->type & DICT_CLUSTERED)) { - fprintf(stderr, - "InnoDB: Error: trying to access update undo rec for table %s\n" - "InnoDB: index %s which is not a clustered index\n", - index->table_name, index->name); - fprintf(stderr, - "InnoDB: Send a detailed bug report to mysql@lists.mysql.com"); - - rec_sprintf(err_buf, 900, index_rec); - fprintf(stderr, "InnoDB: index record %s\n", err_buf); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record version %s\n", err_buf); - + fputs("InnoDB: Error: trying to access" + " update undo rec for non-clustered ", stderr); + dict_index_name_print(stderr, index); + fputs("\n" + "InnoDB: Send a detailed bug report to" + " mysql@lists.mysql.com\n" + "InnoDB: index record ", stderr); + rec_print(stderr, index_rec); + fputs("\n" + "InnoDB: record version ", stderr); + rec_print(stderr, rec); + putc('\n', stderr); return(DB_ERROR); } @@ -1319,56 +1316,49 @@ trx_undo_prev_version_build( if (ut_dulint_cmp(table_id, index->table->id) != 0) { ptr = NULL; - fprintf(stderr, - "InnoDB: Error: trying to access update undo rec for table %s\n" - "InnoDB: but the table id in the undo record is wrong\n", - index->table_name); - fprintf(stderr, - "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n"); - - fprintf(stderr, - "InnoDB: Run also CHECK TABLE on table %s\n", index->table_name); + fputs("InnoDB: Error: trying to access" + " update undo rec for table ", stderr); + ut_print_name(stderr, index->table_name); + fputs("\n" + "InnoDB: but the table id in the" + " undo record is wrong\n" + "InnoDB: Send a detailed bug report to " + "mysql@lists.mysql.com\n" + "InnoDB: Run also CHECK TABLE ", stderr); + ut_print_name(stderr, index->table_name); + putc('\n', stderr); } if (ptr == NULL) { /* The record was corrupted, return an error; these printfs should catch an elusive bug in row_vers_old_has_index_entry */ - fprintf(stderr, - "InnoDB: Table name %s, index name %s, n_uniq %lu\n", - index->table_name, index->name, - (ulong) dict_index_get_n_unique(index)); - - fprintf(stderr, - "InnoDB: undo rec address %lx, type %lu cmpl_info %lu\n", - (ulong) undo_rec, (ulong) type, - (ulong) cmpl_info); - fprintf(stderr, - "InnoDB: undo rec table id %lu %lu, index table id %lu %lu\n", + fputs("InnoDB: ", stderr); + dict_index_name_print(stderr, index); + fprintf(stderr, ", n_uniq %lu\n" + "InnoDB: undo rec address %p, type %lu cmpl_info %lu\n" + "InnoDB: undo rec table id %lu %lu, index table id %lu %lu\n" + "InnoDB: dump of 150 bytes in undo rec: ", + (ulong) dict_index_get_n_unique(index), + undo_rec, (ulong) type, (ulong) cmpl_info, (ulong) ut_dulint_get_high(table_id), (ulong) ut_dulint_get_low(table_id), (ulong) ut_dulint_get_high(index->table->id), (ulong) ut_dulint_get_low(index->table->id)); - - ut_sprintf_buf(err_buf, undo_rec, 150); - - fprintf(stderr, "InnoDB: dump of 150 bytes in undo rec: %s\n", - err_buf); - rec_sprintf(err_buf, 900, index_rec); - fprintf(stderr, "InnoDB: index record %s\n", err_buf); - - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record version %s\n", err_buf); - - fprintf(stderr, - "InnoDB: Record trx id %lu %lu, update rec trx id %lu %lu\n", + ut_print_buf(stderr, undo_rec, 150); + fputs("\n" + "InnoDB: index record ", stderr); + rec_print(stderr, index_rec); + fputs("\n" + "InnoDB: record version ", stderr); + rec_print(stderr, rec); + fprintf(stderr, "\n" + "InnoDB: Record trx id %lu %lu, update rec trx id %lu %lu\n" + "InnoDB: Roll ptr in rec %lu %lu, in update rec %lu %lu\n", (ulong) ut_dulint_get_high(rec_trx_id), (ulong) ut_dulint_get_low(rec_trx_id), (ulong) ut_dulint_get_high(trx_id), - (ulong) ut_dulint_get_low(trx_id)); - - fprintf(stderr, - "InnoDB: Roll ptr in rec %lu %lu, in update rec %lu %lu\n", + (ulong) ut_dulint_get_low(trx_id), (ulong) ut_dulint_get_high(old_roll_ptr), (ulong) ut_dulint_get_low(old_roll_ptr), (ulong) ut_dulint_get_high(roll_ptr), diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index 6a25304c7ef..5c01a5371aa 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -228,9 +228,9 @@ trx_rollback_to_savepoint_for_mysql( if (trx->conc_state == TRX_NOT_STARTED) { ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: transaction has a savepoint %s though it is not started\n", - savep->name); + fputs(" InnoDB: Error: transaction has a savepoint ", stderr); + ut_print_name(stderr, savep->name); + fputs(" though it is not started\n", stderr); return(DB_ERROR); } @@ -301,8 +301,7 @@ trx_savepoint_for_mysql( savep = mem_alloc(sizeof(trx_named_savept_t)); - savep->name = mem_alloc(1 + ut_strlen(savepoint_name)); - ut_memcpy(savep->name, savepoint_name, 1 + ut_strlen(savepoint_name)); + savep->name = mem_strdup(savepoint_name); savep->savept = trx_savept_take(trx); @@ -467,10 +466,11 @@ loop: table = dict_table_get_on_id_low(trx->table_id, trx); if (table) { - fprintf(stderr, -"InnoDB: Table found: dropping table %s in recovery\n", table->name); + fputs("InnoDB: Table found: dropping table ", stderr); + ut_print_name(stderr, table->name); + fputs(" in recovery\n", stderr); - err = row_drop_table_for_mysql(table->name, trx); + err = row_drop_table_for_mysql(table->name, trx, TRUE); ut_a(err == (int) DB_SUCCESS); } @@ -730,7 +730,7 @@ trx_roll_pop_top_rec( undo->top_page_no, mtr); offset = undo->top_offset; -/* printf("Thread %lu undoing trx %lu undo record %lu\n", +/* fprintf(stderr, "Thread %lu undoing trx %lu undo record %lu\n", os_thread_get_curr_id(), ut_dulint_get_low(trx->id), ut_dulint_get_low(undo->top_undo_no)); */ @@ -1140,10 +1140,12 @@ trx_finish_rollback_off_kernel( return; } +#ifdef UNIV_DEBUG if (lock_print_waits) { - printf("Trx %lu rollback finished\n", + fprintf(stderr, "Trx %lu rollback finished\n", (ulong) ut_dulint_get_low(trx->id)); } +#endif /* UNIV_DEBUG */ trx_commit_off_kernel(trx); diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 57cfcef7d6f..ef068d8d523 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -596,8 +596,7 @@ trx_sys_update_mysql_binlog_offset( MLOG_4BYTES, mtr); } - if (0 != ut_memcmp(sys_header + field + TRX_SYS_MYSQL_LOG_NAME, - file_name, 1 + ut_strlen(file_name))) { + if (0 != strcmp(sys_header + field + TRX_SYS_MYSQL_LOG_NAME, file_name)) { mlog_write_string(sys_header + field + TRX_SYS_MYSQL_LOG_NAME, @@ -620,8 +619,9 @@ trx_sys_update_mysql_binlog_offset( MLOG_4BYTES, mtr); } +#ifdef UNIV_HOTBACKUP /********************************************************************* -Prints to stdout the MySQL binlog info in the system header if the +Prints to stderr the MySQL binlog info in the system header if the magic number shows it valid. */ void @@ -638,7 +638,7 @@ trx_sys_print_mysql_binlog_offset_from_page( + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) == TRX_SYS_MYSQL_LOG_MAGIC_N) { - printf( + fprintf(stderr, "ibbackup: Last MySQL binlog file position %lu %lu, file name %s\n", (ulong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), @@ -647,6 +647,7 @@ trx_sys_print_mysql_binlog_offset_from_page( sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME); } } +#endif /* UNIV_HOTBACKUP */ /********************************************************************* Prints to stderr the MySQL binlog offset info in the trx system header if diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 54358ad3d4c..a69b9a96824 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -26,10 +26,10 @@ Created 3/26/1996 Heikki Tuuri #include "os0proc.h" /* Copy of the prototype for innobase_mysql_print_thd: this -copy MUST be equal to the one in mysql/sql/ha_innobase.cc ! */ +copy MUST be equal to the one in mysql/sql/ha_innodb.cc ! */ void innobase_mysql_print_thd( - char* buf, + FILE* f, void* thd); /* Dummy session used currently in MySQL interface */ @@ -239,19 +239,17 @@ trx_free( /*=====*/ trx_t* trx) /* in, own: trx object */ { - char err_buf[1000]; - #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ if (trx->declared_to_be_inside_innodb) { ut_print_timestamp(stderr); - trx_print(err_buf, trx); - - fprintf(stderr, + fputs( " InnoDB: Error: Freeing a trx which is declared to be processing\n" -"InnoDB: inside InnoDB.\n%s\n", err_buf); +"InnoDB: inside InnoDB.\n", stderr); + trx_print(stderr, trx); + putc('\n', stderr); } ut_a(trx->magic_n == TRX_MAGIC_N); @@ -758,7 +756,8 @@ trx_commit_off_kernel( trx->read_view = NULL; } -/* printf("Trx %lu commit finished\n", ut_dulint_get_low(trx->id)); */ +/* fprintf(stderr, "Trx %lu commit finished\n", + ut_dulint_get_low(trx->id)); */ if (must_flush_log) { @@ -1568,93 +1567,99 @@ own the kernel mutex. */ void trx_print( /*======*/ - char* buf, /* in/out: buffer where to print, must be at least - 800 bytes */ + FILE* f, /* in: output stream */ trx_t* trx) /* in: transaction */ { - char* start_of_line; + ibool newline; - buf += sprintf(buf, "TRANSACTION %lu %lu", + fprintf(f, "TRANSACTION %lu %lu", (ulong) ut_dulint_get_high(trx->id), (ulong) ut_dulint_get_low(trx->id)); switch (trx->conc_state) { - case TRX_NOT_STARTED: buf += sprintf(buf, - ", not started"); break; - case TRX_ACTIVE: buf += sprintf(buf, - ", ACTIVE %lu sec", - (ulong) difftime(time(NULL), trx->start_time)); break; - case TRX_COMMITTED_IN_MEMORY: buf += sprintf(buf, - ", COMMITTED IN MEMORY"); + case TRX_NOT_STARTED: + fputs(", not started", f); + break; + case TRX_ACTIVE: + fprintf(f, ", ACTIVE %lu sec", + (ulong)difftime(time(NULL), trx->start_time)); break; - default: buf += sprintf(buf, " state %lu", (ulong) trx->conc_state); + case TRX_COMMITTED_IN_MEMORY: + fputs(", COMMITTED IN MEMORY", f); + break; + default: + fprintf(f, " state %lu", (ulong) trx->conc_state); } #ifdef UNIV_LINUX - buf += sprintf(buf, ", process no %lu", trx->mysql_process_no); + fprintf(f, ", process no %lu", trx->mysql_process_no); #endif - buf += sprintf(buf, ", OS thread id %lu", + fprintf(f, ", OS thread id %lu", (ulong) os_thread_pf(trx->mysql_thread_id)); - if (ut_strlen(trx->op_info) > 0) { - buf += sprintf(buf, " %s", trx->op_info); + if (*trx->op_info) { + putc(' ', f); + fputs(trx->op_info, f); } if (trx->type != TRX_USER) { - buf += sprintf(buf, " purge trx"); + fputs(" purge trx", f); } if (trx->declared_to_be_inside_innodb) { - buf += sprintf(buf, ", thread declared inside InnoDB %lu", + fprintf(f, ", thread declared inside InnoDB %lu", (ulong) trx->n_tickets_to_enter_innodb); } - buf += sprintf(buf, "\n"); + putc('\n', f); if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) { - buf += sprintf(buf, "mysql tables in use %lu, locked %lu\n", - (ulong) trx->n_mysql_tables_in_use, - (ulong) trx->mysql_n_tables_locked); + fprintf(f, "mysql tables in use %lu, locked %lu\n", + (ulong) trx->n_mysql_tables_in_use, + (ulong) trx->mysql_n_tables_locked); } - start_of_line = buf; + newline = TRUE; switch (trx->que_state) { - case TRX_QUE_RUNNING: break; - case TRX_QUE_LOCK_WAIT: buf += sprintf(buf, - "LOCK WAIT "); break; - case TRX_QUE_ROLLING_BACK: buf += sprintf(buf, - "ROLLING BACK "); break; - case TRX_QUE_COMMITTING: buf += sprintf(buf, - "COMMITTING "); break; - default: buf += sprintf(buf, "que state %lu", (ulong) trx->que_state); + case TRX_QUE_RUNNING: + newline = FALSE; break; + case TRX_QUE_LOCK_WAIT: + fputs("LOCK WAIT ", f); break; + case TRX_QUE_ROLLING_BACK: + fputs("ROLLING BACK ", f); break; + case TRX_QUE_COMMITTING: + fputs("COMMITTING ", f); break; + default: + fprintf(f, "que state %lu ", (ulong) trx->que_state); } if (0 < UT_LIST_GET_LEN(trx->trx_locks) || mem_heap_get_size(trx->lock_heap) > 400) { + newline = TRUE; - buf += sprintf(buf, -"%lu lock struct(s), heap size %lu", + fprintf(f, "%lu lock struct(s), heap size %lu", (ulong) UT_LIST_GET_LEN(trx->trx_locks), (ulong) mem_heap_get_size(trx->lock_heap)); } if (trx->has_search_latch) { - buf += sprintf(buf, ", holds adaptive hash latch"); + newline = TRUE; + fputs(", holds adaptive hash latch", f); } if (ut_dulint_cmp(trx->undo_no, ut_dulint_zero) != 0) { - buf += sprintf(buf, ", undo log entries %lu", + newline = TRUE; + fprintf(f, ", undo log entries %lu", (ulong) ut_dulint_get_low(trx->undo_no)); } - if (buf != start_of_line) { - - buf += sprintf(buf, "\n"); + if (newline) { + putc('\n', f); } if (trx->mysql_thd != NULL) { - innobase_mysql_print_thd(buf, trx->mysql_thd); + innobase_mysql_print_thd(f, trx->mysql_thd); } } diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c index 0a47134c163..79566fe01c3 100644 --- a/innobase/trx/trx0undo.c +++ b/innobase/trx/trx0undo.c @@ -394,13 +394,10 @@ trx_undo_seg_create( #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(rseg->mutex))); #endif /* UNIV_SYNC_DEBUG */ -/* - if (type == TRX_UNDO_INSERT) { - printf("Creating insert undo log segment\n"); - } else { - printf("Creating update undo log segment\n"); - } -*/ + +/* fputs(type == TRX_UNDO_INSERT + ? "Creating insert undo log segment\n" + : "Creating update undo log segment\n", stderr); */ slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr); if (slot_no == ULINT_UNDEFINED) { diff --git a/innobase/ut/ut0byte.c b/innobase/ut/ut0byte.c index 74198419560..8764103dc36 100644 --- a/innobase/ut/ut0byte.c +++ b/innobase/ut/ut0byte.c @@ -36,9 +36,9 @@ Copies a string to a memory location, setting characters to lower case. */ void ut_cpy_in_lower_case( /*=================*/ - char* dest, /* in: destination */ - char* source,/* in: source */ - ulint len) /* in: string length */ + char* dest, /* in: destination */ + const char* source, /* in: source */ + ulint len) /* in: string length */ { ulint i; @@ -53,23 +53,27 @@ Compares two strings when converted to lower case. */ int ut_cmp_in_lower_case( /*=================*/ - /* out: -1, 0, 1 if str1 < str2, str1 == str2, - str1 > str2, respectively */ - char* str1, /* in: string1 */ - char* str2, /* in: string2 */ - ulint len) /* in: length of both strings */ + /* out: -1, 0, 1 if str1 < str2, str1 == str2, + str1 > str2, respectively */ + const char* str1, /* in: string1 */ + const char* str2) /* in: string2 */ { - ulint i; - - for (i = 0; i < len; i++) { - if (tolower(str1[i]) < tolower(str2[i])) { - return(-1); - } - - if (tolower(str1[i]) > tolower(str2[i])) { - return(1); - } - } + for (;;) { + int c1, c2; + if (!*str1) { + return(*str2 ? -1 : 0); + } else if (!*str2) { + return 1; + } + c1 = tolower(*str1++); + c2 = tolower(*str2++); + if (c1 < c2) { + return(-1); + } + if (c1 > c2) { + return(1); + } + } - return(0); + return(0); } diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index f7c0e1be9bd..9d0e63e6099 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -107,7 +107,7 @@ ut_malloc_low( /* Make an intentional seg fault so that we get a stack trace */ - printf("%lu\n", (ulong) *ut_mem_null_ptr); + if (*ut_mem_null_ptr) ut_mem_null_ptr = 0; } if (set_to_zero) { @@ -232,6 +232,49 @@ ut_free_all_mem(void) } /************************************************************************** +Make a quoted copy of a string. */ + +char* +ut_strcpyq( +/*=======*/ + /* out: pointer to end of dest */ + char* dest, /* in: output buffer */ + char q, /* in: the quote character */ + const char* src) /* in: null-terminated string */ +{ + while (*src) { + if ((*dest++ = *src++) == q) { + *dest++ = q; + } + } + + return(dest); +} + +/************************************************************************** +Make a quoted copy of a fixed-length string. */ + +char* +ut_memcpyq( +/*=======*/ + /* out: pointer to end of dest */ + char* dest, /* in: output buffer */ + char q, /* in: the quote character */ + const char* src, /* in: string to be quoted */ + ulint len) /* in: length of src */ +{ + const char* srcend = src + len; + + while (src < srcend) { + if ((*dest++ = *src++) == q) { + *dest++ = q; + } + } + + return(dest); +} + +/************************************************************************** Catenates two strings into newly allocated memory. The memory must be freed using mem_free. */ @@ -252,38 +295,12 @@ ut_str_catenate( str = mem_alloc(len1 + len2 + 1); ut_memcpy(str, str1, len1); - ut_memcpy(str + len1, str2, len2); - - str[len1 + len2] = '\0'; + ut_memcpy(str + len1, str2, len2 + 1); return(str); } /************************************************************************** -Checks if a null-terminated string contains a certain character. */ - -ibool -ut_str_contains( -/*============*/ - char* str, /* in: null-terminated string */ - char c) /* in: character */ -{ - ulint len; - ulint i; - - len = ut_strlen(str); - - for (i = 0; i < len; i++) { - if (str[i] == c) { - - return(TRUE); - } - } - - return(FALSE); -} - -/************************************************************************** Return a copy of the given string. The returned string must be freed using mem_free. */ diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c index 77f7a997777..21677e98318 100644 --- a/innobase/ut/ut0ut.c +++ b/innobase/ut/ut0ut.c @@ -19,6 +19,16 @@ Created 5/11/1994 Heikki Tuuri ibool ut_always_false = FALSE; +/********************************************************************* +Get the quote character to be used in SQL identifiers. +This definition must match the one in sql/ha_innodb.cc! */ + +char +mysql_get_identifier_quote_char(void); +/*=================================*/ + /* out: quote character to be + used in SQL identifiers */ + /************************************************************ On the 64-bit Windows we substitute the format string %l -> %I64 @@ -337,7 +347,7 @@ ut_print_timestamp( } /************************************************************** -Sprintfs a timestamp to a buffer. */ +Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */ void ut_sprintf_timestamp( @@ -474,7 +484,7 @@ ut_delay( } if (ut_always_false) { - printf("%lu", (ulong) j); + ut_always_false = (ibool) j; } return(j); @@ -486,78 +496,29 @@ Prints the contents of a memory buffer in hex and ascii. */ void ut_print_buf( /*=========*/ - byte* buf, /* in: memory buffer */ - ulint len) /* in: length of the buffer */ + FILE* file, /* in: file where to print */ + const byte* buf, /* in: memory buffer */ + ulint len) /* in: length of the buffer */ { - byte* data; - ulint i; + const byte* data; + ulint i; - printf(" len %lu; hex ", (ulong) len); - - data = buf; + fprintf(file, " len %lu; hex ", len); - for (i = 0; i < len; i++) { - printf("%02lx", (ulong) *data); - data++; + for (data = buf, i = 0; i < len; i++) { + fprintf(file, "%02lx", (ulong)*data++); } - printf("; asc "); + fputs("; asc ", file); data = buf; for (i = 0; i < len; i++) { - if (isprint((int)(*data))) { - printf("%c", (char)*data); - } - data++; + int c = (int) *data++; + putc(isprint(c) ? c : ' ', file); } - printf(";"); -} - -/***************************************************************** -Prints the contents of a memory buffer in hex and ascii. */ - -ulint -ut_sprintf_buf( -/*===========*/ - /* out: printed length in bytes */ - char* str, /* in: buffer to print to */ - byte* buf, /* in: memory buffer */ - ulint len) /* in: length of the buffer */ -{ - byte* data; - ulint n; - ulint i; - - n = 0; - - n += sprintf(str + n, " len %lu; hex ", (ulong) len); - - data = buf; - - for (i = 0; i < len; i++) { - n += sprintf(str + n, "%02lx", (ulong) *data); - data++; - } - - n += sprintf(str + n, "; asc "); - - data = buf; - - for (i = 0; i < len; i++) { - if (isprint((int)(*data))) { - n += sprintf(str + n, "%c", (char)*data); - } else { - n += sprintf(str + n, "."); - } - - data++; - } - - n += sprintf(str + n, ";"); - - return(n); + putc(';', file); } /**************************************************************** @@ -593,3 +554,64 @@ ut_2_power_up( return(res); } + +/************************************************************************** +Outputs a NUL-terminated string, quoted as an SQL identifier. */ + +void +ut_print_name( +/*==========*/ + FILE* f, /* in: output stream */ + const char* name) /* in: name to print */ +{ + ut_print_namel(f, name, strlen(name)); +} + +/************************************************************************** +Outputs a fixed-length string, quoted as an SQL identifier. */ + +void +ut_print_namel( +/*==========*/ + FILE* f, /* in: output stream */ + const char* name, /* in: name to print */ + ulint namelen)/* in: length of name */ +{ + const char* s = name; + const char* e = s + namelen; + char q = mysql_get_identifier_quote_char(); + putc(q, f); + while (s < e) { + int c = *s++; + if (c == q) { + putc(c, f); + } + putc(c, f); + } + putc(q, f); +} + +/************************************************************************** +Catenate files. */ + +void +ut_copy_file( +/*=========*/ + FILE* dest, /* in: output file */ + FILE* src) /* in: input file to be appended to output */ +{ + long len = ftell(src); + char buf[4096]; + + rewind(src); + do { + size_t maxs = + len < (long) sizeof buf ? (size_t) len : sizeof buf; + size_t size = fread(buf, 1, maxs, src); + fwrite(buf, 1, size, dest); + len -= size; + if (size < maxs) { + break; + } + } while (len > 0); +} diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 0cfcf8b1c49..4e65fa9364e 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -48,7 +48,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ key.cc lock.cc log.cc log_event.cc sql_state.c \ protocol.cc net_serv.cc opt_range.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \ - sql_load.cc sql_olap.cc \ + sql_load.cc sql_olap.cc discover.cc \ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \ sql_lex.cc sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \ diff --git a/ltmain.sh b/ltmain.sh index 953f6e71761..b28d160431c 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -48,6 +48,9 @@ EOF exit 0 fi +# libtool 1.4.2 workaround +SED=${SED:-sed} + # The name of this program. progname=`$echo "$0" | ${SED} 's%^.*/%%'` modename="$progname" diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 1d4bfee86a4..90647990ee8 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -205,6 +205,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) int r; uint off; int subkeys; + my_bool can_go_down; MI_INFO *info=ftb->info; if (init_search) @@ -221,6 +222,24 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) r=_mi_search(info, ftbw->keyinfo, (uchar*) ftbw->word+ftbw->off, USE_WHOLE_KEY, SEARCH_BIGGER, ftbw->key_root); } + + can_go_down=(!ftbw->off && (init_search || (ftbw->flags & FTB_FLAG_TRUNC))); + /* Skip rows inserted by concurrent insert */ + while (!r) + { + if (can_go_down) + { + /* going down ? */ + off=info->lastkey_length-HA_FT_WLEN-info->s->base.rec_reflength; + subkeys=ft_sintXkorr(info->lastkey+off); + } + if (subkeys<0 || info->lastpos < info->state->data_file_length) + break; + r= _mi_search_next(info, ftbw->keyinfo, info->lastkey, + info->lastkey_length, + SEARCH_BIGGER, ftbw->key_root); + } + if (!r && !ftbw->off) { r= mi_compare_text(ftb->charset, @@ -263,12 +282,12 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) if (!ftbw->off && (init_search || (ftbw->flags & FTB_FLAG_TRUNC))) { /* going down ? */ - get_key_full_length_rdonly(off, info->lastkey); - subkeys=ft_sintXkorr(info->lastkey+off); if (subkeys<0) { - /* yep, going down, to the second-level tree */ - /* TODO here: subkey-based optimization */ + /* + yep, going down, to the second-level tree + TODO here: subkey-based optimization + */ ftbw->off=off; ftbw->key_root=info->lastpos; ftbw->keyinfo=& info->s->ft2_keyinfo; diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 03875abe7b0..9b42d51ab55 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -88,7 +88,14 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) keylen-=HA_FT_WLEN; doc_cnt=0; - r=_mi_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root); + /* Skip rows inserted by current inserted */ + for (r=_mi_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root) ; + (subkeys=ft_sintXkorr(info->lastkey+info->lastkey_length-extra)) > 0 && + !r && info->lastpos >= info->state->data_file_length ; + r= _mi_search_next(info, keyinfo, info->lastkey, + info->lastkey_length, SEARCH_BIGGER, key_root)) + ; + info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */ while (!r && gweight) @@ -99,7 +106,6 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) info->lastkey_length-extra-1, keybuff+1,keylen-1,0,0)) break; - subkeys=ft_sintXkorr(info->lastkey+info->lastkey_length-extra); if (subkeys<0) { if (doc_cnt) @@ -113,7 +119,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) key_root=info->lastpos; keylen=0; r=_mi_search_first(info, keyinfo, key_root); - continue; + goto do_skip; } #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT tmp_weight=*(float*)&subkeys; @@ -151,6 +157,12 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) else r=_mi_search(info, keyinfo, info->lastkey, info->lastkey_length, SEARCH_BIGGER, key_root); +do_skip: + while ((subkeys=ft_sintXkorr(info->lastkey+info->lastkey_length-extra)) > 0 && + !r && info->lastpos >= info->state->data_file_length) + r= _mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, + SEARCH_BIGGER, key_root); + } word->weight=gweight; diff --git a/mysql-test/include/have_ndb.inc b/mysql-test/include/have_ndb.inc new file mode 100644 index 00000000000..095c2dcaaa4 --- /dev/null +++ b/mysql-test/include/have_ndb.inc @@ -0,0 +1,4 @@ +-- require r/have_ndb.require +disable_query_log; +show variables like "have_ndbcluster"; +enable_query_log; diff --git a/mysql-test/install_test_db.sh b/mysql-test/install_test_db.sh index ac5435f9832..8db338f0f58 100644 --- a/mysql-test/install_test_db.sh +++ b/mysql-test/install_test_db.sh @@ -77,7 +77,8 @@ EXTRA_ARG="--language=../sql/share/english/ --character-sets-dir=../sql/share/ch fi mysqld_boot=" $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \ - --basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb $EXTRA_ARG" + --basedir=$basedir --datadir=$ldata --skip-innodb --skip-ndbcluster --skip-bdb \ + $EXTRA_ARG" echo "running $mysqld_boot" if $scriptdir/mysql_create_system_tables test $mdata $hostname | $mysqld_boot diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index f47c63160eb..36f11220862 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -244,9 +244,9 @@ while test $# -gt 0; do --local) USE_RUNNING_SERVER="" ;; --extern) USE_RUNNING_SERVER="1" ;; --with-ndbcluster) - USE_NDBCLUSTER="--with-ndbcluster" ;; + USE_NDBCLUSTER="--ndbcluster" ;; --ndbconnectstring=*) - USE_NDBCLUSTER="--with-ndbcluster" ; + USE_NDBCLUSTER="--ndbcluster" ; USE_RUNNING_NDBCLUSTER=`$ECHO "$1" | $SED -e "s;--ndbconnectstring=;;"` ;; --tmpdir=*) MYSQL_TMP_DIR=`$ECHO "$1" | $SED -e "s;--tmpdir=;;"` ;; --local-master) @@ -1040,7 +1040,7 @@ start_slave() --core --init-rpl-role=slave \ --tmpdir=$MYSQL_TMP_DIR \ --language=$LANGUAGE \ - --skip-innodb --skip-slave-start \ + --skip-innodb --skip-ndbcluster --skip-slave-start \ --slave-load-tmpdir=$SLAVE_LOAD_TMPDIR \ --report-host=127.0.0.1 --report-user=root \ --report-port=$slave_port \ @@ -1421,6 +1421,7 @@ then fi # Remove files that can cause problems + $RM -rf $MYSQL_TEST_DIR/var/ndbcluster $RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/* # Remove old berkeley db log files that can confuse the server @@ -1436,7 +1437,7 @@ then if [ -z "$USE_RUNNING_NDBCLUSTER" ] then echo "Starting ndbcluster" - ./ndb/install_ndbcluster --initial --data-dir=$MASTER_MYDDIR || exit 1 + ./ndb/install_ndbcluster --initial --data-dir=$MYSQL_TEST_DIR/var || exit 1 export NDB_CONNECTSTRING=`cat Ndb.cfg` else export NDB_CONNECTSTRING="$USE_RUNNING_NDBCLUSTER" diff --git a/mysql-test/ndb/install_ndbcluster b/mysql-test/ndb/install_ndbcluster index dab94db759e..6cb3985b831 100755 --- a/mysql-test/ndb/install_ndbcluster +++ b/mysql-test/ndb/install_ndbcluster @@ -64,12 +64,12 @@ start_default_ndbcluster() { NDB_CONNECTSTRING= if [ $initial_ndb ] ; then - mkdir $fs_ndb - mkdir $fs_mgm_1 - mkdir $fs_ndb_2 - mkdir $fs_ndb_3 - mkdir $fs_name_2 - mkdir $fs_name_3 + [ -d $fs_ndb ] || mkdir $fs_ndb + [ -d $fs_mgm_1 ] || mkdir $fs_mgm_1 + [ -d $fs_ndb_2 ] || mkdir $fs_ndb_2 + [ -d $fs_ndb_3 ] || mkdir $fs_ndb_3 + [ -d $fs_name_2 ] || mkdir $fs_name_2 + [ -d $fs_name_3 ] || mkdir $fs_name_3 fi if [ -d "$fs_ndb" -a -d "$fs_mgm_1" -a -d "$fs_ndb_2" -a -d "$fs_ndb_3" -a -d "$fs_name_2" -a -d "$fs_name_3" ]; then :; else echo "$fs_ndb filesystem directory does not exist" diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 147d7776e4d..5192251795b 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -221,6 +221,68 @@ select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; max(t1.a2) max(t2.a1) zzz BBB drop table t1,t2; +CREATE TABLE t1 (a int, b int); +select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; +count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +0 NULL NULL NULL NULL NULL 18446744073709551615 0 +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +insert into t1 values (1,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +insert into t1 values (1,null); +insert into t1 values (2,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +insert into t1 values (2,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.0000 0.0000 1 1 1 1 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.0000 0.0000 1 1 1 1 +insert into t1 values (3,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.0000 0.0000 1 1 1 1 +3 1 1 1.0000 0.0000 1 1 1 1 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) bit_xor(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 0 +2 1 1 1.0000 0.0000 1 1 1 1 1 +3 1 1 1.0000 0.0000 1 1 1 1 1 +explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort +Warnings: +Note 1003 select high_priority big_result test.t1.a AS `a`,count(test.t1.b) AS `count(b)`,sum(test.t1.b) AS `sum(b)`,avg(test.t1.b) AS `avg(b)`,std(test.t1.b) AS `std(b)`,min(test.t1.b) AS `min(b)`,max(test.t1.b) AS `max(b)`,bit_and(test.t1.b) AS `bit_and(b)`,bit_or(test.t1.b) AS `bit_or(b)`,bit_xor(test.t1.b) AS `bit_xor(b)` from test.t1 group by test.t1.a +drop table t1; +create table t1 (col int); +insert into t1 values (-1), (-2), (-3); +select bit_and(col), bit_or(col) from t1; +bit_and(col) bit_or(col) +18446744073709551612 18446744073709551615 +select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; +bit_and(col) bit_or(col) +18446744073709551613 18446744073709551613 +18446744073709551614 18446744073709551614 +18446744073709551615 18446744073709551615 +drop table t1; +create table t1 (a int); +select avg(2) from t1; +avg(2) +NULL +drop table t1; create table t1( a1 char(3) primary key, a2 smallint, @@ -562,52 +624,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range k2 k2 4 NULL 6 Using where; Using index 1 SIMPLE t1 index NULL PRIMARY 3 NULL 14 Using index drop table t1, t2; -CREATE TABLE t1 (a int, b int); -select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; -count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -0 NULL NULL NULL NULL NULL 18446744073709551615 0 -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -insert into t1 values (1,null); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -insert into t1 values (1,null); -insert into t1 values (2,null); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -2 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -2 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -insert into t1 values (2,1); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -2 1 1 1.0000 0.0000 1 1 1 1 -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -2 1 1 1.0000 0.0000 1 1 1 1 -insert into t1 values (3,1); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -2 1 1 1.0000 0.0000 1 1 1 1 -3 1 1 1.0000 0.0000 1 1 1 1 -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) bit_xor(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 0 -2 1 1 1.0000 0.0000 1 1 1 1 1 -3 1 1 1.0000 0.0000 1 1 1 1 1 -explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort -Warnings: -Note 1003 select high_priority big_result test.t1.a AS `a`,count(test.t1.b) AS `count(b)`,sum(test.t1.b) AS `sum(b)`,avg(test.t1.b) AS `avg(b)`,std(test.t1.b) AS `std(b)`,min(test.t1.b) AS `min(b)`,max(test.t1.b) AS `max(b)`,bit_and(test.t1.b) AS `bit_and(b)`,bit_or(test.t1.b) AS `bit_or(b)`,bit_xor(test.t1.b) AS `bit_xor(b)` from test.t1 group by test.t1.a -drop table t1; create table t1 (USR_ID integer not null, MAX_REQ integer not null, constraint PK_SEA_USER primary key (USR_ID)) engine=InnoDB; insert into t1 values (1, 3); select count(*) + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ + MAX_REQ - MAX_REQ from t1 group by MAX_REQ; @@ -632,14 +648,3 @@ select a from t1 having a=1; a 1 drop table t1; -create table t1 (col int); -insert into t1 values (-1), (-2), (-3); -select bit_and(col), bit_or(col) from t1; -bit_and(col) bit_or(col) -18446744073709551612 18446744073709551615 -select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; -bit_and(col) bit_or(col) -18446744073709551613 18446744073709551613 -18446744073709551614 18446744073709551614 -18446744073709551615 18446744073709551615 -drop table t1; diff --git a/mysql-test/r/have_ndb.require b/mysql-test/r/have_ndb.require new file mode 100644 index 00000000000..f0402b72c6a --- /dev/null +++ b/mysql-test/r/have_ndb.require @@ -0,0 +1,2 @@ +Variable_name Value +have_ndbcluster YES diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index b0a15d9a021..01114104088 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -21,6 +21,38 @@ DROP TABLE t1; CREATE TABLE t1 (a decimal(240, 20)); INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); +CREATE TABLE `t1` ( + `a` decimal(240,20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('0987654321098765432109876543210987654321.00000000000000000000'); +DROP TABLE t1; +CREATE TABLE t1 (a double); +INSERT INTO t1 VALUES (-9e999999); +CREATE TABLE `t1` ( + `a` double default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO `t1` VALUES (RES); +DROP TABLE t1; +CREATE TABLE t1 (a DECIMAL(10,5), b FLOAT); +INSERT INTO t1 VALUES (1.2345, 2.3456); +INSERT INTO t1 VALUES ('1.2345', 2.3456); +INSERT INTO t1 VALUES ("1.2345", 2.3456); +SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI_QUOTES'; +INSERT INTO t1 VALUES (1.2345, 2.3456); +INSERT INTO t1 VALUES ('1.2345', 2.3456); +INSERT INTO t1 VALUES ("1.2345", 2.3456); +ERROR 42S22: Unknown column '1.2345' in 'field list' +SET SQL_MODE=@OLD_SQL_MODE; +CREATE TABLE `t1` ( + `a` decimal(10,5) default NULL, + `b` float default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); +CREATE TABLE `t1` ( + `a` decimal(10,5) default NULL, + `b` float default NULL +); +INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT, CHARACTER_SET_CLIENT=utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; @@ -28,13 +60,14 @@ INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( - `a` decimal(240,20) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; + `a` decimal(10,5) default NULL, + `b` float default NULL +); /*!40000 ALTER TABLE `t1` DISABLE KEYS */; LOCK TABLES `t1` WRITE; -INSERT INTO `t1` VALUES ("1234567890123456789012345678901234567890.00000000000000000000"),("0987654321098765432109876543210987654321.00000000000000000000"); +INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; @@ -43,30 +76,19 @@ UNLOCK TABLES; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -DROP TABLE t1; -CREATE TABLE t1 (a double); -INSERT INTO t1 VALUES (-9e999999); - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT, CHARACTER_SET_CLIENT=utf8 */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; -DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` ( - `a` double default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - + `a` decimal(10,5) default NULL, + `b` float default NULL +); -/*!40000 ALTER TABLE `t1` DISABLE KEYS */; -LOCK TABLES `t1` WRITE; -INSERT INTO `t1` VALUES (RES); -UNLOCK TABLES; -/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +INSERT INTO `t1` VALUES ('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456),('1.23450',2.3456); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; DROP TABLE t1; CREATE TABLE t1(a int, b text, c varchar(3)); @@ -180,27 +202,9 @@ UNLOCK TABLES; DROP TABLE t1; create table ```a` (i int); - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT, CHARACTER_SET_CLIENT=utf8 */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; -DROP TABLE IF EXISTS ```a`; CREATE TABLE ```a` ( `i` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; - - -/*!40000 ALTER TABLE ```a` DISABLE KEYS */; -LOCK TABLES ```a` WRITE; -UNLOCK TABLES; -/*!40000 ALTER TABLE ```a` ENABLE KEYS */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; - drop table ```a`; create table t1(a int); diff --git a/mysql-test/r/ndb_basic.result b/mysql-test/r/ndb_basic.result new file mode 100644 index 00000000000..ac550937146 --- /dev/null +++ b/mysql-test/r/ndb_basic.result @@ -0,0 +1,82 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +pk1 INT NOT NULL PRIMARY KEY, +attr1 INT NOT NULL +) ENGINE=ndbcluster; +INSERT INTO t1 VALUES (9410,9412); +SELECT pk1 FROM t1; +pk1 +9410 +SELECT * FROM t1; +pk1 attr1 +9410 9412 +SELECT t1.* FROM t1; +pk1 attr1 +9410 9412 +UPDATE t1 SET attr1=1 WHERE pk1=9410; +SELECT * FROM t1; +pk1 attr1 +9410 1 +UPDATE t1 SET pk1=2 WHERE attr1=1; +ERROR 42000: Table 't1' uses an extension that doesn't exist in this MySQL version +SELECT * FROM t1; +pk1 attr1 +9410 1 +DELETE FROM t1; +SELECT * FROM t1; +pk1 attr1 +INSERT INTO t1 VALUES (9410,9412); +DELETE FROM t1 WHERE pk1 = 9410; +SELECT * FROM t1; +pk1 attr1 +INSERT INTO t1 VALUES (9410,9412), (9411, 9413), (9408, 8765); +DELETE FROM t1; +SELECT * FROM t1; +pk1 attr1 +INSERT INTO t1 values (1, 4), (2, 4), (3, 5), (4, 4), (5, 5); +DELETE FROM t1 WHERE attr1=4; +SELECT * FROM t1 order by pk1; +pk1 attr1 +3 5 +5 5 +DELETE FROM t1; +INSERT INTO t1 VALUES (9410,9412), (9411, 9413); +DELETE FROM t1 WHERE pk1 = 9410; +SELECT * FROM t1; +pk1 attr1 +9411 9413 +DROP TABLE t1; +CREATE TABLE t1 (id INT, id2 int) engine=ndbcluster; +INSERT INTO t1 values(3456, 7890); +SELECT * FROM t1; +id id2 +3456 7890 +UPDATE t1 SET id=2 WHERE id2=12; +SELECT * FROM t1; +id id2 +3456 7890 +UPDATE t1 SET id=1234 WHERE id2=7890; +SELECT * FROM t1; +id id2 +1234 7890 +DELETE FROM t1; +INSERT INTO t1 values(3456, 7890), (3456, 7890), (3456, 7890); +SELECT * FROM t1; +id id2 +3456 7890 +3456 7890 +3456 7890 +DELETE FROM t1 WHERE id = 3456; +DROP TABLE t1; +CREATE TABLE t1 ( +pk1 INT NOT NULL PRIMARY KEY, +attr1 INT NOT NULL +) ENGINE=NDBCLUSTER; +INSERT INTO t1 values(1, 9999); +DROP TABLE t1; +CREATE TABLE t1 ( +pk1 INT NOT NULL PRIMARY KEY, +attr1 INT NOT NULL +) ENGINE=NDB; +INSERT INTO t1 values(1, 9999); +DROP TABLE t1; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index b54d4b5a342..c462a88ac1b 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -43,7 +43,7 @@ wait_timeout 28800 show variables like "this_doesn't_exists%"; Variable_name Value show table status from test like "this_doesn't_exists%"; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment show databases; Database mysql @@ -309,7 +309,7 @@ insert into t1 values (1),(2); insert into t2 values (1),(2); insert into t3 values (1,1),(2,2); show table status; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 HEAP Fixed 2 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t2 HEAP Fixed 2 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t3 HEAP Fixed 2 9 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL @@ -317,7 +317,7 @@ insert into t1 values (3),(4); insert into t2 values (3),(4); insert into t3 values (3,3),(4,4); show table status; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 HEAP Fixed 4 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t2 HEAP Fixed 4 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t3 HEAP Fixed 4 9 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL @@ -325,7 +325,7 @@ insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); show table status; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 HEAP Fixed 5 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t2 HEAP Fixed 5 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t3 HEAP Fixed 5 9 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL @@ -333,7 +333,7 @@ delete from t1 where a=3; delete from t2 where b=3; delete from t3 where a=3; show table status; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 HEAP Fixed 4 5 # # # 5 NULL NULL NULL NULL latin1_swedish_ci NULL t2 HEAP Fixed 4 5 # # # 5 NULL NULL NULL NULL latin1_swedish_ci NULL t3 HEAP Fixed 4 9 # # # 9 NULL NULL NULL NULL latin1_swedish_ci NULL @@ -341,7 +341,7 @@ delete from t1; delete from t2; delete from t3; show table status; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 HEAP Fixed 0 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t2 HEAP Fixed 0 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t3 HEAP Fixed 0 9 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL @@ -349,7 +349,7 @@ insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); show table status; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 HEAP Fixed 1 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t2 HEAP Fixed 1 5 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL t3 HEAP Fixed 1 9 # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL @@ -357,7 +357,7 @@ delete from t1 where a=5; delete from t2 where b=5; delete from t3 where a=5; show table status; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment +Name Engine Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 HEAP Fixed 0 5 # # # 5 NULL NULL NULL NULL latin1_swedish_ci NULL t2 HEAP Fixed 0 5 # # # 5 NULL NULL NULL NULL latin1_swedish_ci NULL t3 HEAP Fixed 0 9 # # # 9 NULL NULL NULL NULL latin1_swedish_ci NULL diff --git a/mysql-test/std_data/init_file.dat b/mysql-test/std_data/init_file.dat index 4236ada1142..6105ca2ac1b 100644 --- a/mysql-test/std_data/init_file.dat +++ b/mysql-test/std_data/init_file.dat @@ -1 +1 @@ -select * from mysql.user as t1, mysql.user as t2, mysql.user as t3, mysql.user as t4, mysql.user as t5, mysql.user as t6, mysql.user as t7, mysql.user as t8;
\ No newline at end of file +select * from mysql.user as t1, mysql.user as t2, mysql.user as t3; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 2bd4838f934..a1acf5f89eb 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -135,6 +135,45 @@ select max(t1.a2),max(t2.a1) from t1 left outer join t2 on t1.a1=10; drop table t1,t2; # +# Test of group function and NULL values +# + +CREATE TABLE t1 (a int, b int); +select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (1,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (1,null); +insert into t1 values (2,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (2,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (3,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +drop table t1; + +# +# Bug #1972: test for bit_and(), bit_or() and negative values +# +create table t1 (col int); +insert into t1 values (-1), (-2), (-3); +select bit_and(col), bit_or(col) from t1; +select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; +drop table t1; + +# +# Bug #3376: avg() and an empty table +# + +create table t1 (a int); +select avg(2) from t1; +drop table t1; + +# # Tests to check MIN/MAX query optimization # @@ -327,27 +366,6 @@ explain select concat(min(t1.a1),min(t2.a4)) from t1, t2 where t2.a4 <> 'AME'; drop table t1, t2; -# -# Test of group function and NULL values -# - -CREATE TABLE t1 (a int, b int); -select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -insert into t1 values (1,null); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -insert into t1 values (1,null); -insert into t1 values (2,null); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -insert into t1 values (2,1); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -insert into t1 values (3,1); -select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; -explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; -drop table t1; --disable_warnings create table t1 (USR_ID integer not null, MAX_REQ integer not null, constraint PK_SEA_USER primary key (USR_ID)) engine=InnoDB; --enable_warnings @@ -369,11 +387,3 @@ insert into t1 values (1); select max(a) as b from t1 having b=1; select a from t1 having a=1; drop table t1; -# -# Bug #1972: test for bit_and(), bit_or() and negative values -# -create table t1 (col int); -insert into t1 values (-1), (-2), (-3); -select bit_and(col), bit_or(col) from t1; -select SQL_BIG_RESULT bit_and(col), bit_or(col) from t1 group by col; -drop table t1; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 28992655bd2..bcfe81dc95f 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -6,7 +6,7 @@ DROP TABLE IF EXISTS t1, `"t"1`; CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); ---exec $MYSQL_DUMP --skip-all --skip-comments -X test t1 +--exec $MYSQL_DUMP --skip-create --skip-comments -X test t1 DROP TABLE t1; # @@ -16,7 +16,7 @@ DROP TABLE t1; CREATE TABLE t1 (a decimal(240, 20)); INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); ---exec $MYSQL_DUMP --skip-comments test t1 +--exec $MYSQL_DUMP --compact test t1 DROP TABLE t1; # @@ -28,12 +28,38 @@ INSERT INTO t1 VALUES (-9e999999); # The following replaces is here because some systems replaces the above # double with '-inf' and others with MAX_DOUBLE --replace_result (-1.79769313486232e+308) (RES) (NULL) (RES) ---exec $MYSQL_DUMP --skip-comments test t1 +--exec $MYSQL_DUMP --compact test t1 +DROP TABLE t1; + +# +# Bug #3361 mysqldump quotes DECIMAL values inconsistently +# + +CREATE TABLE t1 (a DECIMAL(10,5), b FLOAT); + +# check at first how mysql work with quoted decimal + +INSERT INTO t1 VALUES (1.2345, 2.3456); +INSERT INTO t1 VALUES ('1.2345', 2.3456); +INSERT INTO t1 VALUES ("1.2345", 2.3456); + +SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI_QUOTES'; +INSERT INTO t1 VALUES (1.2345, 2.3456); +INSERT INTO t1 VALUES ('1.2345', 2.3456); +--error 1054 +INSERT INTO t1 VALUES ("1.2345", 2.3456); +SET SQL_MODE=@OLD_SQL_MODE; + +# check how mysqldump make quoting +--exec $MYSQL_DUMP --compact test t1 +--exec $MYSQL_DUMP --compact --skip-create test t1 +--exec $MYSQL_DUMP --skip-create --skip-comments test t1 +--exec $MYSQL_DUMP --skip-opt --extended-insert --skip-comments test t1 DROP TABLE t1; CREATE TABLE t1(a int, b text, c varchar(3)); INSERT INTO t1 VALUES (1, "test", "tes"), (2, "TEST", "TES"); ---exec $MYSQL_DUMP --skip-all --skip-comments -X test t1 +--exec $MYSQL_DUMP --skip-create --compact -X test t1 DROP TABLE t1; # @@ -42,7 +68,7 @@ DROP TABLE t1; CREATE TABLE t1 (`a"b"` char(2)); INSERT INTO t1 VALUES ("1\""), ("\"2"); ---exec $MYSQL_DUMP --skip-all --skip-comments -X test t1 +--exec $MYSQL_DUMP --compact --skip-create -X test t1 DROP TABLE t1; # @@ -51,7 +77,7 @@ DROP TABLE t1; CREATE TABLE t1 (a VARCHAR(255)) DEFAULT CHARSET koi8r; INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'); ---exec $MYSQL_DUMP --skip-comments test t1 +--exec $MYSQL_DUMP --skip-comments test t1 DROP TABLE t1; # @@ -65,11 +91,11 @@ INSERT INTO t1 VALUES (1), (2); DROP TABLE t1; # -# Bug #2592 'mysqldum doesn't quote "tricky" names correctly' +# Bug #2592 'mysqldump doesn't quote "tricky" names correctly' # create table ```a` (i int); ---exec $MYSQL_DUMP --skip-comments test +--exec $MYSQL_DUMP --compact test drop table ```a`; # diff --git a/mysql-test/t/ndb_basic.test b/mysql-test/t/ndb_basic.test new file mode 100644 index 00000000000..d03abc34633 --- /dev/null +++ b/mysql-test/t/ndb_basic.test @@ -0,0 +1,98 @@ +-- source include/have_ndb.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +# +# Basic test to show that the NDB +# table handler is working +# + +# +# Create a normal table with primary key +# +CREATE TABLE t1 ( + pk1 INT NOT NULL PRIMARY KEY, + attr1 INT NOT NULL +) ENGINE=ndbcluster; + +INSERT INTO t1 VALUES (9410,9412); + +SELECT pk1 FROM t1; +SELECT * FROM t1; +SELECT t1.* FROM t1; + +UPDATE t1 SET attr1=1 WHERE pk1=9410; +SELECT * FROM t1; + +# Can't UPDATE PK! Test that correct error is returned +-- error 1112 +UPDATE t1 SET pk1=2 WHERE attr1=1; +SELECT * FROM t1; + +# Delete the record +DELETE FROM t1; +SELECT * FROM t1; + +# Delete the record by specifying pk +INSERT INTO t1 VALUES (9410,9412); +DELETE FROM t1 WHERE pk1 = 9410; +SELECT * FROM t1; + +# Insert three records and delete the +INSERT INTO t1 VALUES (9410,9412), (9411, 9413), (9408, 8765); +DELETE FROM t1; +SELECT * FROM t1; + +# Insert three records with attr1=4 and two with attr1=5 +# Delete all with attr1=4 +INSERT INTO t1 values (1, 4), (2, 4), (3, 5), (4, 4), (5, 5); +DELETE FROM t1 WHERE attr1=4; +SELECT * FROM t1 order by pk1; +DELETE FROM t1; + +# Insert two records and delete one +INSERT INTO t1 VALUES (9410,9412), (9411, 9413); +DELETE FROM t1 WHERE pk1 = 9410; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Create table without primary key +# a hidden primary key column is created by handler +# +CREATE TABLE t1 (id INT, id2 int) engine=ndbcluster; +INSERT INTO t1 values(3456, 7890); +SELECT * FROM t1; +UPDATE t1 SET id=2 WHERE id2=12; +SELECT * FROM t1; +UPDATE t1 SET id=1234 WHERE id2=7890; +SELECT * FROM t1; +DELETE FROM t1; + +INSERT INTO t1 values(3456, 7890), (3456, 7890), (3456, 7890); +SELECT * FROM t1; +DELETE FROM t1 WHERE id = 3456; + +DROP TABLE t1; + +# test create with the keyword "engine=NDBCLUSTER" +CREATE TABLE t1 ( + pk1 INT NOT NULL PRIMARY KEY, + attr1 INT NOT NULL +) ENGINE=NDBCLUSTER; + +INSERT INTO t1 values(1, 9999); + +DROP TABLE t1; + +# test create with the keyword "engine=NDB" +CREATE TABLE t1 ( + pk1 INT NOT NULL PRIMARY KEY, + attr1 INT NOT NULL +) ENGINE=NDB; + +INSERT INTO t1 values(1, 9999); + +DROP TABLE t1; diff --git a/mysys/charset.c b/mysys/charset.c index 80f62b06a3e..e58c851cf7c 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -97,7 +97,7 @@ static void init_state_maps(CHARSET_INFO *cs) state_map[(uchar)'<']= (uchar) MY_LEX_LONG_CMP_OP; state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) MY_LEX_BOOL; state_map[(uchar)'#']=(uchar) MY_LEX_COMMENT; - state_map[(uchar)';']=(uchar) MY_LEX_COLON; + state_map[(uchar)';']=(uchar) MY_LEX_SEMICOLON; state_map[(uchar)':']=(uchar) MY_LEX_SET_VAR; state_map[0]=(uchar) MY_LEX_EOL; state_map[(uchar)'\\']= (uchar) MY_LEX_ESCAPE; @@ -373,7 +373,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) uint len; MY_STAT stat_info; - if (!my_stat(filename, &stat_info, MYF(MY_WME)) || + if (!my_stat(filename, &stat_info, MYF(myflags)) || ((len= (uint)stat_info.st_size) > MY_MAX_ALLOWED_BUF) || !(buf= (char *)my_malloc(len,myflags))) return TRUE; diff --git a/ndb/BinDist.sh b/ndb/BinDist.sh index ed0b294c912..2f9620549f4 100644 --- a/ndb/BinDist.sh +++ b/ndb/BinDist.sh @@ -27,7 +27,7 @@ bin/flexBench bin/select_all bin/select_count bin/delete_all -bin/ndbsql +#bin/ndbsql bin/drop_tab bin/drop_index bin/list_tables @@ -39,7 +39,7 @@ lib/libNDB_API.a lib/libNDB_API.so lib/libMGM_API.a lib/libMGM_API.so -lib/libNDB_ODBC.so +#lib/libNDB_ODBC.so lib/libMGM_API_pic.a lib/libNDB_API_pic.a include/ diff --git a/ndb/config/GuessConfig.sh b/ndb/config/GuessConfig.sh index a1ecdecfa93..6cbb50a09e4 100755 --- a/ndb/config/GuessConfig.sh +++ b/ndb/config/GuessConfig.sh @@ -48,22 +48,7 @@ esac if [ -z "$NDB_ODBC" ] then - val=N - if [ -f /usr/include/sqlext.h -o -f /usr/local/include/sqlext.h ] - then - val=Y - fi - case $NDB_OS in - LINUX) - NDB_ODBC=$val - ;; - MACOSX) - NDB_ODBC=$val - ;; - *) - NDB_ODBC=N - ;; - esac + NDB_ODBC=N fi diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 6a13af09f4e..3261ec309d4 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -17,6 +17,7 @@ DEBUG=0 SILENT=0 TMP=/tmp SUFFIX="" +NDBCLUSTER= parse_arguments() { for arg do @@ -26,6 +27,7 @@ parse_arguments() { --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; --no-strip) STRIP=0 ;; --silent) SILENT=1 ;; + --with-ndbcluster) NDBCLUSTER=1 ;; *) echo "Unknown argument '$arg'" exit 1 @@ -245,6 +247,18 @@ if [ -d $BASE/sql-bench/SCCS ] ; then find $BASE/sql-bench -name SCCS -print | xargs rm -r -f fi +# NDB Cluster +if [ x$NDBCLUSTER = x1 ]; then + if [ ! -f ndb/BinDist.sh ]; then + echo "Missing ndb/BinDist.sh"; exit 1 + fi + mkdir $BASE/ndb || exit 1 + # assume we have cpio.. + if (cd ndb && sh BinDist.sh | cpio -pdm $BASE/ndb); then :; else + echo "Copy failed - missing files in ndb/BinDist.sh ?"; exit 1 + fi +fi + # Change the distribution to a long descriptive name NEW_NAME=mysql@MYSQL_SERVER_SUFFIX@-$version-$system-$machine$SUFFIX BASE2=$TMP/$NEW_NAME diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index b30d521c093..9767976460c 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -4,7 +4,7 @@ use Getopt::Long; use POSIX qw(strftime); $|=1; -$VER="2.6"; +$VER="2.7"; $opt_config_file = undef(); $opt_example = 0; @@ -47,11 +47,35 @@ sub main print "MySQL distribution.\n"; $my_print_defaults_exists= 0; } - my @defops = `my_print_defaults mysqld_multi`; - chop @defops; - splice @ARGV, 0, 0, @defops; + if ($my_print_defaults_exists) + { + foreach my $arg (@ARGV) + { + if ($arg =~ m/^--config-file=(.*)/) + { + if (!length($1)) + { + die "Option config-file requires an argument\n"; + } + elsif (!( -e $1 && -r $1)) + { + die "Option file '$1' doesn't exists, or is not readable\n"; + } + else + { + $opt_config_file= $1; + } + } + } + my $com= "my_print_defaults "; + $com.= "--config-file=$opt_config_file " if (defined($opt_config_file)); + $com.= "mysqld_multi"; + my @defops = `$com`; + chop @defops; + splice @ARGV, 0, 0, @defops; + } GetOptions("help","example","version","mysqld=s","mysqladmin=s", - "config-file=s","user=s","password=s","log=s","no-log","tcp-ip") + "config-file=s","user=s","password=s","log=s","no-log","tcp-ip") || die "Wrong option! See $my_progname --help for detailed information!\n"; init_log(); @@ -156,6 +180,45 @@ sub init_log } #### +#### Init log file. Check for appropriate place for log file, in the following +#### order my_print_defaults mysqld datadir, @datadir@, /var/log, /tmp +#### + +sub init_log +{ + if ($my_print_defaults_exists) + { + @mysqld_opts= `my_print_defaults mysqld`; + chomp @mysqld_opts; + foreach my $opt (@mysqld_opts) + { + if ($opt =~ m/^\-\-datadir[=](.*)/) + { + if (-d "$1" && -w "$1") + { + $logdir= $1; + } + } + } + } + if (!defined($logdir)) + { + $logdir= "@datadir@" if (-d "@datadir@" && -w "@datadir@"); + } + if (!defined($logdir)) + { + # Log file was not specified and we could not log to a standard place, + # so log file be disabled for now. + print "WARNING: Log file disabled. Maybe directory/file isn't writable?\n"; + $opt_no_log= 1; + } + else + { + $opt_log= "$logdir/mysqld_multi.log"; + } +} + +#### #### Report living and not running MySQL servers #### @@ -632,12 +695,9 @@ reported. Note that you must not have any white spaces in the GNR list. Anything after a white space are ignored. Options: ---config-file=... Alternative config file. NOTE: This will not affect - this program's own options (group [mysqld_multi]), - but only groups [mysqld#]. Without this option everything - will be searched from the ordinary my.cnf file. +--config-file=... Alternative config file. Using: $opt_config_file ---example Give an example of a config file. (PLEASE DO CHECK THIS!) +--example Give an example of a config file. --help Print this help and exit. --log=... Log file. Full path to and the name for the log file. NOTE: If the file exists, everything will be appended. diff --git a/sql/Makefile.am b/sql/Makefile.am index bacf3bc58d1..1044673f8ec 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -16,12 +16,11 @@ #called from the top level Makefile - MYSQLDATAdir = $(localstatedir) MYSQLSHAREdir = $(pkgdatadir) MYSQLBASEdir= $(prefix) INCLUDES = @MT_INCLUDES@ \ - @bdb_includes@ @innodb_includes@ \ + @bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \ -I$(top_srcdir)/include -I$(top_srcdir)/regex \ -I$(srcdir) $(openssl_includes) WRAPLIBS= @WRAPLIBS@ @@ -42,6 +41,7 @@ LDADD = @isam_libs@ \ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \ @bdb_libs@ @innodb_libs@ @pstack_libs@ \ @innodb_system_libs@ \ + @ndbcluster_libs@ @ndbcluster_system_libs@ \ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ item_strfunc.h item_timefunc.h item_uniq.h \ @@ -52,7 +52,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ field.h handler.h \ ha_isammrg.h ha_isam.h ha_myisammrg.h\ ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \ - opt_range.h protocol.h \ + ha_ndbcluster.h opt_range.h protocol.h \ sql_select.h structs.h table.h sql_udf.h hash_filo.h\ lex.h lex_symbol.h sql_acl.h sql_crypt.h \ log_event.h sql_repl.h slave.h \ @@ -76,11 +76,11 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ procedure.cc item_uniq.cc sql_test.cc \ log.cc log_event.cc init.cc derror.cc sql_acl.cc \ unireg.cc des_key_file.cc \ - time.cc opt_range.cc opt_sum.cc \ + discover.cc time.cc opt_range.cc opt_sum.cc \ records.cc filesort.cc handler.cc \ ha_heap.cc ha_myisam.cc ha_myisammrg.cc \ ha_berkeley.cc ha_innodb.cc \ - ha_isam.cc ha_isammrg.cc \ + ha_isam.cc ha_isammrg.cc ha_ndbcluster.cc \ sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ diff --git a/sql/discover.cc b/sql/discover.cc new file mode 100644 index 00000000000..e260f44a8db --- /dev/null +++ b/sql/discover.cc @@ -0,0 +1,172 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* Functions for discover of frm file from handler */ + +#include "mysql_priv.h" +#include <my_dir.h> + +/* + Read the contents of a .frm file + + SYNOPSIS + readfrm() + + name path to table-file "db/name" + frmdata frm data + len length of the read frmdata + + RETURN VALUES + 0 ok + 1 Could not open file + 2 Could not stat file + 3 Could not allocate data for read + Could not read file + + frmdata and len are set to 0 on error +*/ + +int readfrm(const char *name, + const void **frmdata, uint *len) +{ + int error; + char index_file[FN_REFLEN]; + File file; + ulong read_len; + char *read_data; + MY_STAT state; + DBUG_ENTER("readfrm"); + DBUG_PRINT("enter",("name: '%s'",name)); + + *frmdata= NULL; // In case of errors + *len= 0; + error= 1; + if ((file=my_open(fn_format(index_file,name,"",reg_ext,4), + O_RDONLY | O_SHARE, + MYF(0))) < 0) + goto err_end; + + // Get length of file + error= 2; + if (my_fstat(file, &state, MYF(0))) + goto err; + read_len= state.st_size; + + // Read whole frm file + error= 3; + read_data= 0; + if (read_string(file, &read_data, read_len)) + goto err; + + // Setup return data + *frmdata= (void*) read_data; + *len= read_len; + error= 0; + + err: + if (file > 0) + VOID(my_close(file,MYF(MY_WME))); + + err_end: /* Here when no file */ + DBUG_RETURN (error); +} /* readfrm */ + + +/* + Write the content of a frm data pointer + to a frm file + + SYNOPSIS + writefrm() + + name path to table-file "db/name" + frmdata frm data + len length of the frmdata + + RETURN VALUES + 0 ok + 2 Could not write file +*/ + +int writefrm(const char *name, const void *frmdata, uint len) +{ + File file; + char index_file[FN_REFLEN]; + int error; + DBUG_ENTER("writefrm"); + DBUG_PRINT("enter",("name: '%s' len: %d ",name,len)); + //DBUG_DUMP("frmdata", (char*)frmdata, len); + + error= 0; + if ((file=my_create(fn_format(index_file,name,"",reg_ext,4), + CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) + { + if (my_write(file,(byte*)frmdata,len,MYF(MY_WME | MY_NABP))) + error= 2; + } + VOID(my_close(file,MYF(0))); + DBUG_RETURN(error); +} /* writefrm */ + + + + +/* + Try to discover table from handler and + if found, write the frm file to disk. + + RETURN VALUES: + 0 : Table existed in handler and created + on disk if so requested + 1 : Table does not exist + >1 : error + +*/ + +int create_table_from_handler(const char *db, + const char *name, + bool create_if_found) +{ + int error= 0; + const void* frmblob = NULL; + char path[FN_REFLEN]; + uint frmlen = 0; + DBUG_ENTER("create_table_from_handler"); + DBUG_PRINT("enter", ("create_if_found: %d", create_if_found)); + + if (ha_discover(db, name, &frmblob, &frmlen)) + DBUG_RETURN(1); // Table does not exist + + // Table exists in handler + if (create_if_found) + { + (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); + // Save the frm file + error = writefrm(path, frmblob, frmlen); + } + + err: + if (frmblob) + my_free((char*) frmblob,MYF(0)); + DBUG_RETURN(error); +} + +int table_exists_in_handler(const char *db, + const char *name) +{ + return (create_table_from_handler(db, name, false) == 0); +} diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 5dc7c50e04c..7a445ed8c4d 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -461,7 +461,7 @@ int main(int argc,char **argv) hash_map= sql_functions_map;\n\ register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\ \n\ - for(;;){\n\ + for (;;){\n\ register uchar first_char= (uchar)cur_struct;\n\ \n\ if (first_char == 0)\n\ @@ -492,7 +492,7 @@ int main(int argc,char **argv) hash_map= symbols_map;\n\ register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\ \n\ - for(;;){\n\ + for (;;){\n\ register uchar first_char= (uchar)cur_struct;\n\ \n\ if (first_char==0){\n\ diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index a5dc6719182..4192df22e5c 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -15,7 +15,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This file defines the InnoDB handler: the interface between MySQL and -InnoDB */ +InnoDB +NOTE: You can only use noninlined InnoDB functions in this file, because we +have disables the InnoDB inlining in this file. */ /* TODO list for the InnoDB handler in 4.1: - Check if the query_id is now right also in prepared and executed stats @@ -74,6 +76,7 @@ extern "C" { #include "../innobase/include/btr0cur.h" #include "../innobase/include/btr0btr.h" #include "../innobase/include/fsp0fsp.h" +#include "../innobase/include/sync0sync.h" #include "../innobase/include/fil0fil.h" } @@ -321,70 +324,49 @@ convert_error_code_to_mysql( } } -extern "C" { /***************************************************************** Prints info of a THD object (== user session thread) to the standard output. NOTE that /mysql/innobase/trx/trx0trx.c must contain the prototype for this function! */ - +extern "C" void innobase_mysql_print_thd( /*=====================*/ - char* buf, /* in/out: buffer where to print, must be at least - 400 bytes */ + FILE* f, /* in: output stream */ void* input_thd)/* in: pointer to a MySQL THD object */ { THD* thd; - char* old_buf = buf; thd = (THD*) input_thd; - /* We cannot use the return value of normal sprintf() as this is - not portable to some old non-Posix Unixes, e.g., some old SCO - Unixes */ - - buf += my_sprintf(buf, - (buf, "MySQL thread id %lu, query id %lu", - thd->thread_id, thd->query_id)); - if (thd->host) { - *buf = ' '; - buf++; - buf = strnmov(buf, thd->host, 30); - } + fprintf(f, "MySQL thread id %lu, query id %lu", + thd->thread_id, thd->query_id); + if (thd->host) { + putc(' ', f); + fputs(thd->host, f); + } - if (thd->ip) { - *buf = ' '; - buf++; - buf=strnmov(buf, thd->ip, 20); - } + if (thd->ip) { + putc(' ', f); + fputs(thd->ip, f); + } if (thd->user) { - *buf = ' '; - buf++; - buf=strnmov(buf, thd->user, 20); - } - - if (thd->proc_info) { - *buf = ' '; - buf++; - buf=strnmov(buf, thd->proc_info, 50); + putc(' ', f); + fputs(thd->user, f); } - if (thd->query) { - *buf = '\n'; - buf++; - buf=strnmov(buf, thd->query, 150); - } - - buf[0] = '\n'; - buf[1] = '\0'; /* Note that we must put a null character here to end - the printed string */ + if (thd->proc_info) { + putc(' ', f); + fputs(thd->proc_info, f); + } - /* We test the printed length did not overrun the buffer length of - 400 bytes */ + if (thd->query) { + putc(' ', f); + fputs(thd->query, f); + } - ut_a(strlen(old_buf) < 400); -} + putc('\n', f); } /************************************************************************* @@ -627,12 +609,11 @@ innobase_query_caching_of_table_permitted( return((my_bool)FALSE); } -extern "C" { /********************************************************************* Invalidates the MySQL query cache for the table. NOTE that the exact prototype of this function has to be in /innobase/row/row0ins.c! */ - +extern "C" void innobase_invalidate_query_cache( /*============================*/ @@ -652,6 +633,17 @@ innobase_invalidate_query_cache( TRUE); #endif } + +/********************************************************************* +Get the quote character to be used in SQL identifiers. */ +extern "C" +char +mysql_get_identifier_quote_char(void) +/*=================================*/ + /* out: quote character to be + used in SQL identifiers */ +{ + return '`'; } /********************************************************************* @@ -2102,24 +2094,20 @@ ha_innobase::write_row( if (prebuilt->trx != (trx_t*) current_thd->transaction.all.innobase_tid) { - char err_buf[2000]; - fprintf(stderr, "InnoDB: Error: the transaction object for the table handle is at\n" -"InnoDB: %lx, but for the current thread it is at %lx\n", - (ulong)prebuilt->trx, - (ulong)current_thd->transaction.all.innobase_tid); - - ut_sprintf_buf(err_buf, ((byte*)prebuilt) - 100, 200); - fprintf(stderr, -"InnoDB: Dump of 200 bytes around prebuilt: %.1000s\n", err_buf); - - ut_sprintf_buf(err_buf, +"InnoDB: %p, but for the current thread it is at %p\n", + prebuilt->trx, + current_thd->transaction.all.innobase_tid); + fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr); + ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200); + fputs("\n" + "InnoDB: Dump of 200 bytes around transaction.all: ", + stderr); + ut_print_buf(stderr, ((byte*)(&(current_thd->transaction.all))) - 100, 200); - fprintf(stderr, -"InnoDB: Dump of 200 bytes around transaction.all: %.1000s\n", err_buf); - - ut_a(0); + putc('\n', stderr); + ut_error; } statistic_increment(ha_write_count, &LOCK_status); @@ -3390,12 +3378,9 @@ create_index( field = form->field[j]; - if (strlen(field->field_name) - == strlen(key_part->field->field_name) - && 0 == ut_cmp_in_lower_case( + if (0 == ut_cmp_in_lower_case( (char*)field->field_name, - (char*)key_part->field->field_name, - strlen(field->field_name))) { + (char*)key_part->field->field_name)) { /* Found the corresponding column */ break; @@ -3762,7 +3747,8 @@ ha_innobase::delete_table( /* Drop the table in InnoDB */ - error = row_drop_table_for_mysql(norm_name, trx); + error = row_drop_table_for_mysql(norm_name, trx, + thd->lex->sql_command == SQLCOM_DROP_DB); /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -3801,7 +3787,7 @@ innobase_drop_database( trx_t* trx; char* ptr; int error; - char namebuf[10000]; + char* namebuf; /* Get the transaction associated with the current thd, or create one if not yet created */ @@ -3821,6 +3807,7 @@ innobase_drop_database( } ptr++; + namebuf = my_malloc(len + 2, MYF(0)); memcpy(namebuf, ptr, len); namebuf[len] = '/'; @@ -3837,6 +3824,7 @@ innobase_drop_database( } error = row_drop_database_for_mysql(namebuf, trx); + my_free(namebuf, MYF(0)); /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -4361,15 +4349,18 @@ ha_innobase::update_table_comment( info on foreign keys */ const char* comment)/* in: table comment defined by user */ { - row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; - uint length = strlen(comment); - char* str = my_malloc(length + 16500, MYF(0)); - char* pos; + uint length = strlen(comment); + char* str; + row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; /* We do not know if MySQL can call this function before calling external_lock(). To be safe, update the thd of the current table handle. */ + if(length > 64000 - 3) { + return((char*)comment); /* string too long */ + } + update_thd(current_thd); prebuilt->trx->op_info = (char*)"returning table comment"; @@ -4378,37 +4369,47 @@ ha_innobase::update_table_comment( possible adaptive hash latch to avoid deadlocks of threads */ trx_search_latch_release_if_reserved(prebuilt->trx); - - if (!str) { - prebuilt->trx->op_info = (char*)""; + str = NULL; - return((char*)comment); - } + if (FILE* file = tmpfile()) { + long flen; - pos = str; - if (length) { - pos=strmov(str, comment); - *pos++=';'; - *pos++=' '; - } + /* output the data to a temporary file */ + fprintf(file, "InnoDB free: %lu kB", + (ulong) fsp_get_available_space_in_free_extents( + prebuilt->table->space)); + + dict_print_info_on_foreign_keys(FALSE, file, prebuilt->table); + flen = ftell(file); + if(length + flen + 3 > 64000) { + flen = 64000 - 3 - length; + } - pos += my_sprintf(pos, - (pos,"InnoDB free: %lu kB", - (ulong) fsp_get_available_space_in_free_extents( - prebuilt->table->space))); + ut_ad(flen > 0); - /* We assume 16000 - length bytes of space to print info; the limit - 16000 bytes is arbitrary, and MySQL could handle at least 64000 - bytes */ - - if (length < 16000) { - dict_print_info_on_foreign_keys(FALSE, pos, 16000 - length, - prebuilt->table); + /* allocate buffer for the full string, and + read the contents of the temporary file */ + + str = my_malloc(length + flen + 3, MYF(0)); + + if (str) { + char* pos = str + length; + if(length) { + memcpy(str, comment, length); + *pos++ = ';'; + *pos++ = ' '; + } + rewind(file); + flen = fread(pos, 1, flen, file); + pos[flen] = 0; + } + + fclose(file); } prebuilt->trx->op_info = (char*)""; - return(str); + return(str ? str : (char*) comment); } /*********************************************************************** @@ -4422,7 +4423,7 @@ ha_innobase::get_foreign_key_create_info(void) MUST be freed with ::free_foreign_key_create_info */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; - char* str; + char* str = 0; ut_a(prebuilt != NULL); @@ -4432,23 +4433,47 @@ ha_innobase::get_foreign_key_create_info(void) update_thd(current_thd); - prebuilt->trx->op_info = (char*)"getting info on foreign keys"; + if (FILE* file = tmpfile()) { + long flen; - /* In case MySQL calls this in the middle of a SELECT query, release - possible adaptive hash latch to avoid deadlocks of threads */ + prebuilt->trx->op_info = (char*)"getting info on foreign keys"; - trx_search_latch_release_if_reserved(prebuilt->trx); - - str = (char*)ut_malloc(10000); + /* In case MySQL calls this in the middle of a SELECT query, + release possible adaptive hash latch to avoid + deadlocks of threads */ - str[0] = '\0'; - - dict_print_info_on_foreign_keys(TRUE, str, 9000, prebuilt->table); + trx_search_latch_release_if_reserved(prebuilt->trx); - prebuilt->trx->op_info = (char*)""; + /* output the data to a temporary file */ + dict_print_info_on_foreign_keys(TRUE, file, prebuilt->table); + prebuilt->trx->op_info = (char*)""; + + flen = ftell(file); + if(flen > 64000 - 1) { + flen = 64000 - 1; + } + + ut_ad(flen >= 0); + + /* allocate buffer for the string, and + read the contents of the temporary file */ + + str = my_malloc(flen + 1, MYF(0)); + + if (str) { + rewind(file); + flen = fread(str, 1, flen, file); + str[flen] = 0; + } + + fclose(file); + } else { + /* unable to create temporary file */ + str = my_malloc(1, MYF(MY_ZEROFILL)); + } return(str); -} +} /*********************************************************************** Checks if a table is referenced by a foreign key. The MySQL manual states that @@ -4481,7 +4506,7 @@ ha_innobase::free_foreign_key_create_info( char* str) /* in, own: create info string to free */ { if (str) { - ut_free(str); + my_free(str, MYF(0)); } } @@ -4772,34 +4797,55 @@ innodb_show_status( innobase_release_stat_resources(trx); - /* We let the InnoDB Monitor to output at most 60 kB of text, add - a safety margin of 100 kB for buffer overruns */ + /* We let the InnoDB Monitor to output at most 64000 bytes of text. */ - buf = (char*)ut_malloc(160 * 1024); + long flen; + char* str; - srv_sprintf_innodb_monitor(buf, 60 * 1024); + mutex_enter_noninline(&srv_monitor_file_mutex); + rewind(srv_monitor_file); + srv_printf_innodb_monitor(srv_monitor_file); + flen = ftell(srv_monitor_file); + if(flen > 64000 - 1) { + flen = 64000 - 1; + } - List<Item> field_list; + ut_ad(flen > 0); - field_list.push_back(new Item_empty_string("Status", strlen(buf))); + /* allocate buffer for the string, and + read the contents of the temporary file */ - if (protocol->send_fields(&field_list, 1)) + if (!(str = my_malloc(flen + 1, MYF(0)))) { - ut_free(buf); - DBUG_RETURN(-1); + mutex_exit_noninline(&srv_monitor_file_mutex); + DBUG_RETURN(-1); } - protocol->prepare_for_resend(); - protocol->store(buf, strlen(buf), system_charset_info); + rewind(srv_monitor_file); + flen = fread(str, 1, flen, srv_monitor_file); + + mutex_exit_noninline(&srv_monitor_file_mutex); + + List<Item> field_list; - ut_free(buf); + field_list.push_back(new Item_empty_string("Status", flen)); + + if (protocol->send_fields(&field_list, 1)) { + + my_free(str, MYF(0)); + + DBUG_RETURN(-1); + } + + protocol->prepare_for_resend(); + protocol->store(str, flen, system_charset_info); + my_free(str, MYF(0)); if (protocol->write()) DBUG_RETURN(-1); - send_eof(thd); - - DBUG_RETURN(0); + send_eof(thd); + DBUG_RETURN(0); } /**************************************************************************** diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index e5f1c66e23a..83a3edc4126 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -123,6 +123,8 @@ class ha_innobase: public handler whose size is > MAX_KEY_LENGTH */ uint max_key_length() const { return((MAX_KEY_LENGTH <= 3500) ? MAX_KEY_LENGTH : 3500);} + uint max_key_part_length() { return((MAX_KEY_LENGTH <= 3500) ? + MAX_KEY_LENGTH : 3500);} const key_map *keys_to_use_for_scanning() { return &key_map_full; } bool has_transactions() { return 1;} diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc new file mode 100644 index 00000000000..3bc322878d1 --- /dev/null +++ b/sql/ha_ndbcluster.cc @@ -0,0 +1,2943 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + This file defines the NDB Cluster handler: the interface between MySQL and + NDB Cluster +*/ + +/* + TODO + After CREATE DATABASE gör discover på alla tabeller i den databasen + +*/ + + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +#include "mysql_priv.h" + +#ifdef HAVE_NDBCLUSTER_DB +#include <my_dir.h> +#include "ha_ndbcluster.h" +#include <ndbapi/NdbApi.hpp> +#include <ndbapi/NdbScanFilter.hpp> + +#define USE_DISCOVER_ON_STARTUP +//#define USE_NDB_POOL + +// Default value for parallelism +static const int parallelism= 240; + +#define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8 + +#define ERR_PRINT(err) \ + DBUG_PRINT("error", ("Error: %d message: %s", err.code, err.message)) + +#define ERR_RETURN(err) \ +{ \ + ERR_PRINT(err); \ + DBUG_RETURN(ndb_to_mysql_error(&err)); \ +} + +// Typedefs for long names +typedef NdbDictionary::Column NDBCOL; +typedef NdbDictionary::Table NDBTAB; +typedef NdbDictionary::Index NDBINDEX; +typedef NdbDictionary::Dictionary NDBDICT; + +bool ndbcluster_inited= false; + +// Handler synchronization +pthread_mutex_t ndbcluster_mutex; + +// Table lock handling +static HASH ndbcluster_open_tables; + +static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length, + my_bool not_used __attribute__((unused))); +static NDB_SHARE *get_share(const char *table_name); +static void free_share(NDB_SHARE *share); + +static int packfrm(const void *data, uint len, const void **pack_data, uint *pack_len); +static int unpackfrm(const void **data, uint *len, + const void* pack_data); + +/* + Error handling functions +*/ + +struct err_code_mapping +{ + int ndb_err; + int my_err; +}; + +static const err_code_mapping err_map[]= +{ + { 626, HA_ERR_KEY_NOT_FOUND }, + { 630, HA_ERR_FOUND_DUPP_KEY }, + { 893, HA_ERR_FOUND_DUPP_UNIQUE }, + { 721, HA_ERR_TABLE_EXIST }, + { 241, HA_ERR_OLD_METADATA }, + { -1, -1 } +}; + + +static int ndb_to_mysql_error(const NdbError *err) +{ + uint i; + for (i=0 ; err_map[i].ndb_err != err->code ; i++) + { + if (err_map[i].my_err == -1) + return err->code; + } + return err_map[i].my_err; +} + + +/* + Take care of the error that occured in NDB + + RETURN + 0 No error + # The mapped error code +*/ + +int ha_ndbcluster::ndb_err(NdbConnection *trans) +{ + const NdbError err= trans->getNdbError(); + if (!err.code) + return 0; // Don't log things to DBUG log if no error + DBUG_ENTER("ndb_err"); + + ERR_PRINT(err); + switch (err.classification) { + case NdbError::SchemaError: + { + NDBDICT *dict= m_ndb->getDictionary(); + DBUG_PRINT("info", ("invalidateTable %s", m_tabname)); + dict->invalidateTable(m_tabname); + break; + } + default: + break; + } + DBUG_RETURN(ndb_to_mysql_error(&err)); +} + + +/* + Instruct NDB to set the value of the hidden primary key +*/ + +bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op, + uint fieldnr, const byte *field_ptr) +{ + DBUG_ENTER("set_hidden_key"); + DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr, + NDB_HIDDEN_PRIMARY_KEY_LENGTH) != 0); +} + + +/* + Instruct NDB to set the value of one primary key attribute +*/ + +int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, + uint fieldnr, const byte *field_ptr) +{ + uint32 pack_len= field->pack_length(); + DBUG_ENTER("set_ndb_key"); + DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d", + fieldnr, field->field_name, field->type(), + pack_len)); + DBUG_DUMP("key", (char*)field_ptr, pack_len); + + switch (field->type()) { + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + // Common implementation for most field types + DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0); + + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_GEOMETRY: + default: + // Unhandled field types + DBUG_PRINT("error", ("Field type %d not supported", field->type())); + DBUG_RETURN(2); + } + DBUG_RETURN(3); +} + + +/* + Instruct NDB to set the value of one attribute +*/ + +int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, + uint fieldnr) +{ + const byte* field_ptr= field->ptr; + uint32 pack_len= field->pack_length(); + DBUG_ENTER("set_ndb_value"); + DBUG_PRINT("enter", ("%d: %s, type: %u, len=%d, is_null=%s", + fieldnr, field->field_name, field->type(), + pack_len, field->is_null()?"Y":"N")); + DBUG_DUMP("value", (char*) field_ptr, pack_len); + + if (field->is_null()) + { + // Set value to NULL + DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL, pack_len) != 0)); + } + + switch (field->type()) { + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + // Common implementation for most field types + DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)field_ptr, pack_len) != 0); + + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_GEOMETRY: + default: + // Unhandled field types + DBUG_PRINT("error", ("Field type %d not supported", field->type())); + DBUG_RETURN(2); + } + DBUG_RETURN(3); +} + + +/* + Instruct NDB to fetch one field + - data is read directly into buffer provided by field_ptr + if it's NULL, data is read into memory provided by NDBAPI +*/ + +int ha_ndbcluster::get_ndb_value(NdbOperation *op, + uint field_no, byte *field_ptr) +{ + DBUG_ENTER("get_ndb_value"); + DBUG_PRINT("enter", ("field_no: %d", field_no)); + m_value[field_no]= op->getValue(field_no, field_ptr); + DBUG_RETURN(m_value == NULL); +} + + +/* + Get metadata for this table from NDB + + IMPLEMENTATION + - save the NdbDictionary::Table for easy access + - check that frm-file on disk is equal to frm-file + of table accessed in NDB + - build a list of the indexes for the table +*/ + +int ha_ndbcluster::get_metadata(const char *path) +{ + NDBDICT *dict= m_ndb->getDictionary(); + const NDBTAB *tab; + const void *data, *pack_data; + const char **key_name; + uint ndb_columns, mysql_columns, length, pack_length, i; + int error; + DBUG_ENTER("get_metadata"); + DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path)); + + if (!(tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); + + /* + This is the place to check that the table we got from NDB + is equal to the one on local disk + */ + ndb_columns= (uint) tab->getNoOfColumns(); + mysql_columns= table->fields; + if (table->primary_key == MAX_KEY) + ndb_columns--; + if (ndb_columns != mysql_columns) + { + DBUG_PRINT("error", + ("Wrong number of columns, ndb: %d mysql: %d", + ndb_columns, mysql_columns)); + DBUG_RETURN(HA_ERR_OLD_METADATA); + } + + /* + Compare FrmData in NDB with frm file from disk. + */ + error= 0; + if (readfrm(path, &data, &length) || + packfrm(data, length, &pack_data, &pack_length)) + { + my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR)); + DBUG_RETURN(1); + } + + if ((pack_length != tab->getFrmLength()) || + (memcmp(pack_data, tab->getFrmData(), pack_length))) + { + DBUG_PRINT("error", + ("metadata, pack_length: %d getFrmLength: %d memcmp: %d", + pack_length, tab->getFrmLength(), + memcmp(pack_data, tab->getFrmData(), pack_length))); + DBUG_DUMP("pack_data", (char*)pack_data, pack_length); + DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength()); + error= HA_ERR_OLD_METADATA; + } + my_free((char*)data, MYF(0)); + my_free((char*)pack_data, MYF(0)); + if (error) + DBUG_RETURN(error); + + // All checks OK, lets use the table + m_table= (void*)tab; + + for (i= 0; i < MAX_KEY; i++) + m_indextype[i]= UNDEFINED_INDEX; + + // Save information about all known indexes + for (i= 0; i < table->keys; i++) + m_indextype[i] = get_index_type_from_table(i); + + DBUG_RETURN(0); +} + +/* + Decode the type of an index from information + provided in table object +*/ +NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_table(uint index_no) const +{ + if (index_no == table->primary_key) + return PRIMARY_KEY_INDEX; + else + return ((table->key_info[index_no].flags & HA_NOSAME) ? + UNIQUE_INDEX : + ORDERED_INDEX); +} + + +void ha_ndbcluster::release_metadata() +{ + DBUG_ENTER("release_metadata"); + DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); + + m_table= NULL; + + DBUG_VOID_RETURN; +} + +static const ulong index_type_flags[]= +{ + /* UNDEFINED_INDEX */ + 0, + + /* PRIMARY_KEY_INDEX */ + HA_ONLY_WHOLE_INDEX | + HA_WRONG_ASCII_ORDER | + HA_NOT_READ_PREFIX_LAST, + + /* UNIQUE_INDEX */ + HA_ONLY_WHOLE_INDEX | + HA_WRONG_ASCII_ORDER | + HA_NOT_READ_PREFIX_LAST, + + /* ORDERED_INDEX */ + HA_READ_NEXT | + HA_READ_PREV | + HA_NOT_READ_AFTER_KEY +}; + +static const int index_flags_size= sizeof(index_type_flags)/sizeof(ulong); + +inline const char* ha_ndbcluster::get_index_name(uint idx_no) const +{ + return table->keynames.type_names[idx_no]; +} + +inline NDB_INDEX_TYPE ha_ndbcluster::get_index_type(uint idx_no) const +{ + DBUG_ASSERT(idx_no < MAX_KEY); + return m_indextype[idx_no]; +} + + +/* + Get the flags for an index + + RETURN + flags depending on the type of the index. +*/ + +inline ulong ha_ndbcluster::index_flags(uint idx_no) const +{ + DBUG_ENTER("index_flags"); + DBUG_ASSERT(get_index_type_from_table(idx_no) < index_flags_size); + DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)]); +} + + +int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key) +{ + KEY* key_info= table->key_info + table->primary_key; + KEY_PART_INFO* key_part= key_info->key_part; + KEY_PART_INFO* end= key_part+key_info->key_parts; + DBUG_ENTER("set_primary_key"); + + for (; key_part != end; key_part++) + { + Field* field= key_part->field; + if (set_ndb_key(op, field, + key_part->fieldnr-1, key)) + ERR_RETURN(op->getNdbError()); + key += key_part->length; + } + DBUG_RETURN(0); +} + + +int ha_ndbcluster::set_primary_key(NdbOperation *op) +{ + DBUG_ENTER("set_primary_key"); + KEY* key_info= table->key_info + table->primary_key; + KEY_PART_INFO* key_part= key_info->key_part; + KEY_PART_INFO* end= key_part+key_info->key_parts; + + for (; key_part != end; key_part++) + { + Field* field= key_part->field; + if (set_ndb_key(op, field, + key_part->fieldnr-1, field->ptr)) + ERR_RETURN(op->getNdbError()); + } + DBUG_RETURN(0); +} + + +/* + Read one record from NDB using primary key +*/ + +int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) +{ + uint no_fields= table->fields, i; + NdbConnection *trans= m_active_trans; + NdbOperation *op; + THD *thd= current_thd; + DBUG_ENTER("pk_read"); + DBUG_PRINT("enter", ("key_len: %u", key_len)); + DBUG_DUMP("key", (char*)key, key_len); + + if (!(op= trans->getNdbOperation(m_tabname)) || op->readTuple() != 0) + goto err; + + if (table->primary_key == MAX_KEY) + { + // This table has no primary key, use "hidden" primary key + DBUG_PRINT("info", ("Using hidden key")); + DBUG_DUMP("key", (char*)key, 8); + if (set_hidden_key(op, no_fields, key)) + goto err; + // Read key at the same time, for future reference + if (get_ndb_value(op, no_fields, NULL)) + goto err; + } + else + { + int res; + if ((res= set_primary_key(op, key))) + return res; + } + + // Read non-key field(s) + for (i= 0; i < no_fields; i++) + { + Field *field= table->field[i]; + if (thd->query_id == field->query_id) + { + if (get_ndb_value(op, i, field->ptr)) + goto err; + } + else + { + // Attribute was not to be read + m_value[i]= NULL; + } + } + + if (trans->execute(NoCommit, IgnoreError) != 0) + { + table->status= STATUS_NOT_FOUND; + DBUG_RETURN(ndb_err(trans)); + } + + // The value have now been fetched from NDB + unpack_record(buf); + table->status= 0; + DBUG_RETURN(0); + + err: + ERR_RETURN(trans->getNdbError()); +} + + +/* + Read one record from NDB using unique secondary index +*/ + +int ha_ndbcluster::unique_index_read(const byte *key, + uint key_len, byte *buf) +{ + NdbConnection *trans= m_active_trans; + const char *index_name; + NdbIndexOperation *op; + THD *thd= current_thd; + byte *key_ptr; + KEY* key_info; + KEY_PART_INFO *key_part, *end; + uint i; + DBUG_ENTER("unique_index_read"); + DBUG_PRINT("enter", ("key_len: %u, index: %u", key_len, active_index)); + DBUG_DUMP("key", (char*)key, key_len); + + index_name= get_index_name(active_index); + if (!(op= trans->getNdbIndexOperation(index_name, m_tabname)) || + op->readTuple() != 0) + ERR_RETURN(trans->getNdbError()); + + // Set secondary index key(s) + key_ptr= (byte *) key; + key_info= table->key_info + active_index; + DBUG_ASSERT(key_info->key_length == key_len); + end= (key_part= key_info->key_part) + key_info->key_parts; + + for (i= 0; key_part != end; key_part++, i++) + { + if (set_ndb_key(op, key_part->field, i, key_ptr)) + ERR_RETURN(trans->getNdbError()); + key_ptr+= key_part->length; + } + + // Get non-index attribute(s) + for (i= 0; i < table->fields; i++) + { + Field *field= table->field[i]; + if ((thd->query_id == field->query_id) || + (field->flags & PRI_KEY_FLAG)) + { + if (get_ndb_value(op, i, field->ptr)) + ERR_RETURN(op->getNdbError()); + } + else + { + // Attribute was not to be read + m_value[i]= NULL; + } + } + + if (trans->execute(NoCommit, IgnoreError) != 0) + { + table->status= STATUS_NOT_FOUND; + DBUG_RETURN(ndb_err(trans)); + } + // The value have now been fetched from NDB + unpack_record(buf); + table->status= 0; + DBUG_RETURN(0); +} + +/* + Get the next record of a started scan +*/ + +inline int ha_ndbcluster::next_result(byte *buf) +{ + NdbConnection *trans= m_active_trans; + NdbResultSet *cursor= m_active_cursor; + DBUG_ENTER("next_result"); + + if (cursor->nextResult() == 0) + { + // One more record found + unpack_record(buf); + table->status= 0; + DBUG_RETURN(0); + } + table->status= STATUS_NOT_FOUND; + if (ndb_err(trans)) + ERR_RETURN(trans->getNdbError()); + + // No more records + DBUG_PRINT("info", ("No more records")); + DBUG_RETURN(HA_ERR_END_OF_FILE); +} + + +/* + Read record(s) from NDB using ordered index scan +*/ + +int ha_ndbcluster::ordered_index_scan(const byte *key, uint key_len, + byte *buf, + enum ha_rkey_function find_flag) +{ + uint no_fields= table->fields; + uint tot_len, i; + NdbConnection *trans= m_active_trans; + NdbResultSet *cursor= m_active_cursor; + NdbScanOperation *op; + const char *bound_str= NULL; + const char *index_name; + NdbOperation::BoundType bound_type = NdbOperation::BoundEQ; + bool can_be_handled_by_ndb= FALSE; + byte *key_ptr; + KEY *key_info; + THD* thd = current_thd; + DBUG_ENTER("ordered_index_scan"); + DBUG_PRINT("enter", ("index: %u", active_index)); + DBUG_PRINT("enter", ("Starting new ordered scan on %s", m_tabname)); + + index_name= get_index_name(active_index); + if (!(op= trans->getNdbScanOperation(index_name, m_tabname))) + ERR_RETURN(trans->getNdbError()); + if (!(cursor= op->readTuples(parallelism))) + ERR_RETURN(trans->getNdbError()); + m_active_cursor= cursor; + + switch (find_flag) { + case HA_READ_KEY_EXACT: /* Find first record else error */ + bound_str= "HA_READ_KEY_EXACT"; + bound_type= NdbOperation::BoundEQ; + can_be_handled_by_ndb= TRUE; + break; + case HA_READ_KEY_OR_NEXT: /* Record or next record */ + bound_str= "HA_READ_KEY_OR_NEXT"; + bound_type= NdbOperation::BoundLE; + can_be_handled_by_ndb= TRUE; + break; + case HA_READ_KEY_OR_PREV: /* Record or previous */ + bound_str= "HA_READ_KEY_OR_PREV"; + bound_type= NdbOperation::BoundGE; + can_be_handled_by_ndb= TRUE; + break; + case HA_READ_AFTER_KEY: /* Find next rec. after key-record */ + bound_str= "HA_READ_AFTER_KEY"; + bound_type= NdbOperation::BoundLT; + can_be_handled_by_ndb= TRUE; + break; + case HA_READ_BEFORE_KEY: /* Find next rec. before key-record */ + bound_str= "HA_READ_BEFORE_KEY"; + bound_type= NdbOperation::BoundGT; + can_be_handled_by_ndb= TRUE; + break; + case HA_READ_PREFIX: /* Key which as same prefix */ + bound_str= "HA_READ_PREFIX"; + break; + case HA_READ_PREFIX_LAST: /* Last key with the same prefix */ + bound_str= "HA_READ_PREFIX_LAST"; + break; + case HA_READ_PREFIX_LAST_OR_PREV: + /* Last or prev key with the same prefix */ + bound_str= "HA_READ_PREFIX_LAST_OR_PREV"; + break; + default: + bound_str= "UNKNOWN"; + break; + } + DBUG_PRINT("info", ("find_flag: %s, bound_type: %d," + "can_be_handled_by_ndb: %d", + bound_str, bound_type, can_be_handled_by_ndb)); + if (!can_be_handled_by_ndb) + DBUG_RETURN(1); + + // Set bounds using key data + tot_len= 0; + key_ptr= (byte *) key; + key_info= table->key_info + active_index; + for (i= 0; i < key_info->key_parts; i++) + { + Field* field= key_info->key_part[i].field; + uint32 field_len= field->pack_length(); + DBUG_PRINT("info", ("Set index bound on %s", + field->field_name)); + DBUG_DUMP("key", (char*)key_ptr, field_len); + + if (op->setBound(field->field_name, + bound_type, + key_ptr, + field_len) != 0) + ERR_RETURN(op->getNdbError()); + + key_ptr+= field_len; + tot_len+= field_len; + if (tot_len >= key_len) + break; + } + + // Define attributes to read + for (i= 0; i < no_fields; i++) + { + Field *field= table->field[i]; + if ((thd->query_id == field->query_id) || + (field->flags & PRI_KEY_FLAG)) + { + if (get_ndb_value(op, i, field->ptr)) + ERR_RETURN(op->getNdbError()); + } + else + { + m_value[i]= NULL; + } + } + + if (table->primary_key == MAX_KEY) + { + DBUG_PRINT("info", ("Getting hidden key")); + // Scanning table with no primary key + int hidden_no= no_fields; +#ifndef DBUG_OFF + const NDBTAB *tab= (NDBTAB *) m_table; + if (!tab->getColumn(hidden_no)) + DBUG_RETURN(1); +#endif + if (get_ndb_value(op, hidden_no, NULL)) + ERR_RETURN(op->getNdbError()); + } + + if (trans->execute(NoCommit) != 0) + DBUG_RETURN(ndb_err(trans)); + DBUG_PRINT("exit", ("Scan started successfully")); + DBUG_RETURN(next_result(buf)); +} + + +#if 0 +/* + Read record(s) from NDB using full table scan with filter + */ + +int ha_ndbcluster::filtered_scan(const byte *key, uint key_len, + byte *buf, + enum ha_rkey_function find_flag) +{ + uint no_fields= table->fields; + NdbConnection *trans= m_active_trans; + NdbResultSet *cursor= m_active_cursor; + + DBUG_ENTER("filtered_scan"); + DBUG_PRINT("enter", ("key_len: %u, index: %u", + key_len, active_index)); + DBUG_DUMP("key", (char*)key, key_len); + DBUG_PRINT("info", ("Starting a new filtered scan on %s", + m_tabname)); + NdbScanOperation *op= trans->getNdbScanOperation(m_tabname); + if (!op) + ERR_RETURN(trans->getNdbError()); + + cursor= op->readTuples(parallelism); + if (!cursor) + ERR_RETURN(trans->getNdbError()); + m_active_cursor= cursor; + + { + // Start scan filter + NdbScanFilter sf(op); + sf.begin(); + + // Set filter using the supplied key data + byte *key_ptr= (byte *) key; + uint tot_len= 0; + KEY* key_info= table->key_info + active_index; + for (uint k= 0; k < key_info->key_parts; k++) + { + KEY_PART_INFO* key_part= key_info->key_part+k; + Field* field= key_part->field; + uint ndb_fieldnr= key_part->fieldnr-1; + DBUG_PRINT("key_part", ("fieldnr: %d", ndb_fieldnr)); + // const NDBCOL *col= tab->getColumn(ndb_fieldnr); + uint32 field_len= field->pack_length(); + DBUG_DUMP("key", (char*)key, field_len); + + DBUG_PRINT("info", ("Column %s, type: %d, len: %d", + field->field_name, field->real_type(), field_len)); + + // Define scan filter + if (field->real_type() == MYSQL_TYPE_STRING) + sf.eq(ndb_fieldnr, key_ptr, field_len); + else + { + if (field_len == 8) + sf.eq(ndb_fieldnr, (Uint64)*key_ptr); + else if (field_len <= 4) + sf.eq(ndb_fieldnr, (Uint32)*key_ptr); + else + DBUG_RETURN(1); + } + + key_ptr += field_len; + tot_len += field_len; + + if (tot_len >= key_len) + break; + } + // End scan filter + sf.end(); + } + + // Define attributes to read + for (uint field_no= 0; field_no < no_fields; field_no++) + { + Field *field= table->field[field_no]; + + // Read attribute + DBUG_PRINT("get", ("%d: %s", field_no, field->field_name)); + if (get_ndb_value(op, field_no, field->ptr)) + ERR_RETURN(op->getNdbError()); + } + + if (table->primary_key == MAX_KEY) + { + DBUG_PRINT("info", ("Getting hidden key")); + // Scanning table with no primary key + int hidden_no= no_fields; +#ifndef DBUG_OFF + const NDBTAB *tab= (NDBTAB *) m_table; + if (!tab->getColumn(hidden_no)) + DBUG_RETURN(1); +#endif + if (get_ndb_value(op, hidden_no, NULL)) + ERR_RETURN(op->getNdbError()); + } + + if (trans->execute(NoCommit) != 0) + DBUG_RETURN(ndb_err(trans)); + DBUG_PRINT("exit", ("Scan started successfully")); + DBUG_RETURN(next_result(buf)); +} +#endif + + +/* + Read records from NDB using full table scan + */ + +int ha_ndbcluster::full_table_scan(byte *buf) +{ + uint i; + THD *thd= current_thd; + NdbConnection *trans= m_active_trans; + NdbResultSet *cursor; + NdbScanOperation *op; + + DBUG_ENTER("full_table_scan"); + DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); + + if (!(op=trans->getNdbScanOperation(m_tabname))) + ERR_RETURN(trans->getNdbError()); + if (!(cursor= op->readTuples(parallelism))) + ERR_RETURN(trans->getNdbError()); + m_active_cursor= cursor; + + // Define attributes to read + for (i= 0; i < table->fields; i++) + { + Field *field= table->field[i]; + if ((thd->query_id == field->query_id) || + (field->flags & PRI_KEY_FLAG)) + { + if (get_ndb_value(op, i, field->ptr)) + ERR_RETURN(op->getNdbError()); + } + else + { + m_value[i]= NULL; + } + } + + if (table->primary_key == MAX_KEY) + { + DBUG_PRINT("info", ("Getting hidden key")); + // Scanning table with no primary key + int hidden_no= table->fields; +#ifndef DBUG_OFF + const NDBTAB *tab= (NDBTAB *) m_table; + if (!tab->getColumn(hidden_no)) + DBUG_RETURN(1); +#endif + if (get_ndb_value(op, hidden_no, NULL)) + ERR_RETURN(op->getNdbError()); + } + + if (trans->execute(NoCommit) != 0) + DBUG_RETURN(ndb_err(trans)); + DBUG_PRINT("exit", ("Scan started successfully")); + DBUG_RETURN(next_result(buf)); +} + + +/* + Insert one record into NDB +*/ + +int ha_ndbcluster::write_row(byte *record) +{ + uint i; + NdbConnection *trans= m_active_trans; + NdbOperation *op; + int res; + DBUG_ENTER("write_row"); + + statistic_increment(ha_write_count,&LOCK_status); + if (table->timestamp_default_now) + update_timestamp(record+table->timestamp_default_now-1); + if (table->next_number_field && record == table->record[0]) + update_auto_increment(); + + if (!(op= trans->getNdbOperation(m_tabname))) + ERR_RETURN(trans->getNdbError()); + + res= (m_use_write) ? op->writeTuple() :op->insertTuple(); + if (res != 0) + ERR_RETURN(trans->getNdbError()); + + if (table->primary_key == MAX_KEY) + { + // Table has hidden primary key + Uint64 auto_value= m_ndb->getAutoIncrementValue(m_tabname); + if (set_hidden_key(op, table->fields, (const byte*)&auto_value)) + ERR_RETURN(op->getNdbError()); + } + else + { + int res; + if ((res= set_primary_key(op))) + return res; + } + + // Set non-key attribute(s) + for (i= 0; i < table->fields; i++) + { + Field *field= table->field[i]; + if (!(field->flags & PRI_KEY_FLAG) && + set_ndb_value(op, field, i)) + ERR_RETURN(op->getNdbError()); + } + + /* + Execute write operation + NOTE When doing inserts with many values in + each INSERT statement it should not be necessary + to NoCommit the transaction between each row. + Find out how this is detected! + */ + if (trans->execute(NoCommit) != 0) + DBUG_RETURN(ndb_err(trans)); + DBUG_RETURN(0); +} + + +/* Compare if a key in a row has changed */ + +int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row, + const byte * new_row) +{ + KEY_PART_INFO *key_part=table->key_info[keynr].key_part; + KEY_PART_INFO *end=key_part+table->key_info[keynr].key_parts; + + for (; key_part != end ; key_part++) + { + if (key_part->null_bit) + { + if ((old_row[key_part->null_offset] & key_part->null_bit) != + (new_row[key_part->null_offset] & key_part->null_bit)) + return 1; + } + if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH)) + { + + if (key_part->field->cmp_binary((char*) (old_row + key_part->offset), + (char*) (new_row + key_part->offset), + (ulong) key_part->length)) + return 1; + } + else + { + if (memcmp(old_row+key_part->offset, new_row+key_part->offset, + key_part->length)) + return 1; + } + } + return 0; +} + +/* + Update one record in NDB using primary key +*/ + +int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) +{ + THD *thd= current_thd; + NdbConnection *trans= m_active_trans; + NdbOperation *op; + uint i; + DBUG_ENTER("update_row"); + + statistic_increment(ha_update_count,&LOCK_status); + if (table->timestamp_on_update_now) + update_timestamp(new_data+table->timestamp_on_update_now-1); + + if (!(op= trans->getNdbOperation(m_tabname)) || + op->updateTuple() != 0) + ERR_RETURN(trans->getNdbError()); + + if (table->primary_key == MAX_KEY) + { + // This table has no primary key, use "hidden" primary key + DBUG_PRINT("info", ("Using hidden key")); + + // Require that the PK for this record has previously been + // read into m_value + uint no_fields= table->fields; + NdbRecAttr* rec= m_value[no_fields]; + DBUG_ASSERT(rec); + DBUG_DUMP("key", (char*)rec->aRef(), NDB_HIDDEN_PRIMARY_KEY_LENGTH); + + if (set_hidden_key(op, no_fields, rec->aRef())) + ERR_RETURN(op->getNdbError()); + } + else + { + /* Check for update of primary key and return error */ + if (key_cmp(table->primary_key, old_data, new_data)) + DBUG_RETURN(HA_ERR_UNSUPPORTED); + + int res; + if ((res= set_primary_key(op, old_data + table->null_bytes))) + DBUG_RETURN(res); + } + + // Set non-key attribute(s) + for (i= 0; i < table->fields; i++) + { + + Field *field= table->field[i]; + if ((thd->query_id == field->query_id) && + (!(field->flags & PRI_KEY_FLAG)) && + set_ndb_value(op, field, i)) + ERR_RETURN(op->getNdbError()); + } + + // Execute update operation + if (trans->execute(NoCommit) != 0) + DBUG_RETURN(ndb_err(trans)); + + DBUG_RETURN(0); +} + + +/* + Delete one record from NDB, using primary key +*/ + +int ha_ndbcluster::delete_row(const byte *record) +{ + NdbConnection *trans= m_active_trans; + NdbOperation *op; + DBUG_ENTER("delete_row"); + + statistic_increment(ha_delete_count,&LOCK_status); + + if (!(op=trans->getNdbOperation(m_tabname)) || + op->deleteTuple() != 0) + ERR_RETURN(trans->getNdbError()); + + if (table->primary_key == MAX_KEY) + { + // This table has no primary key, use "hidden" primary key + DBUG_PRINT("info", ("Using hidden key")); + uint no_fields= table->fields; + NdbRecAttr* rec= m_value[no_fields]; + DBUG_ASSERT(rec != NULL); + + if (set_hidden_key(op, no_fields, rec->aRef())) + ERR_RETURN(op->getNdbError()); + } + else + { + int res; + if ((res= set_primary_key(op))) + return res; + } + + // Execute delete operation + if (trans->execute(NoCommit) != 0) + DBUG_RETURN(ndb_err(trans)); + DBUG_RETURN(0); +} + +/* + Unpack a record read from NDB + + SYNOPSIS + unpack_record() + buf Buffer to store read row + + NOTE + The data for each row is read directly into the + destination buffer. This function is primarily + called in order to check if any fields should be + set to null. +*/ + +void ha_ndbcluster::unpack_record(byte* buf) +{ + uint row_offset= (uint) (buf - table->record[0]); + Field **field, **end; + NdbRecAttr **value= m_value; + DBUG_ENTER("unpack_record"); + + // Set null flag(s) + bzero(buf, table->null_bytes); + for (field= table->field, end= field+table->fields; + field < end; + field++, value++) + { + if (*value && (*value)->isNULL()) + (*field)->set_null(row_offset); + } + +#ifndef DBUG_OFF + // Read and print all values that was fetched + if (table->primary_key == MAX_KEY) + { + // Table with hidden primary key + int hidden_no= table->fields; + const NDBTAB *tab= (NDBTAB *) m_table; + const NDBCOL *hidden_col= tab->getColumn(hidden_no); + NdbRecAttr* rec= m_value[hidden_no]; + DBUG_ASSERT(rec); + DBUG_PRINT("hidden", ("%d: %s \"%llu\"", hidden_no, + hidden_col->getName(), rec->u_64_value())); + } + print_results(); +#endif + DBUG_VOID_RETURN; +} + + +/* + Utility function to print/dump the fetched field + */ + +void ha_ndbcluster::print_results() +{ + const NDBTAB *tab= (NDBTAB*) m_table; + DBUG_ENTER("print_results"); + +#ifndef DBUG_OFF + if (!_db_on_) + DBUG_VOID_RETURN; + + for (uint f=0; f<table->fields;f++) + { + Field *field; + const NDBCOL *col; + NdbRecAttr *value; + + if (!(value= m_value[f])) + { + fprintf(DBUG_FILE, "Field %d was not read\n", f); + continue; + } + field= table->field[f]; + DBUG_DUMP("field->ptr", (char*)field->ptr, field->pack_length()); + col= tab->getColumn(f); + fprintf(DBUG_FILE, "%d: %s\t", f, col->getName()); + + if (value->isNULL()) + { + fprintf(DBUG_FILE, "NULL\n"); + continue; + } + + switch (col->getType()) { + case NdbDictionary::Column::Blob: + case NdbDictionary::Column::Undefined: + fprintf(DBUG_FILE, "Unknown type: %d", col->getType()); + break; + case NdbDictionary::Column::Tinyint: { + char value= *field->ptr; + fprintf(DBUG_FILE, "Tinyint\t%d", value); + break; + } + case NdbDictionary::Column::Tinyunsigned: { + unsigned char value= *field->ptr; + fprintf(DBUG_FILE, "Tinyunsigned\t%u", value); + break; + } + case NdbDictionary::Column::Smallint: { + short value= *field->ptr; + fprintf(DBUG_FILE, "Smallint\t%d", value); + break; + } + case NdbDictionary::Column::Smallunsigned: { + unsigned short value= *field->ptr; + fprintf(DBUG_FILE, "Smallunsigned\t%u", value); + break; + } + case NdbDictionary::Column::Mediumint: { + byte value[3]; + memcpy(value, field->ptr, 3); + fprintf(DBUG_FILE, "Mediumint\t%d,%d,%d", value[0], value[1], value[2]); + break; + } + case NdbDictionary::Column::Mediumunsigned: { + byte value[3]; + memcpy(value, field->ptr, 3); + fprintf(DBUG_FILE, "Mediumunsigned\t%u,%u,%u", value[0], value[1], value[2]); + break; + } + case NdbDictionary::Column::Int: { + fprintf(DBUG_FILE, "Int\t%lld", field->val_int()); + break; + } + case NdbDictionary::Column::Unsigned: { + Uint32 value= (Uint32) *field->ptr; + fprintf(DBUG_FILE, "Unsigned\t%u", value); + break; + } + case NdbDictionary::Column::Bigint: { + Int64 value= (Int64) *field->ptr; + fprintf(DBUG_FILE, "Bigint\t%lld", value); + break; + } + case NdbDictionary::Column::Bigunsigned: { + Uint64 value= (Uint64) *field->ptr; + fprintf(DBUG_FILE, "Bigunsigned\t%llu", value); + break; + } + case NdbDictionary::Column::Float: { + float value= (float) *field->ptr; + fprintf(DBUG_FILE, "Float\t%f", value); + break; + } + case NdbDictionary::Column::Double: { + double value= (double) *field->ptr; + fprintf(DBUG_FILE, "Double\t%f", value); + break; + } + case NdbDictionary::Column::Decimal: { + char *value= field->ptr; + + fprintf(DBUG_FILE, "Decimal\t'%-*s'", field->pack_length(), value); + break; + } + case NdbDictionary::Column::Char:{ + char buf[field->pack_length()+1]; + char *value= (char *) field->ptr; + snprintf(buf, field->pack_length(), "%s", value); + fprintf(DBUG_FILE, "Char\t'%s'", buf); + break; + } + case NdbDictionary::Column::Varchar: + case NdbDictionary::Column::Binary: + case NdbDictionary::Column::Varbinary: { + char *value= (char *) field->ptr; + fprintf(DBUG_FILE, "'%s'", value); + break; + } + case NdbDictionary::Column::Datetime: { + Uint64 value= (Uint64) *field->ptr; + fprintf(DBUG_FILE, "Datetime\t%llu", value); + break; + } + case NdbDictionary::Column::Timespec: { + Uint64 value= (Uint64) *field->ptr; + fprintf(DBUG_FILE, "Timespec\t%llu", value); + break; + } + } + fprintf(DBUG_FILE, "\n"); + + } +#endif + DBUG_VOID_RETURN; +} + + +int ha_ndbcluster::index_init(uint index) +{ + DBUG_ENTER("index_init"); + DBUG_PRINT("enter", ("index: %u", index)); + DBUG_RETURN(handler::index_init(index)); +} + + +int ha_ndbcluster::index_end() +{ + DBUG_ENTER("index_end"); + DBUG_RETURN(rnd_end()); +} + + +int ha_ndbcluster::index_read(byte *buf, + const byte *key, uint key_len, + enum ha_rkey_function find_flag) +{ + DBUG_ENTER("index_read"); + DBUG_PRINT("enter", ("active_index: %u, key_len: %u, find_flag: %d", + active_index, key_len, find_flag)); + + int error= 1; + statistic_increment(ha_read_key_count, &LOCK_status); + + switch (get_index_type(active_index)){ + case PRIMARY_KEY_INDEX: + error= pk_read(key, key_len, buf); + break; + + case UNIQUE_INDEX: + error= unique_index_read(key, key_len, buf); + break; + + case ORDERED_INDEX: + error= ordered_index_scan(key, key_len, buf, find_flag); + break; + + default: + case UNDEFINED_INDEX: + break; + } + DBUG_RETURN(error); +} + + +int ha_ndbcluster::index_read_idx(byte *buf, uint index_no, + const byte *key, uint key_len, + enum ha_rkey_function find_flag) +{ + statistic_increment(ha_read_key_count,&LOCK_status); + DBUG_ENTER("index_read_idx"); + DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len)); + index_init(index_no); + DBUG_RETURN(index_read(buf, key, key_len, find_flag)); +} + + +int ha_ndbcluster::index_next(byte *buf) +{ + DBUG_ENTER("index_next"); + + int error = 1; + statistic_increment(ha_read_next_count,&LOCK_status); + if (get_index_type(active_index) == PRIMARY_KEY_INDEX) + error= HA_ERR_END_OF_FILE; + else + error = next_result(buf); + DBUG_RETURN(error); +} + + +int ha_ndbcluster::index_prev(byte *buf) +{ + DBUG_ENTER("index_prev"); + statistic_increment(ha_read_prev_count,&LOCK_status); + DBUG_RETURN(1); +} + + +int ha_ndbcluster::index_first(byte *buf) +{ + DBUG_ENTER("index_first"); + statistic_increment(ha_read_first_count,&LOCK_status); + DBUG_RETURN(1); +} + + +int ha_ndbcluster::index_last(byte *buf) +{ + DBUG_ENTER("index_last"); + statistic_increment(ha_read_last_count,&LOCK_status); + DBUG_RETURN(1); +} + + +int ha_ndbcluster::rnd_init(bool scan) +{ + NdbResultSet *cursor= m_active_cursor; + DBUG_ENTER("rnd_init"); + DBUG_PRINT("enter", ("scan: %d", scan)); + // Check that cursor is not defined + if (cursor) + DBUG_RETURN(1); + index_init(table->primary_key); + DBUG_RETURN(0); +} + + +int ha_ndbcluster::rnd_end() +{ + NdbResultSet *cursor= m_active_cursor; + DBUG_ENTER("rnd_end"); + + if (cursor) + { + DBUG_PRINT("info", ("Closing the cursor")); + cursor->close(); + m_active_cursor= NULL; + } + DBUG_RETURN(0); +} + + +int ha_ndbcluster::rnd_next(byte *buf) +{ + DBUG_ENTER("rnd_next"); + statistic_increment(ha_read_rnd_next_count, &LOCK_status); + int error = 1; + if (!m_active_cursor) + error = full_table_scan(buf); + else + error = next_result(buf); + DBUG_RETURN(error); +} + + +/* + An "interesting" record has been found and it's pk + retrieved by calling position + Now it's time to read the record from db once + again +*/ + +int ha_ndbcluster::rnd_pos(byte *buf, byte *pos) +{ + DBUG_ENTER("rnd_pos"); + statistic_increment(ha_read_rnd_count,&LOCK_status); + // The primary key for the record is stored in pos + // Perform a pk_read using primary key "index" + DBUG_RETURN(pk_read(pos, ref_length, buf)); +} + + +/* + Store the primary key of this record in ref + variable, so that the row can be retrieved again later + using "reference" in rnd_pos +*/ + +void ha_ndbcluster::position(const byte *record) +{ + KEY *key_info; + KEY_PART_INFO *key_part; + KEY_PART_INFO *end; + byte *buff; + DBUG_ENTER("position"); + + if (table->primary_key != MAX_KEY) + { + key_info= table->key_info + table->primary_key; + key_part= key_info->key_part; + end= key_part + key_info->key_parts; + buff= ref; + + for (; key_part != end; key_part++) + { + if (key_part->null_bit) { + /* Store 0 if the key part is a NULL part */ + if (record[key_part->null_offset] + & key_part->null_bit) { + *buff++= 1; + continue; + } + *buff++= 0; + } + memcpy(buff, record + key_part->offset, key_part->length); + buff += key_part->length; + } + } + else + { + // No primary key, get hidden key + DBUG_PRINT("info", ("Getting hidden key")); + int hidden_no= table->fields; + NdbRecAttr* rec= m_value[hidden_no]; + const NDBTAB *tab= (NDBTAB *) m_table; + const NDBCOL *hidden_col= tab->getColumn(hidden_no); + DBUG_ASSERT(hidden_col->getPrimaryKey() && + hidden_col->getAutoIncrement() && + rec != NULL && + ref_length == NDB_HIDDEN_PRIMARY_KEY_LENGTH); + memcpy(ref, (const void*)rec->aRef(), ref_length); + } + + DBUG_DUMP("ref", (char*)ref, ref_length); + DBUG_VOID_RETURN; +} + + +void ha_ndbcluster::info(uint flag) +{ + DBUG_ENTER("info"); + DBUG_PRINT("enter", ("flag: %d", flag)); + + if (flag & HA_STATUS_POS) + DBUG_PRINT("info", ("HA_STATUS_POS")); + if (flag & HA_STATUS_NO_LOCK) + DBUG_PRINT("info", ("HA_STATUS_NO_LOCK")); + if (flag & HA_STATUS_TIME) + DBUG_PRINT("info", ("HA_STATUS_TIME")); + if (flag & HA_STATUS_CONST) + DBUG_PRINT("info", ("HA_STATUS_CONST")); + if (flag & HA_STATUS_VARIABLE) + DBUG_PRINT("info", ("HA_STATUS_VARIABLE")); + if (flag & HA_STATUS_ERRKEY) + DBUG_PRINT("info", ("HA_STATUS_ERRKEY")); + if (flag & HA_STATUS_AUTO) + DBUG_PRINT("info", ("HA_STATUS_AUTO")); + DBUG_VOID_RETURN; +} + + +int ha_ndbcluster::extra(enum ha_extra_function operation) +{ + DBUG_ENTER("extra"); + switch (operation) { + case HA_EXTRA_NORMAL: /* Optimize for space (def) */ + DBUG_PRINT("info", ("HA_EXTRA_NORMAL")); + break; + case HA_EXTRA_QUICK: /* Optimize for speed */ + DBUG_PRINT("info", ("HA_EXTRA_QUICK")); + break; + case HA_EXTRA_RESET: /* Reset database to after open */ + DBUG_PRINT("info", ("HA_EXTRA_RESET")); + break; + case HA_EXTRA_CACHE: /* Cash record in HA_rrnd() */ + DBUG_PRINT("info", ("HA_EXTRA_CACHE")); + break; + case HA_EXTRA_NO_CACHE: /* End cacheing of records (def) */ + DBUG_PRINT("info", ("HA_EXTRA_NO_CACHE")); + break; + case HA_EXTRA_NO_READCHECK: /* No readcheck on update */ + DBUG_PRINT("info", ("HA_EXTRA_NO_READCHECK")); + break; + case HA_EXTRA_READCHECK: /* Use readcheck (def) */ + DBUG_PRINT("info", ("HA_EXTRA_READCHECK")); + break; + case HA_EXTRA_KEYREAD: /* Read only key to database */ + DBUG_PRINT("info", ("HA_EXTRA_KEYREAD")); + break; + case HA_EXTRA_NO_KEYREAD: /* Normal read of records (def) */ + DBUG_PRINT("info", ("HA_EXTRA_NO_KEYREAD")); + break; + case HA_EXTRA_NO_USER_CHANGE: /* No user is allowed to write */ + DBUG_PRINT("info", ("HA_EXTRA_NO_USER_CHANGE")); + break; + case HA_EXTRA_KEY_CACHE: + DBUG_PRINT("info", ("HA_EXTRA_KEY_CACHE")); + break; + case HA_EXTRA_NO_KEY_CACHE: + DBUG_PRINT("info", ("HA_EXTRA_NO_KEY_CACHE")); + break; + case HA_EXTRA_WAIT_LOCK: /* Wait until file is avalably (def) */ + DBUG_PRINT("info", ("HA_EXTRA_WAIT_LOCK")); + break; + case HA_EXTRA_NO_WAIT_LOCK: /* If file is locked, return quickly */ + DBUG_PRINT("info", ("HA_EXTRA_NO_WAIT_LOCK")); + break; + case HA_EXTRA_WRITE_CACHE: /* Use write cache in ha_write() */ + DBUG_PRINT("info", ("HA_EXTRA_WRITE_CACHE")); + break; + case HA_EXTRA_FLUSH_CACHE: /* flush write_record_cache */ + DBUG_PRINT("info", ("HA_EXTRA_FLUSH_CACHE")); + break; + case HA_EXTRA_NO_KEYS: /* Remove all update of keys */ + DBUG_PRINT("info", ("HA_EXTRA_NO_KEYS")); + break; + case HA_EXTRA_KEYREAD_CHANGE_POS: /* Keyread, but change pos */ + DBUG_PRINT("info", ("HA_EXTRA_KEYREAD_CHANGE_POS")); /* xxxxchk -r must be used */ + break; + case HA_EXTRA_REMEMBER_POS: /* Remember pos for next/prev */ + DBUG_PRINT("info", ("HA_EXTRA_REMEMBER_POS")); + break; + case HA_EXTRA_RESTORE_POS: + DBUG_PRINT("info", ("HA_EXTRA_RESTORE_POS")); + break; + case HA_EXTRA_REINIT_CACHE: /* init cache from current record */ + DBUG_PRINT("info", ("HA_EXTRA_REINIT_CACHE")); + break; + case HA_EXTRA_FORCE_REOPEN: /* Datafile have changed on disk */ + DBUG_PRINT("info", ("HA_EXTRA_FORCE_REOPEN")); + break; + case HA_EXTRA_FLUSH: /* Flush tables to disk */ + DBUG_PRINT("info", ("HA_EXTRA_FLUSH")); + break; + case HA_EXTRA_NO_ROWS: /* Don't write rows */ + DBUG_PRINT("info", ("HA_EXTRA_NO_ROWS")); + break; + case HA_EXTRA_RESET_STATE: /* Reset positions */ + DBUG_PRINT("info", ("HA_EXTRA_RESET_STATE")); + break; + case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ + DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); + + DBUG_PRINT("info", ("Turning ON use of write instead of insert")); + m_use_write= TRUE; + break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY")); + DBUG_PRINT("info", ("Turning OFF use of write instead of insert")); + m_use_write= false; + break; + case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those + where field->query_id is the same as + the current query id */ + DBUG_PRINT("info", ("HA_EXTRA_RETRIEVE_ALL_COLS")); + break; + case HA_EXTRA_PREPARE_FOR_DELETE: + DBUG_PRINT("info", ("HA_EXTRA_PREPARE_FOR_DELETE")); + break; + case HA_EXTRA_PREPARE_FOR_UPDATE: /* Remove read cache if problems */ + DBUG_PRINT("info", ("HA_EXTRA_PREPARE_FOR_UPDATE")); + break; + case HA_EXTRA_PRELOAD_BUFFER_SIZE: + DBUG_PRINT("info", ("HA_EXTRA_PRELOAD_BUFFER_SIZE")); + break; + case HA_EXTRA_RETRIEVE_PRIMARY_KEY: + DBUG_PRINT("info", ("HA_EXTRA_RETRIEVE_PRIMARY_KEY")); + break; + case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: + DBUG_PRINT("info", ("HA_EXTRA_CHANGE_KEY_TO_UNIQUE")); + break; + case HA_EXTRA_CHANGE_KEY_TO_DUP: + DBUG_PRINT("info", ("HA_EXTRA_CHANGE_KEY_TO_DUP")); + break; + + } + + DBUG_RETURN(0); +} + + +int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size) +{ + DBUG_ENTER("extra_opt"); + DBUG_PRINT("enter", ("cache_size: %d", cache_size)); + DBUG_RETURN(extra(operation)); +} + + +int ha_ndbcluster::reset() +{ + DBUG_ENTER("reset"); + // Reset what? + DBUG_RETURN(1); +} + + +const char **ha_ndbcluster::bas_ext() const +{ static const char *ext[1] = { NullS }; return ext; } + + +/* + How many seeks it will take to read through the table + This is to be comparable to the number returned by records_in_range so + that we can decide if we should scan the table or use keys. +*/ + +double ha_ndbcluster::scan_time() +{ + return rows2double(records/3); +} + + +THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, + THR_LOCK_DATA **to, + enum thr_lock_type lock_type) +{ + DBUG_ENTER("store_lock"); + + if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK) + { + + /* If we are not doing a LOCK TABLE, then allow multiple + writers */ + + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && + lock_type <= TL_WRITE) && !thd->in_lock_tables) + lock_type= TL_WRITE_ALLOW_WRITE; + + /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ... + MySQL would use the lock TL_READ_NO_INSERT on t2, and that + would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts + to t2. Convert the lock to a normal read lock to allow + concurrent inserts to t2. */ + + if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) + lock_type= TL_READ; + + m_lock.type=lock_type; + } + *to++= &m_lock; + + DBUG_RETURN(to); +} + +#ifndef DBUG_OFF +#define PRINT_OPTION_FLAGS(t) { \ + if (t->options & OPTION_NOT_AUTOCOMMIT) \ + DBUG_PRINT("thd->options", ("OPTION_NOT_AUTOCOMMIT")); \ + if (t->options & OPTION_BEGIN) \ + DBUG_PRINT("thd->options", ("OPTION_BEGIN")); \ + if (t->options & OPTION_TABLE_LOCK) \ + DBUG_PRINT("thd->options", ("OPTION_TABLE_LOCK")); \ +} +#else +#define PRINT_OPTION_FLAGS(t) +#endif + + +/* + As MySQL will execute an external lock for every new table it uses + we can use this to start the transactions. + If we are in auto_commit mode we just need to start a transaction + for the statement, this will be stored in transaction.stmt. + If not, we have to start a master transaction if there doesn't exist + one from before, this will be stored in transaction.all + + When a table lock is held one transaction will be started which holds + the table lock and for each statement a hupp transaction will be started + */ + +int ha_ndbcluster::external_lock(THD *thd, int lock_type) +{ + int error=0; + NdbConnection* trans= NULL; + + DBUG_ENTER("external_lock"); + DBUG_PRINT("enter", ("transaction.ndb_lock_count: %d", + thd->transaction.ndb_lock_count)); + + /* + Check that this handler instance has a connection + set up to the Ndb object of thd + */ + if (check_ndb_connection()) + DBUG_RETURN(1); + + if (lock_type != F_UNLCK) + { + if (!thd->transaction.ndb_lock_count++) + { + PRINT_OPTION_FLAGS(thd); + + if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN | OPTION_TABLE_LOCK))) + { + // Autocommit transaction + DBUG_ASSERT(!thd->transaction.stmt.ndb_tid); + DBUG_PRINT("trans",("Starting transaction stmt")); + + trans= m_ndb->startTransaction(); + if (trans == NULL) + { + thd->transaction.ndb_lock_count--; // We didn't get the lock + ERR_RETURN(m_ndb->getNdbError()); + } + thd->transaction.stmt.ndb_tid= trans; + } + else + { + if (!thd->transaction.all.ndb_tid) + { + // Not autocommit transaction + // A "master" transaction ha not been started yet + DBUG_PRINT("trans",("starting transaction, all")); + + trans= m_ndb->startTransaction(); + if (trans == NULL) + { + thd->transaction.ndb_lock_count--; // We didn't get the lock + ERR_RETURN(m_ndb->getNdbError()); + } + + /* + If this is the start of a LOCK TABLE, a table look + should be taken on the table in NDB + + Check if it should be read or write lock + */ + if (thd->options & (OPTION_TABLE_LOCK)) + { + //lockThisTable(); + DBUG_PRINT("info", ("Locking the table..." )); + } + + thd->transaction.all.ndb_tid= trans; + } + } + } + /* + This is the place to make sure this handler instance + has a started transaction. + + The transaction is started by the first handler on which + MySQL Server calls external lock + + Other handlers in the same stmt or transaction should use + the same NDB transaction. This is done by setting up the m_active_trans + pointer to point to the NDB transaction. + */ + + m_active_trans= thd->transaction.all.ndb_tid ? + (NdbConnection*)thd->transaction.all.ndb_tid: + (NdbConnection*)thd->transaction.stmt.ndb_tid; + DBUG_ASSERT(m_active_trans); + + } + else + { + if (!--thd->transaction.ndb_lock_count) + { + DBUG_PRINT("trans", ("Last external_lock")); + PRINT_OPTION_FLAGS(thd); + + if (thd->transaction.stmt.ndb_tid) + { + /* + Unlock is done without a transaction commit / rollback. + This happens if the thread didn't update any rows + We must in this case close the transaction to release resources + */ + DBUG_PRINT("trans",("ending non-updating transaction")); + m_ndb->closeTransaction(m_active_trans); + thd->transaction.stmt.ndb_tid= 0; + } + } + m_active_trans= NULL; + } + DBUG_RETURN(error); +} + +/* + When using LOCK TABLE's external_lock is only called when the actual + TABLE LOCK is done. + Under LOCK TABLES, each used tables will force a call to start_stmt. +*/ + +int ha_ndbcluster::start_stmt(THD *thd) +{ + int error=0; + DBUG_ENTER("start_stmt"); + PRINT_OPTION_FLAGS(thd); + + NdbConnection *trans= (NdbConnection*)thd->transaction.stmt.ndb_tid; + if (!trans){ + DBUG_PRINT("trans",("Starting transaction stmt")); + + NdbConnection *tablock_trans= + (NdbConnection*)thd->transaction.all.ndb_tid; + DBUG_PRINT("info", ("tablock_trans: %x", tablock_trans)); + DBUG_ASSERT(tablock_trans); trans= m_ndb->hupp(tablock_trans); + if (trans == NULL) + ERR_RETURN(m_ndb->getNdbError()); + thd->transaction.stmt.ndb_tid= trans; + } + m_active_trans= trans; + + DBUG_RETURN(error); +} + + +/* + Commit a transaction started in NDB + */ + +int ndbcluster_commit(THD *thd, void *ndb_transaction) +{ + int res= 0; + Ndb *ndb= (Ndb*)thd->transaction.ndb; + NdbConnection *trans= (NdbConnection*)ndb_transaction; + + DBUG_ENTER("ndbcluster_commit"); + DBUG_PRINT("transaction",("%s", + trans == thd->transaction.stmt.ndb_tid ? + "stmt" : "all")); + DBUG_ASSERT(ndb && trans); + + if (trans->execute(Commit) != 0) + { + const NdbError err= trans->getNdbError(); + ERR_PRINT(err); + res= ndb_to_mysql_error(&err); + } + ndb->closeTransaction(trans); + DBUG_RETURN(res); +} + + +/* + Rollback a transaction started in NDB + */ + +int ndbcluster_rollback(THD *thd, void *ndb_transaction) +{ + int res= 0; + Ndb *ndb= (Ndb*)thd->transaction.ndb; + NdbConnection *trans= (NdbConnection*)ndb_transaction; + + DBUG_ENTER("ndbcluster_rollback"); + DBUG_PRINT("transaction",("%s", + trans == thd->transaction.stmt.ndb_tid ? + "stmt" : "all")); + DBUG_ASSERT(ndb && trans); + + if (trans->execute(Rollback) != 0) + { + const NdbError err= trans->getNdbError(); + ERR_PRINT(err); + res= ndb_to_mysql_error(&err); + } + ndb->closeTransaction(trans); + DBUG_RETURN(0); +} + + +/* + Map MySQL type to the corresponding NDB type + */ + +inline NdbDictionary::Column::Type +mysql_to_ndb_type(enum enum_field_types mysql_type, bool unsigned_flg) +{ + switch(mysql_type) { + case MYSQL_TYPE_DECIMAL: + return NdbDictionary::Column::Char; + case MYSQL_TYPE_TINY: + return (unsigned_flg) ? + NdbDictionary::Column::Tinyunsigned : + NdbDictionary::Column::Tinyint; + case MYSQL_TYPE_SHORT: + return (unsigned_flg) ? + NdbDictionary::Column::Smallunsigned : + NdbDictionary::Column::Smallint; + case MYSQL_TYPE_LONG: + return (unsigned_flg) ? + NdbDictionary::Column::Unsigned : + NdbDictionary::Column::Int; + case MYSQL_TYPE_TIMESTAMP: + return NdbDictionary::Column::Unsigned; + case MYSQL_TYPE_LONGLONG: + return (unsigned_flg) ? + NdbDictionary::Column::Bigunsigned : + NdbDictionary::Column::Bigint; + case MYSQL_TYPE_INT24: + return (unsigned_flg) ? + NdbDictionary::Column::Mediumunsigned : + NdbDictionary::Column::Mediumint; + break; + case MYSQL_TYPE_FLOAT: + return NdbDictionary::Column::Float; + case MYSQL_TYPE_DOUBLE: + return NdbDictionary::Column::Double; + case MYSQL_TYPE_DATETIME : + return NdbDictionary::Column::Datetime; + case MYSQL_TYPE_DATE : + case MYSQL_TYPE_NEWDATE : + case MYSQL_TYPE_TIME : + case MYSQL_TYPE_YEAR : + // Missing NDB data types, mapped to char + return NdbDictionary::Column::Char; + case MYSQL_TYPE_ENUM : + return NdbDictionary::Column::Char; + case MYSQL_TYPE_SET : + return NdbDictionary::Column::Char; + case MYSQL_TYPE_TINY_BLOB : + case MYSQL_TYPE_MEDIUM_BLOB : + case MYSQL_TYPE_LONG_BLOB : + case MYSQL_TYPE_BLOB : + return NdbDictionary::Column::Blob; + case MYSQL_TYPE_VAR_STRING : + return NdbDictionary::Column::Varchar; + case MYSQL_TYPE_STRING : + return NdbDictionary::Column::Char; + case MYSQL_TYPE_NULL : + case MYSQL_TYPE_GEOMETRY : + return NdbDictionary::Column::Undefined; + } + return NdbDictionary::Column::Undefined; +} + + +/* + Create a table in NDB Cluster + */ + +int ha_ndbcluster::create(const char *name, + TABLE *form, + HA_CREATE_INFO *info) +{ + NDBTAB tab; + NdbDictionary::Column::Type ndb_type; + NDBCOL col; + uint pack_length, length, i; + int res; + const void *data, *pack_data; + const char **key_name= form->keynames.type_names; + char name2[FN_HEADLEN]; + + DBUG_ENTER("create"); + DBUG_PRINT("enter", ("name: %s", name)); + fn_format(name2, name, "", "",2); // Remove the .frm extension + set_dbname(name2); + set_tabname(name2); + + DBUG_PRINT("table", ("name: %s", m_tabname)); + tab.setName(m_tabname); + tab.setLogging(!(info->options & HA_LEX_CREATE_TMP_TABLE)); + + // Save frm data for this table + if (readfrm(name, &data, &length)) + DBUG_RETURN(1); + if (packfrm(data, length, &pack_data, &pack_length)) + DBUG_RETURN(2); + + DBUG_PRINT("info", ("setFrm data=%x, len=%d", pack_data, pack_length)); + tab.setFrm(pack_data, pack_length); + my_free((char*)data, MYF(0)); + my_free((char*)pack_data, MYF(0)); + + for (i= 0; i < form->fields; i++) + { + Field *field= form->field[i]; + ndb_type= mysql_to_ndb_type(field->real_type(), + field->flags & UNSIGNED_FLAG); + DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d", + field->field_name, field->real_type(), + field->pack_length())); + col.setName(field->field_name); + col.setType(ndb_type); + if ((ndb_type == NdbDictionary::Column::Char) || + (ndb_type == NdbDictionary::Column::Varchar)) + col.setLength(field->pack_length()); + else + col.setLength(1); + col.setNullable(field->maybe_null()); + col.setPrimaryKey(field->flags & PRI_KEY_FLAG); + if (field->flags & AUTO_INCREMENT_FLAG) + { + DBUG_PRINT("info", ("Found auto_increment key")); + col.setAutoIncrement(TRUE); + ulonglong value = info->auto_increment_value ? + info->auto_increment_value -1 : + (ulonglong) 0; + DBUG_PRINT("info", ("initial value=%ld", value)); +// col.setInitialAutIncValue(value); + } + else + col.setAutoIncrement(false); + + tab.addColumn(col); + } + + // No primary key, create shadow key as 64 bit, auto increment + if (form->primary_key == MAX_KEY) + { + DBUG_PRINT("info", ("Generating shadow key")); + col.setName("$PK"); + col.setType(NdbDictionary::Column::Bigunsigned); + col.setLength(1); + col.setNullable(false); + col.setPrimaryKey(TRUE); + col.setAutoIncrement(TRUE); + tab.addColumn(col); + } + + my_errno= 0; + if (check_ndb_connection()) + { + my_errno= HA_ERR_NO_CONNECTION; + DBUG_RETURN(my_errno); + } + + // Create the table in NDB + NDBDICT *dict= m_ndb->getDictionary(); + if (dict->createTable(tab)) + { + const NdbError err= dict->getNdbError(); + ERR_PRINT(err); + my_errno= ndb_to_mysql_error(&err); + DBUG_RETURN(my_errno); + } + DBUG_PRINT("info", ("Table %s/%s created successfully", + m_dbname, m_tabname)); + + // Fetch table from NDB, check that it exists + const NDBTAB *tab2= dict->getTable(m_tabname); + if (tab2 == NULL) + { + const NdbError err= dict->getNdbError(); + ERR_PRINT(err); + my_errno= ndb_to_mysql_error(&err); + DBUG_RETURN(my_errno); + } + + // Create secondary indexes + for (i= 0; i < form->keys; i++) + { + DBUG_PRINT("info", ("Found index %u: %s", i, key_name[i])); + if (i == form->primary_key) + { + DBUG_PRINT("info", ("Skipping it, PK already created")); + continue; + } + + DBUG_PRINT("info", ("Creating index %u: %s", i, key_name[i])); + res= create_index(key_name[i], + form->key_info + i); + switch(res){ + case 0: + // OK + break; + default: + DBUG_PRINT("error", ("Failed to create index %u", i)); + drop_table(); + my_errno= res; + goto err_end; + } + } + +err_end: + DBUG_RETURN(my_errno); +} + + +/* + Create an index in NDB Cluster + */ + +int ha_ndbcluster::create_index(const char *name, + KEY *key_info){ + NdbDictionary::Dictionary *dict= m_ndb->getDictionary(); + KEY_PART_INFO *key_part= key_info->key_part; + KEY_PART_INFO *end= key_part + key_info->key_parts; + + DBUG_ENTER("create_index"); + DBUG_PRINT("enter", ("name: %s ", name)); + + // Check that an index with the same name do not already exist + if (dict->getIndex(name, m_tabname)) + ERR_RETURN(dict->getNdbError()); + + NdbDictionary::Index ndb_index(name); + if (key_info->flags & HA_NOSAME) + ndb_index.setType(NdbDictionary::Index::UniqueHashIndex); + else + { + ndb_index.setType(NdbDictionary::Index::OrderedIndex); + // TODO Only temporary ordered indexes supported + ndb_index.setLogging(false); + } + ndb_index.setTable(m_tabname); + + for (; key_part != end; key_part++) + { + Field *field= key_part->field; + DBUG_PRINT("info", ("attr: %s", field->field_name)); + ndb_index.addColumnName(field->field_name); + } + + if (dict->createIndex(ndb_index)) + ERR_RETURN(dict->getNdbError()); + + // Success + DBUG_PRINT("info", ("Created index %s", name)); + DBUG_RETURN(0); +} + + +/* + Rename a table in NDB Cluster +*/ + +int ha_ndbcluster::rename_table(const char *from, const char *to) +{ + char new_tabname[FN_HEADLEN]; + + DBUG_ENTER("ha_ndbcluster::rename_table"); + set_dbname(from); + set_tabname(from); + set_tabname(to, new_tabname); + + if (check_ndb_connection()) { + my_errno= HA_ERR_NO_CONNECTION; + DBUG_RETURN(my_errno); + } + + int result= alter_table_name(m_tabname, new_tabname); + if (result == 0) + set_tabname(to); + + DBUG_RETURN(result); +} + + +/* + Rename a table in NDB Cluster using alter table + */ + +int ha_ndbcluster::alter_table_name(const char *from, const char *to) +{ + NDBDICT *dict= m_ndb->getDictionary(); + const NDBTAB *orig_tab; + DBUG_ENTER("alter_table_name_table"); + DBUG_PRINT("enter", ("Renaming %s to %s", from, to)); + + if (!(orig_tab= dict->getTable(from))) + ERR_RETURN(dict->getNdbError()); + + NdbDictionary::Table copy_tab= dict->getTableForAlteration(from); + copy_tab.setName(to); + if (dict->alterTable(copy_tab) != 0) + ERR_RETURN(dict->getNdbError()); + + m_table= NULL; + + DBUG_RETURN(0); +} + + +/* + Delete a table from NDB Cluster + */ + +int ha_ndbcluster::delete_table(const char *name) +{ + DBUG_ENTER("delete_table"); + DBUG_PRINT("enter", ("name: %s", name)); + set_dbname(name); + set_tabname(name); + + if (check_ndb_connection()) + DBUG_RETURN(HA_ERR_NO_CONNECTION); + DBUG_RETURN(drop_table()); +} + + +/* + Drop a table in NDB Cluster + */ + +int ha_ndbcluster::drop_table() +{ + NdbDictionary::Dictionary *dict= m_ndb->getDictionary(); + + DBUG_ENTER("drop_table"); + DBUG_PRINT("enter", ("Deleting %s", m_tabname)); + + if (dict->dropTable(m_tabname)) + { + const NdbError err= dict->getNdbError(); + if (err.code == 709) + ; // 709: No such table existed + else + ERR_RETURN(dict->getNdbError()); + } + release_metadata(); + DBUG_RETURN(0); +} + + +/* + Drop a database in NDB Cluster + */ + +int ndbcluster_drop_database(const char *path) +{ + DBUG_ENTER("ndbcluster_drop_database"); + // TODO drop all tables for this database + DBUG_RETURN(1); +} + + +longlong ha_ndbcluster::get_auto_increment() +{ + // NOTE If number of values to be inserted is known + // the autoincrement cache could be used here + Uint64 auto_value= m_ndb->getAutoIncrementValue(m_tabname); + return (longlong)auto_value; +} + + +/* + Constructor for the NDB Cluster table handler + */ + +ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): + handler(table_arg), + m_active_trans(NULL), + m_active_cursor(NULL), + m_ndb(NULL), + m_table(NULL), + m_table_flags(HA_REC_NOT_IN_SEQ | + HA_KEYPOS_TO_RNDPOS | + HA_NOT_EXACT_COUNT | + HA_NO_WRITE_DELAYED | + HA_NO_PREFIX_CHAR_KEYS | + HA_NO_BLOBS | + HA_DROP_BEFORE_CREATE | + HA_NOT_READ_AFTER_KEY), + m_use_write(false) +{ + + DBUG_ENTER("ha_ndbcluster"); + + m_tabname[0]= '\0'; + m_dbname[0]= '\0'; + + // TODO Adjust number of records and other parameters for proper + // selection of scan/pk access + records= 100; + block_size= 1024; + + DBUG_VOID_RETURN; +} + + +/* + Destructor for NDB Cluster table handler + */ + +ha_ndbcluster::~ha_ndbcluster() +{ + DBUG_ENTER("~ha_ndbcluster"); + + release_metadata(); + + // Check for open cursor/transaction + DBUG_ASSERT(m_active_cursor == NULL); + DBUG_ASSERT(m_active_trans == NULL); + + DBUG_VOID_RETURN; +} + + +/* + Open a table for further use + - fetch metadata for this table from NDB + - check that table exists +*/ + +int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked) +{ + KEY *key; + DBUG_ENTER("open"); + DBUG_PRINT("enter", ("name: %s mode: %d test_if_locked: %d", + name, mode, test_if_locked)); + + // Setup ref_length to make room for the whole + // primary key to be written in the ref variable + + if (table->primary_key != MAX_KEY) + { + key= table->key_info+table->primary_key; + ref_length= key->key_length; + DBUG_PRINT("info", (" ref_length: %d", ref_length)); + } + // Init table lock structure + if (!(m_share=get_share(name))) + DBUG_RETURN(1); + thr_lock_data_init(&m_share->lock,&m_lock,(void*) 0); + + set_dbname(name); + set_tabname(name); + + if (check_ndb_connection()) + DBUG_RETURN(HA_ERR_NO_CONNECTION); + + DBUG_RETURN(get_metadata(name)); +} + + +/* + Close the table + - release resources setup by open() + */ + +int ha_ndbcluster::close(void) +{ + DBUG_ENTER("close"); + free_share(m_share); + release_metadata(); + m_ndb= NULL; + DBUG_RETURN(0); +} + + +Ndb* ha_ndbcluster::seize_ndb() +{ + Ndb* ndb; + DBUG_ENTER("seize_ndb"); + +#ifdef USE_NDB_POOL + // Seize from pool + ndb= Ndb::seize(); +#else + ndb= new Ndb(""); +#endif + if (ndb->init(NDB_MAX_TRANSACTIONS) != 0) + { + ERR_PRINT(ndb->getNdbError()); + /* + TODO + Alt.1 If init fails because to many allocated Ndb + wait on condition for a Ndb object to be released. + Alt.2 Seize/release from pool, wait until next release + */ + delete ndb; + ndb= NULL; + } + DBUG_RETURN(ndb); +} + + +void ha_ndbcluster::release_ndb(Ndb* ndb) +{ + DBUG_ENTER("release_ndb"); +#ifdef USE_NDB_POOL + // Release to pool + Ndb::release(ndb); +#else + delete ndb; +#endif + DBUG_VOID_RETURN; +} + + +/* + If this thread already has a Ndb object allocated + in current THD, reuse it. Otherwise + seize a Ndb object, assign it to current THD and use it. + + Having a Ndb object also means that a connection to + NDB cluster has been opened. The connection is + checked. + +*/ + +int ha_ndbcluster::check_ndb_connection() +{ + THD* thd= current_thd; + Ndb* ndb; + DBUG_ENTER("check_ndb_connection"); + + if (!thd->transaction.ndb) + { + ndb= seize_ndb(); + if (!ndb) + DBUG_RETURN(2); + thd->transaction.ndb= ndb; + } + m_ndb= (Ndb*)thd->transaction.ndb; + m_ndb->setDatabaseName(m_dbname); + if (m_ndb->waitUntilReady() != 0) + { + DBUG_PRINT("error", ("Ndb was not ready")); + DBUG_RETURN(3); + } + DBUG_RETURN(0); +} + +void ndbcluster_close_connection(THD *thd) +{ + Ndb* ndb; + DBUG_ENTER("ndbcluster_close_connection"); + ndb= (Ndb*)thd->transaction.ndb; + ha_ndbcluster::release_ndb(ndb); + thd->transaction.ndb= NULL; + DBUG_VOID_RETURN; +} + + +/* + Try to discover one table from NDB + */ + +int ndbcluster_discover(const char *dbname, const char *name, + const void** frmblob, uint* frmlen) +{ + uint len; + const void* data; + const NDBTAB* tab; + DBUG_ENTER("ndbcluster_discover"); + DBUG_PRINT("enter", ("db: %s, name: %s", dbname, name)); + + Ndb ndb(dbname); + if ((ndb.init() != 0) && (ndb.waitUntilReady() != 0)) + ERR_RETURN(ndb.getNdbError()); + + if (!(tab= ndb.getDictionary()->getTable(name))) + { + DBUG_PRINT("info", ("Table %s not found", name)); + DBUG_RETURN(1); + } + + DBUG_PRINT("info", ("Found table %s", tab->getName())); + + len= tab->getFrmLength(); + if (len == 0 || tab->getFrmData() == NULL) + { + DBUG_PRINT("No frm data found", + ("Table is probably created via NdbApi")); + DBUG_RETURN(2); + } + + if (unpackfrm(&data, &len, tab->getFrmData())) + DBUG_RETURN(3); + + *frmlen= len; + *frmblob= data; + + DBUG_RETURN(0); +} + +static Ndb* g_ndb= NULL; + +#ifdef USE_DISCOVER_ON_STARTUP +/* + Dicover tables from NDB Cluster + - fetch a list of tables from NDB + - store the frm file for each table on disk + - if the table has an attached frm file + - if the database of the table exists +*/ + +int ndb_discover_tables() +{ + uint i; + NdbDictionary::Dictionary::List list; + NdbDictionary::Dictionary* dict; + char path[FN_REFLEN]; + DBUG_ENTER("ndb_discover_tables"); + + /* List tables in NDB Cluster kernel */ + dict= g_ndb->getDictionary(); + if (dict->listObjects(list, + NdbDictionary::Object::UserTable) != 0) + ERR_RETURN(g_ndb->getNdbError()); + + for (i= 0 ; i < list.count ; i++) + { + NdbDictionary::Dictionary::List::Element& t= list.elements[i]; + + DBUG_PRINT("discover", ("%d: %s/%s", t.id, t.database, t.name)); + if (create_table_from_handler(t.database, t.name, true)) + DBUG_PRINT("info", ("Could not discover %s/%s", t.database, t.name)); + } + DBUG_RETURN(0); +} +#endif + + +/* + Initialise all gloal variables before creating + a NDB Cluster table handler + */ + +bool ndbcluster_init() +{ + DBUG_ENTER("ndbcluster_init"); + // Create a Ndb object to open the connection to NDB + g_ndb= new Ndb("sys"); + if (g_ndb->init() != 0) + { + ERR_PRINT (g_ndb->getNdbError()); + DBUG_RETURN(TRUE); + } + if (g_ndb->waitUntilReady() != 0) + { + ERR_PRINT (g_ndb->getNdbError()); + DBUG_RETURN(TRUE); + } + (void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0, + (hash_get_key) ndbcluster_get_key,0,0); + pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST); + ndbcluster_inited= 1; +#ifdef USE_DISCOVER_ON_STARTUP + if (ndb_discover_tables() != 0) + DBUG_RETURN(TRUE); +#endif + DBUG_RETURN(false); +} + + +/* + End use of the NDB Cluster table handler + - free all global variables allocated by + ndcluster_init() +*/ + +bool ndbcluster_end() +{ + DBUG_ENTER("ndbcluster_end"); + delete g_ndb; + g_ndb= NULL; + if (!ndbcluster_inited) + DBUG_RETURN(0); + hash_free(&ndbcluster_open_tables); +#ifdef USE_NDB_POOL + ndb_pool_release(); +#endif + pthread_mutex_destroy(&ndbcluster_mutex); + ndbcluster_inited= 0; + DBUG_RETURN(0); +} + + +/* + Set m_tabname from full pathname to table file + */ + +void ha_ndbcluster::set_tabname(const char *path_name) +{ + char *end, *ptr; + + /* Scan name from the end */ + end= strend(path_name)-1; + ptr= end; + while (ptr >= path_name && *ptr != '\\' && *ptr != '/') { + ptr--; + } + uint name_len= end - ptr; + memcpy(m_tabname, ptr + 1, end - ptr); + m_tabname[name_len]= '\0'; +#ifdef __WIN__ + /* Put to lower case */ + ptr= m_tabname; + + while (*ptr != '\0') { + *ptr = tolower(*ptr); + ptr++; + } +#endif +} + +/** + * Set a given location from full pathname to table file + * + */ +void +ha_ndbcluster::set_tabname(const char *path_name, char * tabname) +{ + char *end, *ptr; + + /* Scan name from the end */ + end = strend(path_name)-1; + ptr = end; + while (ptr >= path_name && *ptr != '\\' && *ptr != '/') { + ptr--; + } + uint name_len = end - ptr; + memcpy(tabname, ptr + 1, end - ptr); + tabname[name_len] = '\0'; +#ifdef __WIN__ + /* Put to lower case */ + ptr = tabname; + + while (*ptr != '\0') { + *ptr= tolower(*ptr); + ptr++; + } +#endif +} + + +/* + Set m_dbname from full pathname to table file + + */ + +void ha_ndbcluster::set_dbname(const char *path_name) +{ + char *end, *ptr; + + /* Scan name from the end */ + ptr= strend(path_name)-1; + while (ptr >= path_name && *ptr != '\\' && *ptr != '/') { + ptr--; + } + ptr--; + end= ptr; + while (ptr >= path_name && *ptr != '\\' && *ptr != '/') { + ptr--; + } + uint name_len= end - ptr; + memcpy(m_dbname, ptr + 1, name_len); + m_dbname[name_len]= '\0'; +#ifdef __WIN__ + /* Put to lower case */ + + ptr= m_dbname; + + while (*ptr != '\0') { + *ptr= tolower(*ptr); + ptr++; + } +#endif +} + + +ha_rows +ha_ndbcluster::records_in_range(int inx, + const byte *start_key,uint start_key_len, + enum ha_rkey_function start_search_flag, + const byte *end_key,uint end_key_len, + enum ha_rkey_function end_search_flag) +{ + ha_rows records= 10; + KEY* key_info= table->key_info + inx; + uint key_length= key_info->key_length; + + DBUG_ENTER("records_in_range"); + DBUG_PRINT("enter", ("inx: %d", inx)); + DBUG_PRINT("enter", ("start_key: %x, start_key_len: %d", start_key, start_key_len)); + DBUG_PRINT("enter", ("start_search_flag: %d", start_search_flag)); + DBUG_PRINT("enter", ("end_key: %x, end_key_len: %d", end_key, end_key_len)); + DBUG_PRINT("enter", ("end_search_flag: %d", end_search_flag)); + + /* + Check that start_key_len is equal to + the length of the used index and + prevent partial scan/read of hash indexes by returning HA_POS_ERROR + */ + NDB_INDEX_TYPE idx_type= get_index_type(inx); + if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) && + start_key_len < key_length) + { + DBUG_PRINT("warning", ("Tried to use index which required" + "full key length: %d, HA_POS_ERROR", + key_length)); + records= HA_POS_ERROR; + } + DBUG_RETURN(records); +} + + +/* + Handling the shared NDB_SHARE structure that is needed to + provide table locking. + It's also used for sharing data with other NDB handlers + in the same MySQL Server. There is currently not much + data we want to or can share. + */ + +static byte* ndbcluster_get_key(NDB_SHARE *share,uint *length, + my_bool not_used __attribute__((unused))) +{ + *length=share->table_name_length; + return (byte*) share->table_name; +} + +static NDB_SHARE* get_share(const char *table_name) +{ + NDB_SHARE *share; + pthread_mutex_lock(&ndbcluster_mutex); + uint length=(uint) strlen(table_name); + if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables, + (byte*) table_name, + length))) + { + if ((share=(NDB_SHARE *) my_malloc(sizeof(*share)+length+1, + MYF(MY_WME | MY_ZEROFILL)))) + { + share->table_name_length=length; + share->table_name=(char*) (share+1); + strmov(share->table_name,table_name); + if (my_hash_insert(&ndbcluster_open_tables, (byte*) share)) + { + pthread_mutex_unlock(&ndbcluster_mutex); + my_free((gptr) share,0); + return 0; + } + thr_lock_init(&share->lock); + pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST); + } + } + share->use_count++; + pthread_mutex_unlock(&ndbcluster_mutex); + return share; +} + + +static void free_share(NDB_SHARE *share) +{ + pthread_mutex_lock(&ndbcluster_mutex); + if (!--share->use_count) + { + hash_delete(&ndbcluster_open_tables, (byte*) share); + thr_lock_delete(&share->lock); + pthread_mutex_destroy(&share->mutex); + my_free((gptr) share, MYF(0)); + } + pthread_mutex_unlock(&ndbcluster_mutex); +} + + + +/* + Internal representation of the frm blob + +*/ + +struct frm_blob_struct +{ + struct frm_blob_header + { + uint ver; // Version of header + uint orglen; // Original length of compressed data + uint complen; // Compressed length of data, 0=uncompressed + } head; + char data[1]; +}; + + + +static int packfrm(const void *data, uint len, + const void **pack_data, uint *pack_len) +{ + int error; + ulong org_len, comp_len; + uint blob_len; + frm_blob_struct* blob; + DBUG_ENTER("packfrm"); + DBUG_PRINT("enter", ("data: %x, len: %d", data, len)); + + error= 1; + org_len = len; + if (my_compress((byte*)data, &org_len, &comp_len)) + goto err; + + DBUG_PRINT("info", ("org_len: %d, comp_len: %d", org_len, comp_len)); + DBUG_DUMP("compressed", (char*)data, org_len); + + error= 2; + blob_len= sizeof(frm_blob_struct::frm_blob_header)+org_len; + if (!(blob= (frm_blob_struct*) my_malloc(blob_len,MYF(MY_WME)))) + goto err; + + // Store compressed blob in machine independent format + int4store((char*)(&blob->head.ver), 1); + int4store((char*)(&blob->head.orglen), comp_len); + int4store((char*)(&blob->head.complen), org_len); + + // Copy frm data into blob, already in machine independent format + memcpy(blob->data, data, org_len); + + *pack_data = blob; + *pack_len = blob_len; + error = 0; + + DBUG_PRINT("exit", ("pack_data: %x, pack_len: %d", *pack_data, *pack_len)); +err: + DBUG_RETURN(error); + +} + + +static int unpackfrm(const void **unpack_data, uint *unpack_len, + const void *pack_data) +{ + const frm_blob_struct *blob = (frm_blob_struct*)pack_data; + byte *data; + ulong complen, orglen, ver; + DBUG_ENTER("unpackfrm"); + DBUG_PRINT("enter", ("pack_data: %x", pack_data)); + + complen= uint4korr((char*)&blob->head.complen); + orglen= uint4korr((char*)&blob->head.orglen); + ver= uint4korr((char*)&blob->head.ver); + + DBUG_PRINT("blob",("ver: %d complen: %d orglen: %d", + ver,complen,orglen)); + DBUG_DUMP("blob->data", (char*) blob->data, complen); + + if (ver != 1) + DBUG_RETURN(1); + if (!(data = my_malloc(max(orglen, complen), MYF(MY_WME)))) + DBUG_RETURN(2); + memcpy(data, blob->data, complen); + + if (my_uncompress(data, &complen, &orglen)) + { + my_free((char*)data, MYF(0)); + DBUG_RETURN(3); + } + + *unpack_data = data; + *unpack_len = complen; + + DBUG_PRINT("exit", ("frmdata: %x, len: %d", *unpack_data, *unpack_len)); + + DBUG_RETURN(0); +} +#endif /* HAVE_NDBCLUSTER_DB */ diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h new file mode 100644 index 00000000000..ed66d07d79b --- /dev/null +++ b/sql/ha_ndbcluster.h @@ -0,0 +1,218 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + This file defines the NDB Cluster handler: the interface between MySQL and + NDB Cluster +*/ + +/* The class defining a handle to an NDB Cluster table */ + +#ifdef __GNUC__ +#pragma interface /* gcc class implementation */ +#endif + +#include <ndbapi_limits.h> +#include <ndb_types.h> + +class Ndb; // Forward declaration +class NdbOperation; // Forward declaration +class NdbConnection; // Forward declaration +class NdbRecAttr; // Forward declaration +class NdbResultSet; // Forward declaration + +typedef enum ndb_index_type { + UNDEFINED_INDEX = 0, + PRIMARY_KEY_INDEX = 1, + UNIQUE_INDEX = 2, + ORDERED_INDEX = 3 +} NDB_INDEX_TYPE; + + +typedef struct st_ndbcluster_share { + THR_LOCK lock; + pthread_mutex_t mutex; + char *table_name; + uint table_name_length,use_count; +} NDB_SHARE; + +class ha_ndbcluster: public handler +{ + public: + ha_ndbcluster(TABLE *table); + ~ha_ndbcluster(); + + int open(const char *name, int mode, uint test_if_locked); + int close(void); + + int write_row(byte *buf); + int update_row(const byte *old_data, byte *new_data); + int delete_row(const byte *buf); + int index_init(uint index); + int index_end(); + int index_read(byte *buf, const byte *key, uint key_len, + enum ha_rkey_function find_flag); + int index_read_idx(byte *buf, uint index, const byte *key, uint key_len, + enum ha_rkey_function find_flag); + int index_next(byte *buf); + int index_prev(byte *buf); + int index_first(byte *buf); + int index_last(byte *buf); + int rnd_init(bool scan=1); + int rnd_end(); + int rnd_next(byte *buf); + int rnd_pos(byte *buf, byte *pos); + void position(const byte *record); + + void info(uint); + int extra(enum ha_extra_function operation); + int extra_opt(enum ha_extra_function operation, ulong cache_size); + int reset(); + int external_lock(THD *thd, int lock_type); + int start_stmt(THD *thd); + const char * table_type() const { return("ndbcluster");} + const char ** bas_ext() const; + ulong table_flags(void) const { return m_table_flags; } + ulong index_flags(uint idx) const; + uint max_record_length() const { return NDB_MAX_TUPLE_SIZE; }; + uint max_keys() const { return MAX_KEY; } + uint max_key_parts() const { return NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY; }; + uint max_key_length() const { return NDB_MAX_KEY_SIZE;}; + + int rename_table(const char *from, const char *to); + int delete_table(const char *name); + int create(const char *name, TABLE *form, HA_CREATE_INFO *info); + THR_LOCK_DATA **store_lock(THD *thd, + THR_LOCK_DATA **to, + enum thr_lock_type lock_type); + + bool low_byte_first() const + { +#ifdef WORDS_BIGENDIAN + return false; +#else + return true; +#endif + } + bool has_transactions() { return true;} + + const char* index_type(uint key_number) { + switch (get_index_type(key_number)) { + case ORDERED_INDEX: + return "BTREE"; + case UNIQUE_INDEX: + case PRIMARY_KEY_INDEX: + default: + return "HASH"; + } + } + + double scan_time(); + ha_rows records_in_range(int inx, + const byte *start_key,uint start_key_len, + enum ha_rkey_function start_search_flag, + const byte *end_key,uint end_key_len, + enum ha_rkey_function end_search_flag); + + + static Ndb* seize_ndb(); + static void release_ndb(Ndb* ndb); + + + private: + int alter_table_name(const char *from, const char *to); + int drop_table(); + int create_index(const char *name, KEY *key_info); + int initialize_autoincrement(const void* table); + int get_metadata(const char* path); + void release_metadata(); + const char* get_index_name(uint idx_no) const; + NDB_INDEX_TYPE get_index_type(uint idx_no) const; + NDB_INDEX_TYPE get_index_type_from_table(uint index_no) const; + + int pk_read(const byte *key, uint key_len, + byte *buf); + int unique_index_read(const byte *key, uint key_len, + byte *buf); + int ordered_index_scan(const byte *key, uint key_len, + byte *buf, + enum ha_rkey_function find_flag); + int full_table_scan(byte * buf); + int next_result(byte *buf); +#if 0 + int filtered_scan(const byte *key, uint key_len, + byte *buf, + enum ha_rkey_function find_flag); +#endif + + void unpack_record(byte *buf); + + void set_dbname(const char *pathname); + void set_tabname(const char *pathname); + void set_tabname(const char *pathname, char *tabname); + + bool set_hidden_key(NdbOperation*, + uint fieldnr, const byte* field_ptr); + int set_ndb_key(NdbOperation*, Field *field, + uint fieldnr, const byte* field_ptr); + int set_ndb_value(NdbOperation*, Field *field, uint fieldnr); + int get_ndb_value(NdbOperation*, uint fieldnr, byte *field_ptr); + int set_primary_key(NdbOperation *op, const byte *key); + int set_primary_key(NdbOperation *op); + int key_cmp(uint keynr, const byte * old_row, const byte * new_row); + void print_results(); + + longlong get_auto_increment(); + + int ndb_err(NdbConnection*); + + private: + int check_ndb_connection(); + + NdbConnection *m_active_trans; + NdbResultSet *m_active_cursor; + Ndb *m_ndb; + void *m_table; + char m_dbname[FN_HEADLEN]; + //char m_schemaname[FN_HEADLEN]; + char m_tabname[FN_HEADLEN]; + ulong m_table_flags; + THR_LOCK_DATA m_lock; + NDB_SHARE *m_share; + NDB_INDEX_TYPE m_indextype[MAX_KEY]; + NdbRecAttr *m_value[NDB_MAX_ATTRIBUTES_IN_TABLE]; + bool m_use_write; +}; + +bool ndbcluster_init(void); +bool ndbcluster_end(void); + +int ndbcluster_commit(THD *thd, void* ndb_transaction); +int ndbcluster_rollback(THD *thd, void* ndb_transaction); + +void ndbcluster_close_connection(THD *thd); + +int ndbcluster_discover(const char* dbname, const char* name, + const void** frmblob, uint* frmlen); +int ndbcluster_drop_database(const char* path); + + + + + + + + diff --git a/sql/handler.cc b/sql/handler.cc index 97abc11abe3..670a2b401be 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -40,6 +40,9 @@ #else #define innobase_query_caching_of_table_permitted(X,Y,Z) 1 #endif +#ifdef HAVE_NDBCLUSTER_DB +#include "ha_ndbcluster.h" +#endif #include <myisampack.h> #include <errno.h> @@ -51,7 +54,7 @@ ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count, ha_read_key_count, ha_read_next_count, ha_read_prev_count, ha_read_first_count, ha_read_last_count, ha_commit_count, ha_rollback_count, - ha_read_rnd_count, ha_read_rnd_next_count; + ha_read_rnd_count, ha_read_rnd_next_count, ha_discover_count; static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; @@ -79,6 +82,10 @@ struct show_table_type_st sys_table_types[]= "Supports transactions and page-level locking", DB_TYPE_BERKELEY_DB}, {"BERKELEYDB",&have_berkeley_db, "Alias for BDB", DB_TYPE_BERKELEY_DB}, + {"NDBCLUSTER", &have_ndbcluster, + "Clustered, fault tolerant memory based tables", DB_TYPE_NDBCLUSTER}, + {"NDB", &have_ndbcluster, + "Alias for NDBCLUSTER", DB_TYPE_NDBCLUSTER}, {"EXAMPLE",&have_example_db, "Example storage engine", DB_TYPE_EXAMPLE_DB}, {NullS, NULL, NullS, DB_TYPE_UNKNOWN} @@ -181,6 +188,10 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) case DB_TYPE_EXAMPLE_DB: return new ha_example(table); #endif +#ifdef HAVE_NDBCLUSTER_DB + case DB_TYPE_NDBCLUSTER: + return new ha_ndbcluster(table); +#endif case DB_TYPE_HEAP: return new ha_heap(table); default: // should never happen @@ -225,6 +236,18 @@ int ha_init() opt_using_transactions=1; } #endif +#ifdef HAVE_NDBCLUSTER_DB + if (have_ndbcluster == SHOW_OPTION_YES) + { + if (ndbcluster_init()) + { + have_ndbcluster= SHOW_OPTION_DISABLED; + error= 1; + } + else + opt_using_transactions=1; + } +#endif return error; } @@ -252,6 +275,10 @@ int ha_panic(enum ha_panic_function flag) if (have_innodb == SHOW_OPTION_YES) error|=innobase_end(); #endif +#ifdef HAVE_NDBCLUSTER_DB + if (have_ndbcluster == SHOW_OPTION_YES) + error|=ndbcluster_end(); +#endif return error; } /* ha_panic */ @@ -261,6 +288,10 @@ void ha_drop_database(char* path) if (have_innodb == SHOW_OPTION_YES) innobase_drop_database(path); #endif +#ifdef HAVE_NDBCLUSTER_DB + if (have_ndbcluster == SHOW_OPTION_YES) + ndbcluster_drop_database(path); +#endif } void ha_close_connection(THD* thd) @@ -269,6 +300,10 @@ void ha_close_connection(THD* thd) if (have_innodb == SHOW_OPTION_YES) innobase_close_connection(thd); #endif +#ifdef HAVE_NDBCLUSTER_DB + if (have_ndbcluster == SHOW_OPTION_YES) + ndbcluster_close_connection(thd); +#endif } /* @@ -428,6 +463,19 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) WRITE_CACHE, (my_off_t) 0, 0, 1); thd->transaction.trans_log.end_of_file= max_binlog_cache_size; } +#ifdef HAVE_NDBCLUSTER_DB + if (trans->ndb_tid) + { + if ((error=ndbcluster_commit(thd,trans->ndb_tid))) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); + error=1; + } + if (trans == &thd->transaction.all) + operation_done= transaction_commited= 1; + trans->ndb_tid=0; + } +#endif #ifdef HAVE_BERKELEY_DB if (trans->bdb_tid) { @@ -481,6 +529,18 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) if (opt_using_transactions) { bool operation_done=0; +#ifdef HAVE_NDBCLUSTER_DB + if (trans->ndb_tid) + { + if ((error=ndbcluster_rollback(thd, trans->ndb_tid))) + { + my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error); + error=1; + } + trans->ndb_tid = 0; + operation_done=1; + } +#endif #ifdef HAVE_BERKELEY_DB if (trans->bdb_tid) { @@ -1160,8 +1220,10 @@ bool handler::caching_allowed(THD* thd, char* table_key, ** Some general functions that isn't in the handler class ****************************************************************************/ - /* Initiates table-file and calls apropriate database-creator */ - /* Returns 1 if something got wrong */ +/* + Initiates table-file and calls apropriate database-creator + Returns 1 if something got wrong +*/ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, bool update_create_info) @@ -1177,7 +1239,7 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, { update_create_info_from_table(create_info, &table); if (table.file->table_flags() & HA_DROP_BEFORE_CREATE) - table.file->delete_table(name); // Needed for BDB tables + table.file->delete_table(name); } if (lower_case_table_names == 2 && !(table.file->table_flags() & HA_FILE_BASED)) @@ -1299,6 +1361,26 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, /* + Try to discover one table from handler(s) +*/ + +int ha_discover(const char* dbname, const char* name, + const void** frmblob, uint* frmlen) +{ + int error= 1; // Table does not exist in any handler + DBUG_ENTER("ha_discover"); + DBUG_PRINT("enter", ("db: %s, name: %s", dbname, name)); +#ifdef HAVE_NDBCLUSTER_DB + if (have_ndbcluster == SHOW_OPTION_YES) + error= ndbcluster_discover(dbname, name, frmblob, frmlen); +#endif + if (!error) + statistic_increment(ha_discover_count,&LOCK_status); + DBUG_RETURN(error); +} + + +/* Read first row between two ranges. Store ranges for future calls to read_range_next @@ -1434,3 +1516,5 @@ int handler::compare_key(key_range *range) } return key_compare_result_on_equal; } + + diff --git a/sql/handler.h b/sql/handler.h index 9d39eff1301..62ff74c436a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -28,7 +28,8 @@ #define NO_HASH /* Not yet implemented */ #endif -#if defined(HAVE_BERKELEY_DB) || defined(HAVE_INNOBASE_DB) +#if defined(HAVE_BERKELEY_DB) || defined(HAVE_INNOBASE_DB) || \ + defined(HAVE_NDBCLUSTER_DB) #define USING_TRANSACTIONS #endif @@ -80,7 +81,6 @@ #define HA_FILE_BASED (1 << 26) - /* bits in index_flags(index_number) for what you can do with index */ #define HA_WRONG_ASCII_ORDER 1 /* Can't use sorting through key */ #define HA_READ_NEXT 2 /* Read next record with same key */ @@ -141,12 +141,18 @@ #define HA_CACHE_TBL_ASKTRANSACT 1 #define HA_CACHE_TBL_TRANSACT 2 -enum db_type { DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1, - DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM, - DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM, - DB_TYPE_MRG_ISAM, DB_TYPE_MYISAM, DB_TYPE_MRG_MYISAM, - DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB, DB_TYPE_GEMINI, - DB_TYPE_EXAMPLE_DB, DB_TYPE_DEFAULT }; +enum db_type +{ + DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1, + DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM, + DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM, + DB_TYPE_MRG_ISAM, DB_TYPE_MYISAM, DB_TYPE_MRG_MYISAM, + DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB, + DB_TYPE_GEMINI, DB_TYPE_NDBCLUSTER, + DB_TYPE_EXAMPLE_DB, + + DB_TYPE_DEFAULT // Must be last +}; struct show_table_type_st { const char *type; @@ -176,6 +182,7 @@ typedef struct st_thd_trans { void *bdb_tid; void *innobase_tid; bool innodb_active_trans; + void *ndb_tid; } THD_TRANS; enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED, @@ -479,3 +486,5 @@ bool ha_flush_logs(void); int ha_recovery_logging(THD *thd, bool on); int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); +int ha_discover(const char* dbname, const char* name, + const void** frmblob, uint* frmlen); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 196b54141d1..2d10be62d53 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1356,7 +1356,7 @@ void subselect_uniquesubquery_engine::exclude() table_map subselect_engine::calc_const_tables(TABLE_LIST *table) { table_map map= 0; - for(; table; table= table->next) + for (; table; table= table->next) { TABLE *tbl= table->table; if (tbl && tbl->const_table) diff --git a/sql/item_sum.h b/sql/item_sum.h index 107c19b7d85..9593c8ddbba 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -298,6 +298,7 @@ class Item_sum_avg :public Item_sum_num void update_field(); Item *result_item(Field *field) { return new Item_avg_field(this); } + void no_rows_in_result() {} const char *func_name() const { return "avg"; } Item *copy_or_same(THD* thd); }; diff --git a/sql/lex.h b/sql/lex.h index 3274d544744..64cc6b57464 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -48,7 +48,7 @@ SYM_GROUP sym_group_rtree= {"RTree keys", "HAVE_RTREE_KEYS"}; */ static SYMBOL symbols[] = { - { "&&", SYM(AND)}, + { "&&", SYM(AND_SYM)}, { "<", SYM(LT)}, { "<=", SYM(LE)}, { "<>", SYM(NE)}, @@ -67,7 +67,7 @@ static SYMBOL symbols[] = { { "ALL", SYM(ALL)}, { "ALTER", SYM(ALTER)}, { "ANALYZE", SYM(ANALYZE_SYM)}, - { "AND", SYM(AND)}, + { "AND", SYM(AND_SYM)}, { "ANY", SYM(ANY_SYM)}, { "AS", SYM(AS)}, { "ASC", SYM(ASC)}, @@ -296,6 +296,8 @@ static SYMBOL symbols[] = { { "NAMES", SYM(NAMES_SYM)}, { "NATIONAL", SYM(NATIONAL_SYM)}, { "NATURAL", SYM(NATURAL)}, + { "NDB", SYM(NDBCLUSTER_SYM)}, + { "NDBCLUSTER", SYM(NDBCLUSTER_SYM)}, { "NCHAR", SYM(NCHAR_SYM)}, { "NEW", SYM(NEW_SYM)}, { "NEXT", SYM(NEXT_SYM)}, @@ -313,7 +315,7 @@ static SYMBOL symbols[] = { { "OPTIMIZE", SYM(OPTIMIZE)}, { "OPTION", SYM(OPTION)}, { "OPTIONALLY", SYM(OPTIONALLY)}, - { "OR", SYM(OR)}, + { "OR", SYM(OR_SYM)}, { "ORDER", SYM(ORDER_SYM)}, { "OUTER", SYM(OUTER)}, { "OUTFILE", SYM(OUTFILE)}, diff --git a/sql/log_event.cc b/sql/log_event.cc index 3b92e0956ba..207f4a51ff4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -923,15 +923,15 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) (ulong) thread_id, (ulong) exec_time, error_code); } - bool same_db = 0; + bool different_db= 1; if (db && last_db) { - if (!(same_db = !memcmp(last_db, db, db_len + 1))) + if (different_db= memcmp(last_db, db, db_len + 1)) memcpy(last_db, db, db_len + 1); } - if (db && db[0] && !same_db) + if (db && db[0] && different_db) fprintf(file, "use %s;\n", db); end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10); *end++=';'; @@ -960,8 +960,10 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) position to store is of the END of the current log event. */ #if MYSQL_VERSION_ID < 50000 - rli->future_group_master_log_pos= log_pos + get_event_len(); + rli->future_group_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #else + /* In 5.0 we store the end_log_pos in the relay log so no problem */ rli->future_group_master_log_pos= log_pos; #endif clear_all_errors(thd, rli); @@ -1165,6 +1167,11 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) { DBUG_ENTER("Start_log_event::exec_event"); + /* + If the I/O thread has not started, mi->old_format is BINLOG_FORMAT_CURRENT + (that's what the MASTER_INFO constructor does), so the test below is not + perfect at all. + */ switch (rli->mi->old_format) { case BINLOG_FORMAT_CURRENT: /* @@ -1542,14 +1549,21 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db, thread_id, exec_time); } - bool same_db = 0; + bool different_db= 1; if (db && last_db) { - if (!(same_db = !memcmp(last_db, db, db_len + 1))) + /* + If the database is different from the one of the previous statement, we + need to print the "use" command, and we update the last_db. + But if commented, the "use" is going to be commented so we should not + update the last_db. + */ + if ((different_db= memcmp(last_db, db, db_len + 1)) && + !commented) memcpy(last_db, db, db_len + 1); } - if (db && db[0] && !same_db) + if (db && db[0] && different_db) fprintf(file, "%suse %s;\n", commented ? "# " : "", db); @@ -1667,7 +1681,8 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, if (!use_rli_only_for_errors) { #if MYSQL_VERSION_ID < 50000 - rli->future_group_master_log_pos= log_pos + get_event_len(); + rli->future_group_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #else rli->future_group_master_log_pos= log_pos; #endif @@ -3138,9 +3153,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) */ #if MYSQL_VERSION_ID < 40100 - rli->future_master_log_pos= log_pos + get_event_len(); + rli->future_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #elif MYSQL_VERSION_ID < 50000 - rli->future_group_master_log_pos= log_pos + get_event_len(); + rli->future_group_master_log_pos= log_pos + get_event_len() - + (rli->mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); #else rli->future_group_master_log_pos= log_pos; #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 00af3c67c7e..4381ea1f93e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -839,7 +839,7 @@ extern ulong server_id, concurrency; extern ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count; extern ulong ha_read_key_count, ha_read_next_count, ha_read_prev_count; extern ulong ha_read_first_count, ha_read_last_count; -extern ulong ha_read_rnd_count, ha_read_rnd_next_count; +extern ulong ha_read_rnd_count, ha_read_rnd_next_count, ha_discover_count; extern ulong ha_commit_count, ha_rollback_count,table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong slave_net_timeout; @@ -893,6 +893,7 @@ extern SHOW_VAR init_vars[],status_vars[], internal_vars[]; extern SHOW_COMP_OPTION have_isam; extern SHOW_COMP_OPTION have_innodb; extern SHOW_COMP_OPTION have_berkeley_db; +extern SHOW_COMP_OPTION have_ndbcluster; extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; extern struct rand_struct sql_rand; @@ -962,6 +963,10 @@ int format_number(uint inputflag,uint max_length,my_string pos,uint length, my_string *errpos); int openfrm(const char *name,const char *alias,uint filestat,uint prgflag, uint ha_open_flags, TABLE *outparam); +int readfrm(const char *name, const void** data, uint* length); +int writefrm(const char* name, const void* data, uint len); +int create_table_from_handler(const char *db, const char *name, + bool create_if_found); int closefrm(TABLE *table); db_type get_table_type(const char *name); int read_string(File file, gptr *to, uint length); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2468deb2cc7..2878654b759 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -32,6 +32,9 @@ #ifdef HAVE_ISAM #include "ha_isam.h" #endif +#ifdef HAVE_NDBCLUSTER_DB +#include "ha_ndbcluster.h" +#endif #include <nisam.h> #include <thr_alarm.h> #include <ft_global.h> @@ -261,7 +264,7 @@ my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; my_bool opt_log_slave_updates= 0; -my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam; +my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster; my_bool opt_readonly, use_temp_pool, relay_log_purge; my_bool opt_sync_bdb_logs, opt_sync_frm; my_bool opt_secure_auth= 0; @@ -370,7 +373,8 @@ KEY_CACHE *sql_key_cache; CHARSET_INFO *system_charset_info, *files_charset_info ; CHARSET_INFO *national_charset_info, *table_alias_charset; -SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam, have_example_db; +SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam, + have_ndbcluster, have_example_db; SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache; SHOW_COMP_OPTION have_crypt, have_compress; @@ -3625,7 +3629,7 @@ enum options_mysqld OPT_INNODB_FAST_SHUTDOWN, OPT_INNODB_FILE_PER_TABLE, OPT_SAFE_SHOW_DB, - OPT_INNODB, OPT_ISAM, OPT_SKIP_SAFEMALLOC, + OPT_INNODB, OPT_ISAM, OPT_NDBCLUSTER, OPT_SKIP_SAFEMALLOC, OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS, OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, @@ -4158,6 +4162,10 @@ Disable with --skip-innodb (will save memory).", Disable with --skip-isam.", (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"ndbcluster", OPT_NDBCLUSTER, "Enable NDB Cluster (if this version of MySQL supports it). \ +Disable with --skip-ndbcluster (will save memory).", + (gptr*) &opt_ndbcluster, (gptr*) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 1, 0, 0, + 0, 0, 0}, {"skip-locking", OPT_SKIP_LOCK, "Deprecated option, use --skip-external-locking instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -4831,6 +4839,7 @@ struct show_var_st status_vars[]= { {"Handler_rollback", (char*) &ha_rollback_count, SHOW_LONG}, {"Handler_update", (char*) &ha_update_count, SHOW_LONG}, {"Handler_write", (char*) &ha_write_count, SHOW_LONG}, + {"Handler_discover", (char*) &ha_discover_count, SHOW_LONG}, {"Key_blocks_not_flushed", (char*) &dflt_key_cache_var.global_blocks_changed, SHOW_KEY_CACHE_LONG}, {"Key_blocks_used", (char*) &dflt_key_cache_var.global_blocks_used, @@ -5129,6 +5138,11 @@ static void mysql_init_variables(void) #else have_example_db= SHOW_OPTION_NO; #endif +#ifdef HAVE_NDBCLUSTER_DB + have_ndbcluster=SHOW_OPTION_DISABLED; +#else + have_ndbcluster=SHOW_OPTION_NO; +#endif #ifdef USE_RAID have_raid=SHOW_OPTION_YES; #else @@ -5599,6 +5613,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), have_isam= SHOW_OPTION_DISABLED; #endif break; + case OPT_NDBCLUSTER: +#ifdef HAVE_NDBCLUSTER_DB + if (opt_ndbcluster) + have_ndbcluster=SHOW_OPTION_YES; + else + have_ndbcluster=SHOW_OPTION_DISABLED; +#endif + break; case OPT_INNODB: #ifdef HAVE_INNOBASE_DB if (opt_innodb) diff --git a/sql/set_var.cc b/sql/set_var.cc index 5ccda5c7052..1339bdc887f 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -59,6 +59,9 @@ #ifdef HAVE_INNOBASE_DB #include "ha_innodb.h" #endif +#ifdef HAVE_NDBCLUSTER_DB +#include "ha_ndbcluster.h" +#endif static HASH system_variable_hash; const char *bool_type_names[]= { "OFF", "ON", NullS }; @@ -638,6 +641,7 @@ struct show_var_st init_vars[]= { {"have_crypt", (char*) &have_crypt, SHOW_HAVE}, {"have_innodb", (char*) &have_innodb, SHOW_HAVE}, {"have_isam", (char*) &have_isam, SHOW_HAVE}, + {"have_ndbcluster", (char*) &have_ndbcluster, SHOW_HAVE}, {"have_openssl", (char*) &have_openssl, SHOW_HAVE}, {"have_query_cache", (char*) &have_query_cache, SHOW_HAVE}, {"have_raid", (char*) &have_raid, SHOW_HAVE}, @@ -1090,9 +1094,9 @@ static void fix_max_relay_log_size(THD *thd, enum_var_type type) static int check_max_delayed_threads(THD *thd, set_var *var) { - int val= var->value->val_int(); + longlong val= var->value->val_int(); if (var->type != OPT_GLOBAL && val != 0 && - val != global_system_variables.max_insert_delayed_threads) + val != (longlong) global_system_variables.max_insert_delayed_threads) { char buf[64]; my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, llstr(val, buf)); @@ -1101,6 +1105,7 @@ static int check_max_delayed_threads(THD *thd, set_var *var) return 0; } + static void fix_max_connections(THD *thd, enum_var_type type) { resize_thr_alarm(max_connections + diff --git a/sql/slave.cc b/sql/slave.cc index 67b9c7515e1..061c737b538 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -361,6 +361,55 @@ void init_slave_skip_errors(const char* arg) } } + +void st_relay_log_info::inc_group_relay_log_pos(ulonglong val, + ulonglong log_pos, + bool skip_lock) +{ + if (!skip_lock) + pthread_mutex_lock(&data_lock); + inc_event_relay_log_pos(val); + group_relay_log_pos= event_relay_log_pos; + strmake(group_relay_log_name,event_relay_log_name, + sizeof(group_relay_log_name)-1); + + notify_group_relay_log_name_update(); + + /* + If the slave does not support transactions and replicates a transaction, + users should not trust group_master_log_pos (which they can display with + SHOW SLAVE STATUS or read from relay-log.info), because to compute + group_master_log_pos the slave relies on log_pos stored in the master's + binlog, but if we are in a master's transaction these positions are always + the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does + not advance as it should on the non-transactional slave (it advances by + big leaps, whereas it should advance by small leaps). + */ + if (log_pos) // 3.23 binlogs don't have log_posx + { +#if MYSQL_VERSION_ID < 50000 + /* + If the event was converted from a 3.23 format, get_event_len() has + grown by 6 bytes (at least for most events, except LOAD DATA INFILE + which is already a big problem for 3.23->4.0 replication); 6 bytes is + the difference between the header's size in 4.0 (LOG_EVENT_HEADER_LEN) + and the header's size in 3.23 (OLD_HEADER_LEN). Note that using + mi->old_format will not help if the I/O thread has not started yet. + Yes this is a hack but it's just to make 3.23->4.x replication work; + 3.23->5.0 replication is working much better. + */ + group_master_log_pos= log_pos + val - + (mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0); +#else + group_master_log_pos= log_pos+ val; +#endif /* MYSQL_VERSION_ID < 5000 */ + } + pthread_cond_broadcast(&data_cond); + if (!skip_lock) + pthread_mutex_unlock(&data_lock); +} + + void st_relay_log_info::close_temporary_tables() { TABLE *table,*next; @@ -3473,8 +3522,16 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf, DBUG_RETURN(1); } memcpy(tmp_buf,buf,event_len); - tmp_buf[event_len]=0; // Create_file constructor wants null-term buffer + /* + Create_file constructor wants a 0 as last char of buffer, this 0 will + serve as the string-termination char for the file's name (which is at the + end of the buffer) + We must increment event_len, otherwise the event constructor will not see + this end 0, which leads to segfault. + */ + tmp_buf[event_len++]=0; buf = (const char*)tmp_buf; + int4store(buf+EVENT_LEN_OFFSET, event_len); } /* This will transform LOAD_EVENT into CREATE_FILE_EVENT, ask the master to @@ -3520,7 +3577,11 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf, DBUG_ASSERT(tmp_buf); int error = process_io_create_file(mi,(Create_file_log_event*)ev); delete ev; - mi->master_log_pos += event_len; + /* + We had incremented event_len, but now when it is used to calculate the + position in the master's log, we must use the original value. + */ + mi->master_log_pos += --event_len; DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos)); pthread_mutex_unlock(&mi->data_lock); my_free((char*)tmp_buf, MYF(0)); diff --git a/sql/slave.h b/sql/slave.h index 549ceb5d42c..c925831d1a5 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -291,34 +291,7 @@ typedef struct st_relay_log_info event_relay_log_pos+= val; } - void inc_group_relay_log_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0) - { - if (!skip_lock) - pthread_mutex_lock(&data_lock); - inc_event_relay_log_pos(val); - group_relay_log_pos= event_relay_log_pos; - strmake(group_relay_log_name,event_relay_log_name, - sizeof(group_relay_log_name)-1); - - notify_group_relay_log_name_update(); - - /* - If the slave does not support transactions and replicates a transaction, - users should not trust group_master_log_pos (which they can display with - SHOW SLAVE STATUS or read from relay-log.info), because to compute - group_master_log_pos the slave relies on log_pos stored in the master's - binlog, but if we are in a master's transaction these positions are always - the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does - not advance as it should on the non-transactional slave (it advances by - big leaps, whereas it should advance by small leaps). - */ - if (log_pos) // 3.23 binlogs don't have log_posx - group_master_log_pos= log_pos+ val; - pthread_cond_broadcast(&data_cond); - if (!skip_lock) - pthread_mutex_unlock(&data_lock); - } - + void inc_group_relay_log_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0); int wait_for_pos(THD* thd, String* log_name, longlong log_pos, longlong timeout); void close_temporary_tables(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8c4571dd540..d24b13ff96f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1317,18 +1317,34 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, { char path[FN_REFLEN]; int error; + uint discover_retry_count= 0; DBUG_ENTER("open_unireg_entry"); strxmov(path, mysql_data_home, "/", db, "/", name, NullS); - if (openfrm(path,alias, + while (openfrm(path,alias, (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX | HA_TRY_READ_ONLY), READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, thd->open_options, entry)) { if (!entry->crashed) - goto err; // Can't repair the table + { + /* + Frm file could not be found on disk + Since it does not exist, no one can be using it + LOCK_open has been locked to protect from someone else + trying to discover the table at the same time. + */ + if (discover_retry_count++ != 0) + goto err; + if (create_table_from_handler(db, name, true) != 0) + goto err; + + thd->clear_error(); // Clear error message + continue; + } + // Code below is for repairing a crashed file TABLE_LIST table_list; bzero((char*) &table_list, sizeof(table_list)); // just for safe table_list.db=(char*) db; @@ -1374,6 +1390,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, if (error) goto err; + break; } /* If we are here, there was no fatal error (but error may be still diff --git a/sql/sql_class.h b/sql/sql_class.h index 8ccfe3cddd5..97baf47a8cb 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -703,7 +703,10 @@ public: THD_TRANS all; // Trans since BEGIN WORK THD_TRANS stmt; // Trans for current statement uint bdb_lock_count; - + uint ndb_lock_count; +#ifdef HAVE_NDBCLUSTER_DB + void* ndb; +#endif /* Tables changed in transaction (that must be invalidated in query cache). List contain only transactional tables, that not invalidated in query @@ -893,7 +896,8 @@ public: { #ifdef USING_TRANSACTIONS return (transaction.all.bdb_tid != 0 || - transaction.all.innodb_active_trans != 0); + transaction.all.innodb_active_trans != 0 || + transaction.all.ndb_tid != 0); #else return 0; #endif diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 51b875385f1..a6bd1955fa5 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -551,7 +551,12 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, If the directory is a symbolic link, remove the link first, then remove the directory the symbolic link pointed at */ - if (!found_other_files) + if (found_other_files) + { + my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST); + DBUG_RETURN(-1); + } + else { char tmp_path[FN_REFLEN], *pos; char *path= tmp_path; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index e0e8fed29c8..19a6941fe32 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -879,13 +879,15 @@ int yylex(void *arg, void *yythd) } yySkip(); return (SET_VAR); - case MY_LEX_COLON: // optional line terminator + case MY_LEX_SEMICOLON: // optional line terminator if (yyPeek()) { - if (((THD *)yythd)->client_capabilities & CLIENT_MULTI_STATEMENTS) + THD* thd= (THD*)yythd; + if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) && + (thd->command != COM_PREPARE)) { lex->found_colon=(char*)lex->ptr; - ((THD *)yythd)->server_status |= SERVER_MORE_RESULTS_EXISTS; + thd->server_status |= SERVER_MORE_RESULTS_EXISTS; lex->next_state=MY_LEX_END; return(END_OF_INPUT); } @@ -1529,7 +1531,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) */ bool st_select_lex_unit::check_updateable(char *db, char *table) { - for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) if (sl->check_updateable(db, table)) return 1; return 0; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 64fa398e5f4..34d0d2b31f9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5260,5 +5260,5 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables, DBUG_RETURN(1); DBUG_RETURN((grant_option && want_priv != CREATE_TMP_ACL && check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) ? - 1 : 0) + 1 : 0); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e87a37150ea..448dc825a26 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -181,7 +181,7 @@ int mysqld_show_storage_engines(THD *thd) Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_storage_engines"); - field_list.push_back(new Item_empty_string("Type",10)); + field_list.push_back(new Item_empty_string("Engine",10)); field_list.push_back(new Item_empty_string("Support",10)); field_list.push_back(new Item_empty_string("Comment",80)); @@ -471,7 +471,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) (void) sprintf(path,"%s/%s",mysql_data_home,db); (void) unpack_dirname(path,path); field_list.push_back(item=new Item_empty_string("Name",NAME_LEN)); - field_list.push_back(item=new Item_empty_string("Type",10)); + field_list.push_back(item=new Item_empty_string("Engine",10)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Row_format",10)); item->maybe_null=1; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index a4eae8a6346..8a093738e2b 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -830,7 +830,7 @@ outp: void String::print(String *str) { char *st= (char*)Ptr, *end= st+str_length; - for(; st < end; st++) + for (; st < end; st++) { uchar c= *st; switch (c) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d5f77bf545d..c46a9823a52 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1148,6 +1148,35 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } } + /* + Check that table with given name does not already + exist in any storage engine. In such a case it should + be discovered and the error ER_TABLE_EXISTS_ERROR be returned + unless user specified CREATE TABLE IF EXISTS + The LOCK_open mutex has been locked to make sure no + one else is attempting to discover the table. Since + it's not on disk as a frm file, no one could be using it! + */ + if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) + { + bool create_if_not_exists = + create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS; + if (!create_table_from_handler(db, table_name, + create_if_not_exists)) + { + DBUG_PRINT("info", ("Table already existed in handler")); + + if (create_if_not_exists) + { + create_info->table_existed= 1; // Mark that table existed + error= 0; + } + else + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + goto end; + } + } + thd->proc_info="creating table"; create_info->table_existed= 0; // Mark that table is created diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a25bd3f17bc..247bec84e8e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -181,7 +181,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token ACTION %token AGGREGATE_SYM %token ALL -%token AND +%token AND_SYM %token AS %token ASC %token AUTO_INC @@ -305,6 +305,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token NAMES_SYM %token NATIONAL_SYM %token NATURAL +%token NDBCLUSTER_SYM %token NEW_SYM %token NCHAR_SYM %token NCHAR_STRING @@ -318,7 +319,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token OPEN_SYM %token OPTION %token OPTIONALLY -%token OR +%token OR_SYM %token OR_OR_CONCAT %token ORDER_SYM %token OUTER @@ -576,8 +577,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token BEFORE_SYM %left SET_VAR -%left OR_OR_CONCAT OR XOR -%left AND +%left OR_OR_CONCAT OR_SYM XOR +%left AND_SYM %left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE %left EQ EQUAL_SYM GE GT_SYM LE LT NE IS LIKE REGEXP IN_SYM %left '|' @@ -730,7 +731,7 @@ END_OF_INPUT %type <NONE> '-' '+' '*' '/' '%' '(' ')' - ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM + ',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_CONCAT BETWEEN_SYM CASE_SYM THEN_SYM WHEN_SYM DIV_SYM MOD_SYM %% @@ -2493,14 +2494,14 @@ expr_expr: { $$= new Item_func_not(new Item_in_subselect($1, $4)); } - | expr BETWEEN_SYM no_and_expr AND expr + | expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } - | expr NOT BETWEEN_SYM no_and_expr AND expr + | expr NOT BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } - | expr OR expr { $$= new Item_cond_or($1,$3); } + | expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } - | expr AND expr { $$= new Item_cond_and($1,$3); } + | expr AND_SYM expr { $$= new Item_cond_and($1,$3); } | expr SOUNDS_SYM LIKE expr { $$= new Item_func_eq(new Item_func_soundex($1), @@ -2541,14 +2542,14 @@ expr_expr: /* expressions that begin with 'expr' that do NOT follow IN_SYM */ no_in_expr: - no_in_expr BETWEEN_SYM no_and_expr AND expr + no_in_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } - | no_in_expr NOT BETWEEN_SYM no_and_expr AND expr + | no_in_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } - | no_in_expr OR expr { $$= new Item_cond_or($1,$3); } + | no_in_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } - | no_in_expr AND expr { $$= new Item_cond_and($1,$3); } + | no_in_expr AND_SYM expr { $$= new Item_cond_and($1,$3); } | no_in_expr SOUNDS_SYM LIKE expr { $$= new Item_func_eq(new Item_func_soundex($1), @@ -2599,12 +2600,12 @@ no_and_expr: { $$= new Item_func_not(new Item_in_subselect($1, $4)); } - | no_and_expr BETWEEN_SYM no_and_expr AND expr + | no_and_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } - | no_and_expr NOT BETWEEN_SYM no_and_expr AND expr + | no_and_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } - | no_and_expr OR expr { $$= new Item_cond_or($1,$3); } + | no_and_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } | no_and_expr SOUNDS_SYM LIKE expr { @@ -4219,8 +4220,8 @@ show_param: YYABORT; } | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ - TEXT_STRING_sys AND MASTER_LOG_POS_SYM EQ ulonglong_num - AND MASTER_SERVER_ID_SYM EQ + TEXT_STRING_sys AND_SYM MASTER_LOG_POS_SYM EQ ulonglong_num + AND_SYM MASTER_SERVER_ID_SYM EQ ULONG_NUM { Lex->sql_command = SQLCOM_SHOW_NEW_MASTER; @@ -5056,6 +5057,7 @@ keyword: | NAMES_SYM {} | NATIONAL_SYM {} | NCHAR_SYM {} + | NDBCLUSTER_SYM {} | NEXT_SYM {} | NEW_SYM {} | NO_SYM {} @@ -5508,7 +5510,7 @@ grant_privilege: opt_and: /* empty */ {} - | AND {} + | AND_SYM {} ; require_list: diff --git a/sql/table.cc b/sql/table.cc index 1b7d30560ef..281a8c10409 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -944,7 +944,8 @@ static void frm_error(int error, TABLE *form, const char *name, myf errortype) break; case 2: { - datext=form->file ? *form->file->bas_ext() : ""; + datext= form->file ? *form->file->bas_ext() : ""; + datext= datext==NullS ? "" : datext; err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ? ER_FILE_USED : ER_CANT_OPEN_FILE; my_error(err_no,errortype, diff --git a/sql/unireg.h b/sql/unireg.h index 442809a9e08..4ab2ba26b15 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -48,7 +48,7 @@ #define MAX_ALIAS_NAME 256 #define MAX_FIELD_NAME 34 /* Max colum name length +2 */ #define MAX_SYS_VAR_LENGTH 32 -#define MAX_KEY 32 /* Max used keys */ +#define MAX_KEY 64 /* Max used keys */ #define MAX_REF_PARTS 16 /* Max parts used as ref */ #define MAX_KEY_LENGTH 1024 /* max possible key */ #if SIZEOF_OFF_T > 4 diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index fe5dae3dbf6..8583b623392 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -23,6 +23,7 @@ Packager: Lenz Grimmer <build@mysql.com> Vendor: MySQL AB Requires: fileutils sh-utils Provides: msqlormysql MySQL-server mysql +BuildPrereq: ncurses-devel Obsoletes: mysql # Think about what you use here since the first step is to @@ -577,6 +578,10 @@ fi # The spec file changelog only includes changes made to the spec file # itself %changelog +* Mon Apr 05 2004 Lenz Grimmer <lenz@mysql.com> + +- added ncurses-devel to the build prerequisites (BUG 3377) + * Thu Feb 12 2004 Lenz Grimmer <lenz@mysql.com> - when using gcc, _always_ use CXX=gcc diff --git a/tests/client_test.c b/tests/client_test.c index 6e8fcca1053..000b55a202e 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -4940,6 +4940,34 @@ DROP TABLE IF EXISTS test_multi_tab"; mysql_close(mysql_local); } +/******************************************************** +* Check that Prepared statement cannot contain several * +* SQL statements * +*********************************************************/ +static void test_prepare_multi_statements() +{ + MYSQL *mysql_local; + MYSQL_STMT *stmt; + myheader("test_prepare_multi_statements"); + + if (!(mysql_local = mysql_init(NULL))) + { + fprintf(stdout,"\n mysql_init() failed"); + exit(1); + } + + if (!(mysql_real_connect(mysql_local,opt_host,opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_STATEMENTS))) + { + fprintf(stdout,"\n connection failed(%s)", mysql_error(mysql_local)); + exit(1); + } + strmov(query, "select 1; select 'another value'"); + stmt = mysql_simple_prepare(mysql_local,query); + mystmt_init_r(stmt); + mysql_close(mysql_local); +} /******************************************************** * to test simple bind store result * @@ -6735,7 +6763,7 @@ static void test_explain_bug() "","","",10,0); verify_prepare_field(result,4,"possible_keys","",MYSQL_TYPE_VAR_STRING, - "","","",NAME_LEN*32,0); + "","","",NAME_LEN*64,0); verify_prepare_field(result,5,"key","",MYSQL_TYPE_VAR_STRING, "","","",NAME_LEN,0); @@ -9210,6 +9238,8 @@ int main(int argc, char **argv) test_prepare_field_result(); /* prepare meta info */ test_multi_stmt(); /* multi stmt test */ test_multi_statements();/* test multi statement execution */ + test_prepare_multi_statements(); /* check that multi statements are + disabled in PS */ test_store_result(); /* test the store_result */ test_store_result1(); /* test store result without buffers */ test_store_result2(); /* test store result for misc case */ |