diff --git a/.bzrignore b/.bzrignore index 379f5401021..17fee4a6fc1 100644 --- a/.bzrignore +++ b/.bzrignore @@ -581,3 +581,4 @@ vio/test-sslserver vio/viotest-ssl libmysqld/protocol.cc test_xml +extra/mysql_waitpid diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index e3da1e2292e..2e693cab134 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -17,6 +17,7 @@ bell@sanja.is.com.ua bk@admin.bk davida@isil.mysql.com gluh@gluh.(none) +gluh@gluh.mysql.r18.ru heikki@donna.mysql.fi heikki@hundin.mysql.fi heikki@rescue. diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index 4351a4f69f4..8695c72b913 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -135,6 +135,7 @@ $ENV{'MYSQL_UNIX_PORT'}=$mysql_unix_port="$opt_tmp/mysql$opt_suffix.build"; $ENV{"PERL5LIB"}="$pwd/$host/perl5:$pwd/$host/perl5/site_perl"; $slave_port=$mysql_tcp_port+16; $manager_port=$mysql_tcp_port+1; +$mysqladmin_args="--no-defaults -u root --connect_timeout=5 --shutdown_timeout=20"; if ($opt_stage == 0) { @@ -154,13 +155,18 @@ log_timestamp(); if (-x "$host/bin/mysqladmin") { - log_system("$host/bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown"); - log_system("$host/bin/mysqladmin --no-defaults -u root -P $mysql_tcp_port -h $host -s shutdown"); - log_system("$host/bin/mysqladmin --no-defaults -u root -P $slave_port -h $host -s shutdown"); - log_system("$host/bin/mysqladmin --no-defaults -u root -P 9306 -h $host -s shutdown"); - log_system("$host/bin/mysqladmin --no-defaults -u root -P 9307 -h $host -s shutdown"); + log_system("$host/bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -s shutdown"); + log_system("$host/bin/mysqladmin $mysqladmin_args -P $mysql_tcp_port -h $host -s shutdown"); + log_system("$host/bin/mysqladmin $mysqladmin_args -P $slave_port -h $host -s shutdown"); + log_system("$host/bin/mysqladmin $mysqladmin_args -P 9306 -h $host -s shutdown"); + log_system("$host/bin/mysqladmin $mysqladmin_args -P 9307 -h $host -s shutdown"); } kill_all("mysqlmanager"); +# +# Kill all old processes that are in the build directories +# This is to find any old mysqld servers left from previous builds +kill_all("$pwd/host/mysql"); +kill_all("$pwd/host/test"); if ($opt_stage == 0) { @@ -308,8 +314,9 @@ if ($opt_stage <= 4 && !$opt_no_test) $tar_file =~ /(mysql[^\/]*)\.tar/; $ver=$1; $test_dir="$pwd/$host/test/$ver"; -$ENV{"LD_LIBRARY_PATH"}= "$test_dir/lib:" . $ENV{"LD_LIBRARY_PATH"}; - +$ENV{"LD_LIBRARY_PATH"}= ("$test_dir/lib" . + (defined($ENV{"LD_LIBRARY_PATH"}) ? + ":" . $ENV{"LD_LIBRARY_PATH"} : "")); # # Run the test suite # @@ -328,7 +335,7 @@ if (!$opt_no_test && !$opt_no_benchmark) { my $extra; safe_cd($test_dir); - log_system("./bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown") || info("There was no mysqld running\n"); + log_system("./bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -s shutdown") || info("There was no mysqld running\n"); sleep(2); log_system("rm -f ./data/mysql/*"); check_system("scripts/mysql_install_db --no-defaults --skip-locking","https://order"); @@ -418,7 +425,7 @@ if ($opt_stage <= 9 && !$opt_no_test && !$opt_no_benchmark) rm_all($bench_tmpdir); rm_all("$opt_tmp") if ($new_opt_tmp); -log_system("$pwd/$host/bin/mysqladmin --no-defaults -S $mysql_unix_port -u root shutdown"); +log_system("$pwd/$host/bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -u root shutdown"); print LOG "ok\n"; close LOG; print "$host: ok\n"; @@ -429,7 +436,7 @@ exit 0; sub usage { print < +@set _extra_head + +@settitle MySQL Prepared Statements + +@c We want single-sided heading format, with chapters on new pages. To +@c get double-sided format change 'on' below to 'odd' +@ifclear nusphere +@setchapternewpage on +@end ifclear + +@ifset nusphere +@setchapternewpage odd +@end ifset + +@c @paragraphindent 0 + +@ifset nusphere +@smallbook +@end ifset + +@c @titlepage +@c @sp 10 +@c @center @titlefont{MySQL Prepared Statements} +@c @sp 10 +@c @right Copyright @copyright{} 1995-2003 MySQL AB +@c blank page after title page makes page 1 be a page front. +@c also makes the back of the title page blank. +@c @page +@c @end titlepage + +@c Short contents, blank page, long contents. +@c until i can figure out the blank page, no short contents. +@c @shortcontents +@c @page +@c @page +@contents + +@c This should be added. The HTML conversion also needs a MySQL version +@c number somewhere. + +@iftex +@c change this to double if you want formatting for double-sided +@c printing +@headings single +@end iftex + +@c @node Top, MySQL C API, (dir), (dir) + +@c @menu +@c * MySQL C API:: +@c @end menu + +@c @node MySQL C API, , Top, Top +@c @chapter MySQL C API + +@c @menu +@c * Prepared statements:: +@c @end menu + +@node Top, MySQL prepared statements, (dir), (dir) + +@menu +* MySQL prepared statements:: +@end menu + +@node MySQL prepared statements, , Top, Top +@chapter MySQL Prepared Statements + +@menu +* C Prepared statements:: +* C Prepared statement datatypes:: +* C Prepared statements function overview:: +* C Prepared statement functions:: +@end menu + +@node C Prepared statements, C Prepared statement datatypes, MySQL prepared statements, MySQL prepared statements +@subsection C Prepared Statements + +@sp 1 + +From MySQL 4.1 and above, you can also make use of the prepared +statements using the statement handler 'MYSQL_STMT', which supports +simultanious query executions along with input and output binding. + +@sp 1 + +Prepared execution is an efficient way to execute a statement more than +once. The statement is first parsed, or prepared. This is executed one +or more times at a later time using the statement handle that is +returned during the prepare. + +@sp 1 + +Another advantage of prepared statements is that, it uses a binary protocol +which makes the data tranfer between client and server in a more efficient +way than the old MySQL protocol. + +@sp 1 + +Prepared execution is faster than direct execution for statements +executed more than once, primarly becuase the query is parsed only +once; In the case of direct execution, the query is parsed every +time. Prepared execution also can provide a reduction in the network +traffic becuase during the execute call, it only sends the data for the +parameters. + + + +@node C Prepared statement datatypes, C Prepared statements function overview, C Prepared statements, MySQL prepared statements +@subsection C Prepared Statements DataTypes + +Prepared statements mainly uses the following two @code{MYSQL_STMT} and +@code{MYSQL_BIND} structures: +@sp 1 + +@table @code +@tindex MYSQL C type +@item MYSQL_STMT +This structure represents a statement handle to prepared statements.It +is used for all statement related functions. + +@sp 1 + +The statement is initialized when the query is prepared using +@code{mysql_prepare()}. + +@sp 1 + +One connection can have 'n' statement handles, and the limit depends up on +the system resources. + +@sp 1 + +@tindex MYSQL_BIND C type +@item MYSQL_BIND +This structure is used in order to bind parameter buffers inorder to +send the parameters data to @code{mysql_execute()} call; as well as to +bind row buffers to fetch the result set data using @code{mysql_fetch()}. +@end table + +@sp 1 + +@noindent +The @code{MYSQL_BIND} structure contains the members listed here: + + +@table @code +@item enum enum_field_types buffer_type [input] +The type of the buffer. The @code{type} value must be one of the following: + + +@itemize @bullet +@item @code{MYSQL_TYPE_TINY} +@item @code{MYSQL_TYPE_SHORT} +@item @code{MYSQL_TYPE_LONG} +@item @code{MYSQL_TYPE_LONGLONG} +@item @code{MYSQL_TYPE_FLOAT} +@item @code{MYSQL_TYPE_DOUBLE} +@item @code{MYSQL_TYPE_STRING} +@item @code{MYSQL_TYPE_VAR_STRING} +@item @code{MYSQL_TYPE_TINY_BLOB} +@item @code{MYSQL_TYPE_MEDIUM_BLOB} +@item @code{MYSQL_TYPE_LONG_BLOB} +@item @code{MYSQL_TYPE_BLOB} +@end itemize +@sp 1 + +@item void *buffer [input/output] +A pointer to a buffer for the parameters data in case if it is used to +supply parameters data or pointer to a buffer in which to return the +data when the structure is used for result set bind. + +@sp 1 + +@item long *length [input/output] +Pointer to the buffer for the parameter's length. When the structure is +used as a input parameter data binding, then this argument points to a +buffer that, when @code{mysql_execute()} is called, contains one of the +following: + +@itemize @bullet +@item +The length of the parameter value stored in *buffer. This is ignored +except for character or binary C data. +@item +MYSQL_NULL_DATA. The parameter value is NULL. +@item +MYSQL_LONG_DATA. The parameter value is a long data and is supplied in +chunks through @code{mysql_send_long_data()}. +@end itemize + +If the length is a null pointer, then the protocol assumes that all +input parameter values are non-NULL and that character and binary data +are null terminated. + + +When this structure is used in output binding, then @code{mysql_fetch()} +return the following values in the length buffer: + +@itemize @bullet +@item +The length of the data that is returned +@item +MYSQL_NULL_DATA, indicating the data returned is a NULL data. +@end itemize + + +@c @item bool is_null [input] +@c To indicate the parameter data is NULL. This is same as supplying +@c MYSQL_NULL_DATA, -1 as the length in length pointer. + + +@c @item bool is_long_data [input] +@c To indicate the parameter data is a long data, and the data will be +@c supplied in chunks through @code{mysql_send_long_data()}.This is also +@c same as supplying MYSQL_LONG_DATA, -2 as the length in length pointer. +@c @end table +@end table + + +@node C Prepared statements function overview, C Prepared statement functions, C Prepared statement datatypes, MySQL prepared statements +@subsection C Prepared Statements Function Overview + +@cindex C Prepared statements API, functions +@cindex functions, C Prepared statements API + +The functions available in the prepared statements are listed here and +are described in greater detail in the later section. +@xref{C Prepared statement functions}. + +@multitable @columnfractions .32 .68 +@item @strong{Function} @tab @strong{Description} + +@item @strong{mysql_prepare()} @tab Prepares an SQL string for execution. + +@item @strong{mysql_param_count()} @tab Returns the number of parameters in a prepared SQL statement. + +@item @strong{mysql_prepare_result()} @tab Returns prepared statement meta information in the form of resultset. + +@item @strong{mysql_bind_param()} @tab Binds a buffer to parameter markers in a prepared SQL statement. + +@item @strong{mysql_execute()} @tab Executes the prepared statement. + +@item @strong{mysql_stmt_affected_rows()} @tab Returns the number of rows changes/deleted/inserted by the last UPDATE,DELETE,or INSERT query + +@item @strong{mysql_bind_result()} @tab Binds application data buffers to columns in the resultset. + +@item @strong{mysql_fetch()} @tab Fetches the next rowset of data from the result set and returns data for all bound columns. + +@item @strong{mysql_stmt_close()} @tab Frees memory used by prepared statement. + +@item @strong{mysql_stmt_errno()} @tab Returns the error number for the last statement execution. + +@item @strong{mysql_stmt_error()} @tab Returns the error message for the last statement execution. + +@item @strong{mysql_send_long_data()} @tab Sends long data in chunks to server. + +@c TO BE MOVED TO MAIN C API FUCTIONS +@item @strong{mysql_commit()} @tab Commits the transaction. + +@item @strong{mysql_rollback()} @tab Rollbacks the transaction. + +@item @strong{mysql_autocommit()} @tab Toggles the autocommit mode to on/off. + +@item @strong{mysql_more_results()} @tab Returns if there are any more results exists + +@item @strong{mysql_next_result()} @tab Returns/Initiates the next result in the multi-query executions + +@end multitable + +@sp 1 +Call @code{mysql_prepare()} to prepare and initialize the statement +handle, then call @code{mysql_bind_param()} to supply the parameters +data, and then call @code{mysql_execute()} to execute the query. You can +repeat the @code{mysql_execute()} by changing parameter values from the +respective buffer supplied through @code{mysql_bind_param()}. + +@sp 1 + + +In case if the query is a SELECT statement or any other query which +results in a resultset, then mysql_prepare() will also return the result +set meta data information in the form of @code{MYSQL_RES } result set +through @code{mysql_prepare_result()}. + +@sp 1 + +You can supply the result buffers using @code{mysql_bind_result()}, so +that the @code{mysql_fetch()} will automatically returns data to this +buffers. This is row by row fetching. + +@sp 1 + +You can also send the text or binary data in chunks to server using +@code{mysql_send_long_data()}, by specifying the option is_long_data=1 +or length=MYSQL_LONG_DATA or -2 in the MYSQL_BIND structure supplied +with @code{mysql_bind_param()}. + +@sp 1 + +Once the statement execution is over, it must be freed using +@code{mysql_stmt_close} so that it frees all the alloced resources for +the statement handle. + + +@subsubheading Execution Steps: + +To prepare and execute a statement, the application: + +@itemize @bullet +@item +Calls @strong{mysql_prepare()} and passes it a string containing the SQL +statement. On a successful prepare, mysql_prepare returns the valid statement +handle back to the application +@item +If the query results in a resultset, then @strong{mysql_prepare_result} +returns the result set meta info.. +@item +Sets the values of any parameters using @strong{mysql_bind_param}. All +parameters must be set; else it will return an error or produce +un-expected results +@item +Calls @strong{mysql_execute} to execute the statement. +@item +Repeat steps 2 and 3 as necessary, by changing the parameter values and +re-executing the statement. +@item +Bind the data buffers to return the row values, if it is a result set +query; using @strong{mysql_bind_result()}. +@item +Fetch the data to buffers row by row by calling @strong{mysql_fetch()} +repetedely until no more rows found. +@item +When @strong{mysql_prepare()} is called, in the MySQL client/server protocol: +@itemize @minus +@item +Server parses the query and sends the ok status back to client by +assinging a statement id. It also sends total number of parameters, +columns count and its meta information if it is a result set oriented +query. All syntax and symantecs of the query is checked during this call +by the server. +@item +Client uses this statement id for the further executions, so that server +identifies the statement back from the pool of statements. Now, client +allocates a statement handle with this id and returns back to +application. +@end itemize +@item +When @strong{mysql_execute()} is called, in the MySQL client/server protocol: +@itemize @minus +@item +Client uses the statement handle and sends the parameters data to +server. +@item +Server identifies the statement using the id provided by the client, and +replaces the parameter markers with the newly supplied data and executes +the query. If it results in a result set, then sends the data back to +client, else sends an OK status with total number of rows +changes/deleted/inserted. +@end itemize +@item +When @strong{mysql_fetch()} is called, in the MySQL client/server protocol: +@itemize @minus +@item +Client reads the data from the packet row by row and places it to +application data buffers by doing the necessary conversions. If the +application buffer type is same as that of field type, then the +conversions are stright forward. +@end itemize +@end itemize + + + +You can get the statement error code and message using +@code{mysql_stmt_errno()} and @code{mysql_stmt_error()} respectively. + + +@node C Prepared statement functions, , C Prepared statements function overview, MySQL prepared statements +@subsection C Prepared Statement Function Descriptions + +You need to use the following functions when you want to prepare and +execute the queries. + + +@menu +* mysql_prepare:: +* mysql_param_count:: +* mysql_prepare_result:: +* mysql_bind_param:: +* mysql_execute:: +* mysql_stmt_affected_rows:: +* mysql_bind_result:: +* mysql_fetch:: +* mysql_send_long_data:: +* mysql_stmt_close:: +* mysql_stmt_errno:: +* mysql_stmt_error:: +* mysql_commit:: +* mysql_rollback:: +* mysql_autocommit:: +@end menu + +@node mysql_prepare, mysql_param_count, C Prepared statement functions, C Prepared statement functions +@subsubsection @code{mysql_prepare()} + +@findex @code{mysql_prepare()} + +@code{MYSQL_STMT * mysql_prepare(MYSQL *mysql, const char *query, unsigned +long length)} + +@subsubheading Description + +Prepares the SQL query pointed to by the null-terminated string +'query'. The query must consist of a single SQL statement. You should +not add a terminating semicolon (`;`) or \g to the statement. + +@sp 1 +The application can include one or more parameter markers in the SQL +statement. To include a parameter marker, the appication embeds a +question mark (@code{?}) into the SQL string at the appropriate +position. + +@sp 1 +The markers are legal only in certain places in SQL statements. For +example, they are not allowed in the select list(the list of columns to +be returned by a SELECT statement), nor are they allowed as both +operands of a binary operator such as the equal sign (=), becuase it +would be impossible to determine the parameter type. In general, +parameters are legal only in Data Manipulation Languange(DML) +statements, and not in Data Defination Language(DDL) statements. + +@sp 1 +The parameter markers are then bound to application variables using +@code{mysql_bind_param()}. + + + +@subsubheading Return Values + +@code{MYSQL_STMT} if the prepare was successful. NULL if an error +occured. + +@subsubheading Errors + +If the prepare is not successful, i.e. when @code{mysql_prepare()} returned a +NULL statement, errors can be obtained by calling @code{mysql_error()}. + + +@subsubheading Example + +For the usage of @code{mysql_prepare()} refer to the Example from +@ref{mysql_execute,mysql_execute()}. + + + + +@node mysql_param_count, mysql_prepare_result, mysql_prepare, C Prepared statement functions +@subsubsection @code{mysql_param_count()} + +@findex @code{mysql_param_count()} + +@code{unsigned int mysql_param_count(MYSQL_STMT *stmt)} + +@subsubheading Description + +Returns the number of parameter markers present from the prepared query. + +@subsubheading Return Values + +An unsigned integer representing the number of parameters in a +statement. + +@subsubheading Errors + +None + +@subsubheading Example + +For the usage of @code{mysql_param_count()} refer to the Example from +@ref{mysql_execute,mysql_execute()}. + + + +@node mysql_prepare_result, mysql_bind_param, mysql_param_count, C Prepared statement functions +@subsubsection @code{mysql_prepare_result()} + + +@findex @code{mysql_prepare_result}. + +@code{MYSQL_RES *mysql_prepare_result(MYSQL_STMT *stmt)} + +@subsubheading Description + +If the @code{mysql_prepare()} resulted in a result set query, then +@code{mysql_prepare_result()} returns the result set meta data in the form of +@code{MYSQL_RES} structure; which can further be used to process the +meta information such as total number of fields and individual field +information. This resulted result set can be passed as an argument to +any of the field based APIs in order to process the result set meta data +information such as: + +@itemize @minus +@item +mysql_num_fields() +@item +mysql_fetch_field() +@item +mysql_fetch_field_direct() +@item +mysql_fetch_fields() +@item +mysql_field_count() +@item +mysql_field_seek() +@item +mysql_field_tell() and +@item +mysql_free_result() +@end itemize + + +@subsubheading Return Values + +A @code{MYSQL_RES} result structure. NULL if no meta information exists from +the prepared query. + + +@subsubheading Errors + +None + + +@subsubheading Example + +For the usage of @code{mysql_prepare_result()} refer to the Example from +@ref{mysql_fetch,mysql_fetch()} + + + +@node mysql_bind_param, mysql_execute, mysql_prepare_result, C Prepared statement functions +@subsubsection @code{mysql_bind_param()} + +@findex @code{mysql_bind_param()} + +@code{int mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)} + +@subsubheading Description + +@code{mysql_bind_param} is used to bind data for the parameter markers +in the SQL statement from @code{mysql_prepare}. It uses the structure +MYSQL_BIND to supply the data. + +The supported buffer types are: + +@itemize @bullet +@item +MYSQL_TYPE_TINY +@item +MYSQL_TYPE_SHORT +@item +MYSQL_TYPE_LONG +@item +MYSQL_TYPE_LONGLONG +@item +MYSQL_TYPE_FLOAT +@item +MYSQL_TYPE_DOUBLE +@item +MYSQL_TYPE_STRING +@item +MYSQL_TYPE_VAR_STRING +@item +MYSQL_TYPE_TINY_BLOB +@item +MYSQL_TYPE_MEDIUM_BLOB +@item +MYSQL_TYPE_LONG_BLOB +@end itemize + +@subsubheading Return Values + +Zero if the bind was successful. Non-zero if an error occured. + +@subsubheading Errors +@table @code +@item CR_NO_PREPARE_STMT +No prepared statement exists +@item CR_NO_PARAMETERS_EXISTS +No parameters exists to bind +@item CR_INVALID_BUFFER_USE +Indicates if the bind is to supply the long data in chunks and if the +buffer type is non string or binary +@item CR_UNSUPPORTED_PARAM_TYPE +The conversion is not supported, possibly the buffer_type is illegal or +its not from the above list of supported types. +@end table + +@subsubheading Example + +For the usage of @code{mysql_bind_param()} refer to the Example from +@ref{mysql_execute,mysql_execute()}. + + + +@node mysql_execute, mysql_stmt_affected_rows, mysql_bind_param, C Prepared statement functions +@subsubsection @code{mysql_execute()} + +@findex @code{mysql_execute()} + +@code{int mysql_execute(MYSQL_STMT *stmt}. + +@subsubheading Description + +@code{mysql_execute()} executes the prepared query associated with the +statement handle. The parameter marker values will be sent to server +during this call, so that server replaces markers with this newly +supplied data. + +@sp 1 + +If the statement is UPDATE,DELETE,or INSERT, the total number of +changed/deletd/inserted values can be found by calling +@code{mysql_stmt_affected_rows}. If this is a result set query, then one +must call @code{mysql_fetch()} to fetch the data prior to calling any +other calls which results in query processing. For more information on +how to fetch the statement binary data, refer to @ref{mysql_fetch}. + + +@subsubheading Return Values + +@code{mysql_execute()} returns the following return values: + +@multitable @columnfractions .30 .65 +@item @strong{Return Value} @tab @strong{Description} +@item MYSQL_SUCCESS, 0 @tab Successful +@item MYSQL_STATUS_ERROR, 1 @tab Error occured. Error code and +message can be obtained by calling @code{mysql_stmt_errno()} and @code{mysql_stmt_error()}. +@item MYSQL_NEED_DATA, 99 @tab One of the parameter buffer is +indicating the data suppy in chunks, and the supply is not yet complete. +@end multitable + + +@subsubheading Errors + +@table @code +@item CR_NO_PREPARE_QUERY +No query prepared prior to execution +@item CR_ALL_PARAMS_NOT_BOUND +Not all parameters data is supplied +@item CR_SERVER_GONE_ERROR +The MySQL server has gone away +@item CR_UNKNOWN_ERROR +An unkown error occured +@end table + + +@subsubheading Example + +The following example explains the uasage of @code{mysql_prepare}, +@code{mysql_param_count}, @code{mysql_bind_param}, @code{mysql_execute} +and @code{mysql_stmt_affected_rows()}. + +@example + +MYSQL_BIND bind[3]; +MYSQL_STMT *stmt; +ulonglong affected_rows; +long length; +unsigned int param_count; +int int_data; +char str_data[50], query[255]; + + /* Set autocommit mode to true */ + mysql_autocommit(mysql, 1); + + if (mysql_query(mysql,"DROP TABLE IF EXISTS test_table")) + @{ + fprintf(stderr, "\n drop table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + @} + if (mysql_query(mysql,"CREATE TABLE test_table(col1 int, col2 varchar(50), \ + col3 smallint,\ + col4 timestamp(14))")) + @{ + fprintf(stderr, "\n create table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + @} + + /* Prepare a insert query with 3 parameters */ + strcpy(query, "INSERT INTO test_table(col1,col2,col3) values(?,?,?)"); + if(!(stmt = mysql_prepare(mysql,query,strlen(query)))) + @{ + fprintf(stderr, "\n prepare, insert failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + @} + fprintf(stdout, "\n prepare, insert successful"); + + /* Get the parameter count from the statement */ + param_count= mysql_param_count(stmt); + + fprintf(stdout, "\n total parameters in insert: %d", param_count); + if (param_count != 3) /* validate parameter count */ + @{ + fprintf(stderr, "\n invalid parameter count returned by MySQL"); + exit(0); + @} + + /* Bind the data for the parameters */ + + /* INTEGER PART */ + memset(bind,0,sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&int_data; + + /* STRING PART */ + bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer= (void *)str_data; + bind[1].buffer_length= sizeof(str_data); + + /* SMALLINT PART */ + bind[2].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer= (void *)&small_data; + bind[2].length= (long *)&length; + + /* Bind the buffers */ + if (mysql_bind_param(stmt, bind)) + @{ + fprintf(stderr, "\n param bind failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + /* Specify the data */ + int_data= 10; /* integer */ + strcpy(str_data,"MySQL"); /* string */ + /* INSERT SMALLINT data as NULL */ + length= MYSQL_NULL_DATA; + + /* Execute the insert statement - 1*/ + if (mysql_execute(stmt)) + @{ + fprintf(stderr, "\n execute 1 failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + fprintf(stderr, "\n send a bug report to bugs@@lists.mysql.com, by asking why this is not working ?"); + exit(0); + @} + + /* Get the total rows affected */ + affected_rows= mysql_stmt_affected_rows(stmt); + + fprintf(stdout, "\n total affected rows: %lld", affected_rows); + if (affected_rows != 1) /* validate affected rows */ + @{ + fprintf(stderr, "\n invalid affected rows by MySQL"); + exit(0); + @} + + /* Re-execute the insert, by changing the values */ + int_data= 1000; + strcpy(str_data,"The most popular open source database"); + small_data= 1000; /* smallint */ + length= 0; + + /* Execute the insert statement - 2*/ + if (mysql_execute(stmt)) + @{ + fprintf(stderr, "\n execute 2 failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + /* Get the total rows affected */ + affected_rows= mysql_stmt_affected_rows(stmt); + + fprintf(stdout, "\n total affected rows: %lld", affected_rows); + if (affected_rows != 1) /* validate affected rows */ + @{ + fprintf(stderr, "\n invalid affected rows by MySQL"); + exit(0); + @} + + /* Close the statement */ + if (mysql_stmt_close(stmt)) + @{ + fprintf(stderr, "\n failed while closing the statement"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + /* DROP THE TABLE */ + if (mysql_query(mysql,"DROP TABLE test_table")) + @{ + fprintf(stderr, "\n drop table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + @} + fprintf(stdout, "Success, MySQL prepared statements are working great !!!"); +@end example + + + + +@node mysql_stmt_affected_rows, mysql_bind_result, mysql_execute, C Prepared statement functions +@subsubsection @code{mysql_stmt_affected_rows()} + +@findex @code{mysql_stmt_affected_rows()} + +@code{ulonglong mysql_stmt_affected_rows(MYSQL_STMT *stmt)} + +@subsubheading Description + +Returns total number of rows changed by the last execute statement. May +be called immediatlely after mysql_execute() for UPDATE,DELETE,or INSERT +statements.For SELECT statements, mysql_stmt_affected rows works like +mysql_num_rows(). + +@subsubheading Return Values + +An integer greater than zero indicates the number of rows affected or +retrieved. Zero indicates that no records where updated for an UPDATE +statement, no rows matched the WHERE clause in the query or that no +query has yet been executed. -1 indicates that the query returned an +error or that, for a SELECT query, mysql_stmt_affected_rows() was called +prior to calling mysql_fetch(). + +@subsubheading Errors + +None. + +@subsubheading Example + +For the usage of @code{mysql_stmt_affected_rows()} refer to the Example +from @ref{mysql_execute,mysql_execute()}. + + + + + +@node mysql_bind_result, mysql_fetch, mysql_stmt_affected_rows, C Prepared statement functions +@subsubsection @code{mysql_bind_result()} + +@findex @code{mysql_bind_result()} + +@code{my_bool mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)} + +@subsubheading Description + +@code{mysql_bind_result()} is ised to associate, or bind, columns in the +resultset to data buffers and length buffers. When @code{mysql_fetch()} is +called to fetch data, the MySQL client protocol returns the data for the +bound columns in the specified buffers. + +@sp 1 + +Note that all columns must be bound prior to calling @code{mysql_fetch()} +in case of fetching the data to buffers; else @code{mysql_fetch()} simply ignores +the data fetch; also the buffers should be sufficient enough to hold the +data as the ptotocol doesn't return the data in chunks. + +@sp 1 + +A column can be bound or rebound at any time, even after data has been +fetched from the result set. The new binding takes effect the next time +@code{mysql_fetch()} is called. For example, suppose an application binds +the columns in a result set and calls @code{mysql_fetch()}. The mysql +protocol returns data in the bound buffers. Now suppose the application +binds the columns to a different set of buffers, then the protocol does +not place the data for the just fetched row in the newly bound +buffers. Instead, it does when the next @code{mysql_fetch()} is called. + +@sp 1 + +To bind a column, an application calls @code{mysql_bind_result()} and +passes the type, address, and the address of the length buffer. + +The supported buffer types are: + +@itemize @bullet +@item +MYSQL_TYPE_TINY +@item +MYSQL_TYPE_SHORT +@item +MYSQL_TYPE_LONG +@item +MYSQL_TYPE_LONGLONG +@item +MYSQL_TYPE_FLOAT +@item +MYSQL_TYPE_DOUBLE +@item +MYSQL_TYPE_STRING +@item +MYSQL_TYPE_VAR_STRING +@item +MYSQL_TYPE_BLOB +@item +MYSQL_TYPE_TINY_BLOB +@item +MYSQL_TYPE_MEDIUM_BLOB +@item +MYSQL_TYPE_LONG_BLOB +@end itemize + +@subsubheading Return Values + +Zero if the bind was successful. Non-zero if an error occured. + +@subsubheading Errors +@table @code +@item CR_NO_PREPARE_STMT +No prepared statement exists +@item CR_UNSUPPORTED_PARAM_TYPE +The conversion is not supported, possibly the buffer_type is illegal or +its not from the list of supported types. +@end table + +@subsubheading Example + +For the usage of @code{mysql_bind_result()} refer to the Example from +@ref{mysql_fetch,mysql_fetch()} + + + +@node mysql_fetch, mysql_send_long_data, mysql_bind_result, C Prepared statement functions +@subsubsection @code{mysql_fetch()} + +@findex code{mysql_fetch()} + +@code{int mysql_fetch(MYSQL_STMT *stmt)} + +@subsubheading Description + +@code{mysql_fetch()} returns the next rowset in the result set. It can +be called only while the result set exists i.e. after a call to +@code{mysql_execute()} that creates a result set. + +@sp 1 + +If row buffers are bound using @code{mysql_bind_result()}, it returns +the data in those buffers for all the columns in the current row +set and the lengths are returned to the length pointer. + +@sp 1 +Note that, all columns must be bound by the application. + +@sp 1 +If the data fetched is a NULL data, then the length buffer will have a +value of @strong{MYSQL_NULL_DATA}, -1, else it will have the length of +the data being fetched based on the buffer type specified by the +application. All numeric, float and double types have the +fixed length(in bytes) as listed below: + +@multitable @columnfractions .10 .30 +@item @strong{Type} @tab @strong{Length} +@item MYSQL_TYPE_TINY @tab 1 +@item MYSQL_TYPE_SHORT @tab 2 +@item MYSQL_TYPE_LONG @tab 4 +@item MYSQL_TYPE_FLOAT @tab 4 +@item MYSQL_TYPE_LONGLONG @tab 8 +@item MYSQL_TYPE_DOUBLE @tab 8 +@item MYSQL_TYPE_STRING @tab data length +@item MYSQL_TYPE_VAR_STRING @tab data_length +@item MYSQL_TYPE_BLOB @tab data_length +@item MYSQL_TYPE_TINY_BLOB @tab data_length +@item MYSQL_TYPE_MEDIUM_BLOB @tab data_length +@item MYSQL_TYPE_LONG_BLOB @tab data_length +@end multitable + +@* +where @code{*data_length} is nothing but the 'Actual length of the data'. + +@subsubheading Return Values + +@multitable @columnfractions .30 .65 +@item @strong{Return Value} @tab @strong{Description} +@item MYSQL_SUCCESS, 0 @tab Successful, the data has been +fetched to application data buffers. +@item MYSQL_STATUS_ERROR, 1 @tab Error occured. Error code and +message can be obtained by calling @code{mysql_stmt_errno()} and @code{mysql_stmt_error()}. +@item MYSQL_NO_DATA, 100 @tab No more rows/data exists +@end multitable + + +@subsubheading Errors +@table @code +@item CR_UNSUPPORTED_PARAM_TYPE +If the field type is DATE,DATETIME,TIME,or TIMESTAMP; and the +application buffer type is non string based. +@item +All other un-supported conversions are returned from +@code{mysql_bind_result()}. +@end table + +@subsubheading Example + +The following example explains the usage of @code{mysql_prepare_result}, +@code{mysql_bind_result()}, and @code{mysql_fetch()} + +@example + +MYSQL_STMT *stmt; +MYSQL_BIND bind[2]; +MYSQL_RES *result; +int int_data; +long int_length, str_length; +char str_data[50]; + + query= "SELECT col1, col2 FROM test_table WHERE col1= 10)"); + if (!(stmt= mysql_prepare(&mysql, query, strlen(query))) + @{ + fprintf(stderr, "\n prepare failed"); + fprintf(stderr, "\n %s", mysql_error(&stmt)); + exit(0); + @} + + /* Get the fields meta information */ + if (!(result= mysql_prepare_result(stmt))) + @{ + fprintf(stderr, "\n prepare_result failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + fprintf(stdout, "Total fields: %ld", mysql_num_fields(result)); + + if (mysql_num_fields(result) != 2) + @{ + fprintf(stderr, "\n prepare returned invalid field count"); + exit(0); + @} + + /* Execute the SELECT query */ + if (mysql_execute(stmt)) + @{ + fprintf(stderr, "\n execute didn't retuned expected return code, MYSQL_NEED_DATA"); + exit(0); + @} + + /* Bind the result data buffers */ + bzero(bind, 0, sizeof(bind)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&int_data; + bind[0].length= &int_length; + + bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer= (void *)str_data; + bind[1].length= &str_length; + + if (mysql_bind_result(stmt, bind)) + @{ + fprintf(stderr, "\n bind_result failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + /* Now fetch data to buffers */ + if (mysql_fetch(stmt)) + @{ + fprintf(stderr, "\n fetch failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + fprintf(stdout, "\n int_data: %d, length: %ld", int_data, int_length); + fprintf(stdout, "\n str_data: %s, length: %ld", str_data, str_length); + + /* call mysql_fetch again */ + if (mysql_fetch(stmt) |= MYSQL_NO_DATA) + @{ + fprintf(stderr, "\n fetch return more than one row); + exit(0); + @} + + /* Free the prepare result */ + mysql_free_result(result); + + /* Free the statement handle */ + if (mysql_stmt_free(stmt)) + @{ + fprintf(stderr, "\n failed to free the statement handle); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + +@end example + + + +@node mysql_send_long_data, mysql_stmt_close, mysql_fetch, C Prepared statement functions +@subsubsection @code{mysql_send_long_data()} + + +@findex @code{mysql_send_long_data()}. + +@code{int mysql_send_long_data(MYSQL_STMT *stmt, unsigned int +parameter_number, const char *data, ulong length, my_bool is_last_data)} + +@subsubheading Description + +Allows an application to send the data in pieces or chunks to +server. This function can be used to send character or binary data +values in parts to a column(it must be a text or blob) with a character or +binary data type. + +@sp 1 +The @code{data} is a pointer to buffer containing the actual data for +the parameter represendted by @code{parameter_number}. The @code{length} +indicates the amount of data to be sent in bytes, and @code{is_last_data} is a +boolean flag to indicate the end of the data. If it is != 0, then the +current call will be the end of the data, else it waits for the +application to send all data. If the application doesn't ended the data +supply from @code{mysql_send_long_data()}, then the +@code{mysql_execute()} will return @strong{MYSQL_NEED_DATA}. + + + +@subsubheading Return Values + +Zero if the data is sent successfully to server. Non-zero if an error +occured. + + +@subsubheading Errors + +@table @code +@item CR_INVALID_PARAMETER_NO +Invalid parameter number +@item CR_SERVER_GONE_ERROR +The MySQL server has gone away +@item CR_UNKNOWN_ERROR +An unkown error occured +@end table + +@subsubheading Example +The following example explains how to send the data in chunks to text +column: +@example + +MYSQL_BIND bind[1]; +long length; + + query= "INSERT INTO test_long_data(text_column) VALUES(?)"); + if (!mysql_prepare(&mysql, query, strlen(query)) + @{ + fprintf(stderr, "\n prepare failed"); + fprintf(stderr, "\n %s", mysql_error(&stmt)); + exit(0); + @} + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].length= &length; + + /* Indicate that the data supply is in CHUNKS */ + length= MYSQL_LONG_DATA; + + /* Bind the buffers */ + if (mysql_bind_param(stmt, bind)) + @{ + fprintf(stderr, "\n param bind failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + /* Execute the insert statement - It should return MYSQL_NEED_DATA */ + if (mysql_execute(stmt) != MYSQL_NEED_DATA) + @{ + fprintf(stderr, "\n execute didn't retuned expected return code, MYSQL_NEED_DATA"); + exit(0); + @} + + /* Supply data in chunks to server */ + if (!mysql_send_long_data(stmt,1,"MySQL",5,0)) + @{ + fprintf(stderr, "\n send_long_data failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + /* Supply the last piece of data */ + if (mysql_send_long_data(stmt,1," - The most popular open source database",40,1)) + @{ + fprintf(stderr, "\n send_long_data failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + /* Now, execute the query */ + if (mysql_execute(stmt)) + @{ + fprintf(stderr, "\n mysql_execute failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + @} + + This inserts the data, "MySQL - The most popular open source database" + to the field 'text_column'. +@end example + + + +@node mysql_stmt_close, mysql_stmt_errno, mysql_send_long_data, C Prepared statement functions +@subsubsection @code{mysql_stmt_close()} + +@findex @code{mysql_stmt_close()} + +@code{my_bool mysql_stmt_close(MYSQL_STMT *)} + +@subsubheading Description + +Closes the prepared statement. @code{mysql_stmt_close()} also +deallocates the statement handle pointed to by @code{stmt}. + +@subsubheading Return Values + +Zero if the statement was freed successfully. Non-zero if an error occured. + + +@subsubheading Errors + +@table @code +@item CR_SERVER_GONE_ERROR +The MySQL server has gone away +@item CR_UNKNOWN_ERROR +An unkown error occured +@end table + +@subsubheading Example + +For the usage of @code{mysql_stmt_close()} refer to the Example from +@ref{mysql_execute,mysql_execute()}. + + + +@node mysql_stmt_errno, mysql_stmt_error, mysql_stmt_close, C Prepared statement functions +@subsubsection @code{mysql_stmt_errno()} + + +@findex @code{mysql_stmt_errno()} + +@code{unsigned int mysql_stmt_errno(MYSQL_STMT *stmt)} + +@subsubheading Description + +For the statement specified by @code{stmt}, @code{mysql_stmt_errno()} +returns the error code for the most recently invoked statement API +function that can succeed or fail. A return value of zero means that no +error occured. Client error message numbers are listed in the MySQL +errmsg.h header file. Server error message numbers are listed in +mysqld_error.h. In the MySQL source distribution you can find a complete +list of error messages and error numbers in the file Docs/mysqld_error.txt + +@subsubheading Return Values + +An error code value. Zero if no error occured. + +@subsubheading Errors + +None + + +@node mysql_stmt_error, mysql_commit, mysql_stmt_errno, C Prepared statement functions +@subsubsection @code{mysql_stmt_error()} + + +@findex @code{mysql_stmt_error()}. + +@code{char *mysql_stmt_error(MYSQL_STMT *stmt)} + +@subsubheading Description + +For the statement specified by @code{stmt}, @code{mysql_stmt_error()} +returns the error message for the most recently invoked statement API +that can succeed or fail. An empty string ("") is returned if no error +occured. This means the following two sets are equivalent: + +@example + +if (mysql_stmt_errno(stmt)) +@{ + // an error occured +@} + +if (mysql_stmt_error(stmt)) +@{ + // an error occured +@} +@end example + +The language of the client error messages many be changed by recompiling +the MySQL client library. Currently you can choose error messages in +several different languages. + + +@subsubheading Return Values + +A character string that describes the error. An empry string if no error +occured. + +@subsubheading Errors + +None + + + +@node mysql_commit, mysql_rollback, mysql_stmt_error, C Prepared statement functions +@subsubsection @code{mysql_commit()} + + +@findex @code{mysql_commit()}. + +@code{my_bool mysql_commit(MYSQL *mysql)} + +@subsubheading Description + +Commits the current transaction + +@subsubheading Return Values + +Zero if successful. Non-zero if an error occured. + +@subsubheading Errors + +None + + + +@node mysql_rollback, mysql_autocommit, mysql_commit, C Prepared statement functions +@subsubsection @code{mysql_rollback()} + + +@findex @code{mysql_rollback()}. + +@code{my_bool mysql_rollback(MYSQL *mysql)} + +@subsubheading Description + +Rollbacks the current transaction. + + +@subsubheading Return Values + +Zero if successful. Non-zero if an error occured. + +@subsubheading Errors + +None. + + + + +@node mysql_autocommit, , mysql_rollback, C Prepared statement functions +@subsubsection @code{mysql_autocommit()} + + +@findex @code{mysql_autocommit()}. + +@code{my_bool mysql_autocommit(MYSQL *mysql, my_bool mode)} + +@subsubheading Description + +Sets the autocommit mode to on or off. If the @code{mode} is '1', then it +sets the autocommit mode to on, else to off in case of '0'. + +@subsubheading Return Values + +Zero if successful. Non-zero if an error occured + +@subsubheading Errors + +None. + +@bye diff --git a/client/client_priv.h b/client/client_priv.h index eb4473cb10f..b6bfc253854 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -38,4 +38,5 @@ enum options { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_SHUTDOWN_TIMEOUT, OPT_LOCAL_INFILE, OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION,OPT_MYSQL_PROTOCOL, - OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM }; + OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM, OPT_SKIP_OPTIMIZATION, + OPT_COMPATIBLE }; diff --git a/client/mysqladmin.c b/client/mysqladmin.c index 2c8314d83ca..2fc77552d5f 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.c @@ -25,7 +25,7 @@ #include #include -#define ADMIN_VERSION "8.38" +#define ADMIN_VERSION "8.39" #define MAX_MYSQL_VAR 128 #define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */ #define MAX_TRUNC_LENGTH 3 @@ -76,8 +76,8 @@ static void print_relative_header(); static void print_relative_line(); static void truncate_names(); static my_bool get_pidfile(MYSQL *mysql, char *pidfile); -static void wait_pidfile(char *pidfile, time_t last_modified, - struct stat *pidfile_status); +static my_bool wait_pidfile(char *pidfile, time_t last_modified, + struct stat *pidfile_status); static void store_values(MYSQL_RES *result); /* @@ -513,7 +513,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) printf("Shutdown signal sent to server; Waiting for pid file to disappear\n"); /* Wait until pid file is gone */ - wait_pidfile(pidfile, last_modified, &pidfile_status); + if (wait_pidfile(pidfile, last_modified, &pidfile_status)) + return -1; } break; } @@ -1150,34 +1151,51 @@ static my_bool get_pidfile(MYSQL *mysql, char *pidfile) return 1; /* Error */ } +/* + Return 1 if pid file didn't disappear or change +*/ -static void wait_pidfile(char *pidfile, time_t last_modified, - struct stat *pidfile_status) +static my_bool wait_pidfile(char *pidfile, time_t last_modified, + struct stat *pidfile_status) { char buff[FN_REFLEN]; - int fd = -1; - uint count=0; + int error= 1; + uint count= 0; + DBUG_ENTER("wait_pidfile"); system_filename(buff, pidfile); - while (count++ <= opt_shutdown_timeout && !interrupted && - (!last_modified || (last_modified == pidfile_status->st_mtime)) && - (fd= my_open(buff, O_RDONLY, MYF(0))) >= 0) + do { - if (!my_close(fd,MYF(0))) - fd= -1; + int fd; + if ((fd= my_open(buff, O_RDONLY, MYF(0))) < 0) + { + error= 0; + break; + } + (void) my_close(fd,MYF(0)); + if (last_modified && !stat(pidfile, pidfile_status)) + { + if (last_modified != pidfile_status->st_mtime) + { + /* File changed; Let's assume that mysqld did restart */ + if (opt_verbose) + printf("pid file '%s' changed while waiting for it to disappear!\nmysqld did probably restart\n", + buff); + error= 0; + break; + } + } + if (count++ == opt_shutdown_timeout) + break; sleep(1); - if (last_modified && stat(pidfile, pidfile_status)) - last_modified= 0; - } - if (opt_verbose && last_modified && - last_modified != pidfile_status->st_mtime) - printf("Warning; pid file '%s' changed while waiting for it to disappear!\n", - buff); - if (fd >= 0) + } while (!interrupted); + + if (error) { - my_close(fd,MYF(0)); + DBUG_PRINT("warning",("Pid file didn't disappear")); fprintf(stderr, "Warning; Aborted waiting on pid file: '%s' after %d seconds\n", buff, count-1); } + DBUG_RETURN(error); } diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 4cf86eb31c7..6dbd79e9053 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -56,6 +56,9 @@ static short binlog_flags = 0; static MYSQL* mysql = NULL; static const char* table = 0; +static bool use_local_load= 0; +static const char* dirname_for_local_load= 0; + static void dump_local_log_entries(const char* logname); static void dump_remote_log_entries(const char* logname); static void dump_log_entries(const char* logname); @@ -64,6 +67,129 @@ static void dump_remote_table(NET* net, const char* db, const char* table); static void die(const char* fmt, ...); static MYSQL* safe_connect(); +class Load_log_processor { + char target_dir_name[MY_NFILE]; + int target_dir_name_len; + DYNAMIC_ARRAY file_names; + + const char* create_file(Create_file_log_event *ce) + { + const char *bname= ce->fname + ce->fname_len -1; + while (bname>ce->fname && bname[-1]!=FN_LIBCHAR) + bname--; + + uint blen= ce->fname_len - (bname-ce->fname); + uint full_len= target_dir_name_len + blen; + char *tmp; + if (!(tmp= my_malloc(full_len + 9 + 1,MYF(MY_WME))) || + set_dynamic(&file_names,(gptr)&ce,ce->file_id)) + { + die("Could not construct local filename %s%s",target_dir_name,bname); + return 0; + } + + char *ptr= tmp; + memcpy(ptr,target_dir_name,target_dir_name_len); + ptr+= target_dir_name_len; + memcpy(ptr,bname,blen); + ptr+= blen; + sprintf(ptr,"-%08x",ce->file_id); + + ce->set_fname_outside_temp_buf(tmp,full_len); + + return tmp; + } + + void append_to_file(const char* fname, int flags, + gptr data, uint size) + { + FILE *file; + if(!(file= my_fopen(fname,flags,MYF(MY_WME)))) + exit(1); + if (my_fwrite(file,data,size,MYF(MY_WME|MY_NABP))) + exit(1); + if (my_fclose(file,MYF(MY_WME))) + exit(1); + } + +public: + + Load_log_processor() + { + init_dynamic_array(&file_names,sizeof(Create_file_log_event*), + 100,100 CALLER_INFO); + } + + ~Load_log_processor() + { + destroy(); + delete_dynamic(&file_names); + } + + void init_by_dir_name(const char *atarget_dir_name) + { + char *end= strmov(target_dir_name,atarget_dir_name); + if (end[-1]!=FN_LIBCHAR) + *end++= FN_LIBCHAR; + target_dir_name_len= end-target_dir_name; + } + void init_by_file_name(const char *file_name) + { + int len= strlen(file_name); + const char *end= file_name + len - 1; + while (end>file_name && *end!=FN_LIBCHAR) + end--; + if (*end!=FN_LIBCHAR) + target_dir_name_len= 0; + else + { + target_dir_name_len= end - file_name + 1; + memmove(target_dir_name,file_name,target_dir_name_len); + } + } + void init_by_cur_dir() + { + target_dir_name_len= 0; + } + void destroy() + { + Create_file_log_event **ptr= (Create_file_log_event**)file_names.buffer; + Create_file_log_event **end= ptr + file_names.elements; + for (; ptrfname,MYF(MY_WME)); + delete *ptr; + *ptr= 0; + } + } + } + Create_file_log_event *grab_event(uint file_id) + { + Create_file_log_event **ptr= + (Create_file_log_event**)file_names.buffer + file_id; + Create_file_log_event *res= *ptr; + *ptr= 0; + return res; + } + void process(Create_file_log_event *ce) + { + const char *fname= create_file(ce); + append_to_file (fname,O_CREAT|O_BINARY,ce->block,ce->block_len); + } + void process(Append_block_log_event *ae) + { + if (ae->file_id >= file_names.elements) + die("Skiped CreateFile event for file_id: %u",ae->file_id); + Create_file_log_event* ce= + *((Create_file_log_event**)file_names.buffer + ae->file_id); + append_to_file(ce->fname,O_APPEND|O_BINARY,ae->block,ae->block_len); + } +}; + +Load_log_processor load_processor; + static struct my_option my_long_options[] = { #ifndef DBUG_OFF @@ -97,6 +223,9 @@ static struct my_option my_long_options[] = {"user", 'u', "Connect to the remote server as username", (gptr*) &user, (gptr*) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"local-load", 'l', "Prepare files for local load in directory", + (gptr*) &dirname_for_local_load, (gptr*) &dirname_for_local_load, 0, + GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} @@ -209,6 +338,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); + case 'l': + use_local_load= 1; + break; case '?': usage(); exit(0); @@ -420,6 +552,8 @@ static void dump_local_log_entries(const char* logname) MYF(MY_WME | MY_NABP))) exit(1); old_format = check_header(file); + if (use_local_load && !dirname_for_local_load) + load_processor.init_by_file_name(logname); } else { @@ -441,6 +575,8 @@ static void dump_local_log_entries(const char* logname) } file->pos_in_file=position; file->seek_not_done=0; + if (use_local_load && !dirname_for_local_load) + load_processor.init_by_cur_dir(); } if (!position) @@ -495,11 +631,43 @@ Could not read entry at offset %s : Error in log format or read error", } if (!short_form) fprintf(result_file, "# at %s\n",llstr(old_off,llbuff)); - - ev->print(result_file, short_form, last_db); + + if (!use_local_load) + ev->print(result_file, short_form, last_db); + else + { + switch(ev->get_type_code()) + { + case CREATE_FILE_EVENT: + { + Create_file_log_event* ce= (Create_file_log_event*)ev; + ce->print(result_file, short_form, last_db,true); + load_processor.process(ce); + ev= 0; + break; + } + case APPEND_BLOCK_EVENT: + ev->print(result_file, short_form, last_db); + load_processor.process((Append_block_log_event*)ev); + break; + case EXEC_LOAD_EVENT: + { + ev->print(result_file, short_form, last_db); + Execute_load_log_event *exv= (Execute_load_log_event*)ev; + Create_file_log_event *ce= load_processor.grab_event(exv->file_id); + ce->print(result_file, short_form, last_db,true); + my_free((char*)ce->fname,MYF(MY_WME)); + delete ce; + break; + } + default: + ev->print(result_file, short_form, last_db); + } + } } rec_count++; - delete ev; + if (ev) + delete ev; } if (fd >= 0) my_close(fd, MYF(MY_WME)); @@ -520,6 +688,8 @@ int main(int argc, char** argv) if (use_remote) mysql = safe_connect(); + if (dirname_for_local_load) + load_processor.init_by_dir_name(dirname_for_local_load); if (table) { diff --git a/client/mysqldump.c b/client/mysqldump.c index 9534cc68ed4..5eabce9b038 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -36,7 +36,7 @@ ** Added --single-transaction option 06/06/2002 by Peter Zaitsev */ -#define DUMP_VERSION "9.07" +#define DUMP_VERSION "10.0" #include #include @@ -69,21 +69,25 @@ static char *add_load_option(char *ptr, const char *object, const char *statement); +static ulong find_set(TYPELIB *lib, const char *x, uint length, + char **err_pos, uint *err_len); static char *field_escape(char *to,const char *from,uint length); -static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick=0, extended_insert = 0, - lock_tables=0,ignore_errors=0,flush_logs=0,replace=0, - ignore=0,opt_drop=0,opt_keywords=0,opt_lock=0,opt_compress=0, - opt_delayed=0,create_options=0,opt_quoted=0,opt_databases=0, +static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick= 1, extended_insert= 1, + lock_tables=1,ignore_errors=0,flush_logs=0,replace=0, + ignore=0,opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0, + opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0, opt_alldbs=0,opt_create_db=0,opt_first_slave=0, - opt_autocommit=0,opt_master_data,opt_disable_keys=0,opt_xml=0, + opt_autocommit=0,opt_master_data,opt_disable_keys=1,opt_xml=0, tty_password=0,opt_single_transaction=0; static MYSQL mysql_connection,*sock=0; static char insert_pat[12 * 1024],*opt_password=0,*current_user=0, *current_host=0,*path=0,*fields_terminated=0, *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0, - *where=0, *default_charset; -static uint opt_mysql_port=0; + *where=0, *default_charset, *opt_compatible_mode_str= 0, + *err_ptr= 0; +static ulong opt_compatible_mode= 0; +static uint opt_mysql_port= 0, err_len= 0; static my_string opt_mysql_unix_port=0; static int first_error=0; extern ulong net_buffer_length; @@ -93,7 +97,17 @@ FILE *md_result_file; #ifdef HAVE_SMEM static char *shared_memory_base_name=0; #endif -static uint opt_protocol=0; +static uint opt_protocol= 0; + +const char *compatible_mode_names[]= +{ + "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", + "SAPDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", + NullS +}; +TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, + "", compatible_mode_names}; + static struct my_option my_long_options[] = { @@ -102,13 +116,13 @@ static struct my_option my_long_options[] = (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, 0, + (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, 0, 0, 0, 0, 0, + (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"add-locks", OPT_LOCKS, "Add locks around insert statements.", - (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, + (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"allow-keywords", OPT_KEYWORDS, "Allow creation of column names that are keywords.", (gptr*) &opt_keywords, @@ -116,6 +130,10 @@ static struct my_option my_long_options[] = {"character-sets-dir", OPT_CHARSETS_DIR, "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: mysql323, mysql40, postgresql, oracle, mssql, db2, sapdb, 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.", + (gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"complete-insert", 'c', "Use complete insert statements.", (gptr*) &cFlag, (gptr*) &cFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use compression in server/client protocol.", @@ -135,11 +153,11 @@ static struct my_option my_long_options[] = 0, 0}, {"disable-keys", 'K', "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (gptr*) &opt_disable_keys, - (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"extended-insert", 'e', "Allows utilization of the new, much faster INSERT syntax.", (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG, - 0, 0, 0, 0, 0, 0}, + 1, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, "Fields in the textfile are terminated by ...", (gptr*) &fields_terminated, (gptr*) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -168,7 +186,7 @@ static struct my_option my_long_options[] = (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables, - (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"master-data", OPT_MASTER_DATA, "This will cause the master position and filename to be appended to your output. This will automagically enable --first-slave.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -178,8 +196,8 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"single-transaction", OPT_TRANSACTION, "Dump all tables in single transaction to get consistent snapshot. Mutually exclusive with --lock-tables.", - (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, GET_BOOL, NO_ARG, - 0, 0, 0, 0, 0, 0}, + (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-create-db", 'n', "'CREATE DATABASE /*!32312 IF NOT EXISTS*/ db_name;' will not be put in the output. The above line will be added otherwise, if --databases or --all-databases option was given.}", (gptr*) &opt_create_db, (gptr*) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0, @@ -192,7 +210,7 @@ static struct my_option my_long_options[] = "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"opt", OPT_OPTIMIZE, - "Same as --add-drop-table --add-locks --all --quick --extended-insert --lock-tables --disable-keys", + "Same as --add-drop-table --add-locks --all --quick --extended-insert --lock-tables --disable-keys. Enabled by default, disable with --skip-opt.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given it's solicited on the tty.", @@ -207,7 +225,7 @@ static struct my_option my_long_options[] = {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory)", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"quick", 'q', "Don't buffer query, dump directly to stdout.", - (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"quote-names",'Q', "Quote table and column names with a `", (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -219,6 +237,9 @@ static struct my_option my_long_options[] = "Base name of shared memory", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"skip-opt", OPT_SKIP_OPTIMIZATION, + "Disable --opt. Disables --add-locks, --all, --quick, --extended-insert, --lock-tables and --disable-keys.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -322,6 +343,7 @@ static void write_header(FILE *sql_file, char *db_name) return; } /* write_header */ + static void write_footer(FILE *sql_file) { if (opt_xml) @@ -329,6 +351,7 @@ static void write_footer(FILE *sql_file) fputs("\n", sql_file); } /* write_footer */ + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -378,27 +401,48 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), usage(); exit(0); case (int) OPT_OPTIMIZE: - extended_insert=opt_drop=opt_lock=quick=create_options=opt_disable_keys= - lock_tables=1; + extended_insert= opt_drop= opt_lock= quick= create_options= + opt_disable_keys= lock_tables= 1; if (opt_single_transaction) lock_tables=0; break; + case (int) OPT_SKIP_OPTIMIZATION: + extended_insert= opt_drop= opt_lock= quick= create_options= + opt_disable_keys= lock_tables= 0; + break; case (int) OPT_TABLES: opt_databases=0; break; - case OPT_MYSQL_PROTOCOL: - { - if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == ~(ulong) 0) - { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); + case (int) OPT_COMPATIBLE: + { + char buff[255]; + + opt_quoted= 1; + opt_compatible_mode_str= argument; + opt_compatible_mode= find_set(&compatible_mode_typelib, + argument, strlen(argument), + &err_ptr, &err_len); + if (err_len) + { + strmake(buff, err_ptr, min(sizeof(buff), err_len)); + fprintf(stderr, "Invalid mode to --compatible: %s\n", buff); + exit(1); + } + break; + } + case (int) OPT_MYSQL_PROTOCOL: + { + if ((opt_protocol= find_type(argument, &sql_protocol_typelib, 0)) + == ~(ulong) 0) + { + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); + } + break; } - break; - } } return 0; } - static int get_options(int *argc, char ***argv) { int ho_error; @@ -418,13 +462,8 @@ static int get_options(int *argc, char ***argv) "%s: You must use option --tab with --fields-...\n", my_progname); return(1); } - - if (opt_single_transaction && lock_tables) - { - fprintf(stderr, "%s: You can't use --lock-tables and --single-transaction at the same time.\n", my_progname); - return(1); - } - + if (opt_single_transaction) + lock_tables= 0; if (enclosed && opt_enclosed) { fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname); @@ -604,6 +643,31 @@ static uint getTableStructure(char *table, char* db) /* Make an sql-file, if path was given iow. option -T was given */ char buff[20+FN_REFLEN]; + if (opt_compatible_mode) + { + char *end; + uint i; + + sprintf(buff, "/*!41000 SET @@sql_mode=\""); + end= strend(buff); + for (i= 0; opt_compatible_mode; opt_compatible_mode>>= 1, i++) + { + if (opt_compatible_mode & 1) + { + end= strmov(end, compatible_mode_names[i]); + end= strmov(end, ","); + } + } + end= strmov(--end, "\" */"); + if (mysql_query(sock, buff)) + { + fprintf(stderr, "%s: Can't set the compatible mode '%s' (%s)\n", + my_progname, table, mysql_error(sock)); + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + } + sprintf(buff,"show create table `%s`",table); if (mysql_query(sock, buff)) { @@ -1399,6 +1463,48 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* dump_selected_tables */ + +static ulong find_set(TYPELIB *lib, const char *x, uint length, + char **err_pos, uint *err_len) +{ + const char *end= x + length; + ulong found= 0; + uint find; + char buff[255]; + + *err_pos= 0; // No error yet + while (end > x && my_isspace(system_charset_info, end[-1])) + end--; + + *err_len= 0; + if (x != end) + { + const char *start= x; + for (;;) + { + const char *pos= start; + uint var_len; + + for (; pos != end && *pos != ','; pos++) ; + var_len= (uint) (pos - start); + strmake(buff, start, min(sizeof(buff), var_len)); + find= find_type(buff, lib, var_len); + if (!find) + { + *err_pos= (char*) start; + *err_len= var_len; + } + else + found|= ((longlong) 1 << (find - 1)); + if (pos == end) + break; + start= pos + 1; + } + } + return found; +} + + /* Print a value with a prefix on file */ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, const char *prefix, const char *name, diff --git a/client/mysqltest.c b/client/mysqltest.c index ed95efc282e..f3037fcc173 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "1.25" +#define MTEST_VERSION "1.26" #include #include @@ -1809,10 +1809,8 @@ int read_query(struct st_query** q_ptr) static struct my_option my_long_options[] = { -#ifndef DBUG_OFF {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -#endif {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Basedir for tests", (gptr*) &opt_basedir, @@ -1905,7 +1903,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), { switch(optid) { case '#': +#ifndef DBUG_OFF DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace"); +#endif break; case 'r': record = 1; @@ -1983,7 +1983,7 @@ int parse_args(int argc, char **argv) default_argv= argv; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) - exit(ho_error); + exit(1); if (argc > 1) { diff --git a/extra/Makefile.am b/extra/Makefile.am index 6895d7a09f8..8107beb2657 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -18,7 +18,7 @@ INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \ ../dbug/libdbug.a ../strings/libmystrings.a bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \ - resolve_stack_dump mysql_install + resolve_stack_dump mysql_install mysql_waitpid # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/extra/mysql_waitpid.c b/extra/mysql_waitpid.c new file mode 100644 index 00000000000..14d3f893c60 --- /dev/null +++ b/extra/mysql_waitpid.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include + +static const char *VER= "1.1"; +static char *progname; +static my_bool verbose; + +void usage(void); + +static struct my_option my_long_options[] = +{ + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, + {"help", 'I', "Synonym for -?.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, + {"verbose", 'v', + "Be more verbose. Give a warning, if kill can't handle signal 0.", + (gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Print version information and exit.", 0, 0, 0, + GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + +static my_bool +get_one_option(int optid, const struct my_option *opt __attribute__((unused)), + char *argument __attribute__((unused))) +{ + switch(optid) { + case 'V': + printf("%s version %s by Jani Tolonen\n", progname, VER); + exit(-1); + case 'I': + case '?': + usage(); + } + return 0; +} + + +int main(int argc, char *argv[]) +{ + int pid= 0, t= 0, sig= 0; + + progname= argv[0]; + + if (handle_options(&argc, &argv, my_long_options, get_one_option)) + exit(-1); + if (!argv[0] || !argv[1] || (pid= atoi(argv[0])) <= 0 || + (t= atoi(argv[1])) <= 0) + usage(); + for (; t > 0; t--) + { + if (kill((pid_t) pid, sig)) + { + if (errno == EINVAL) + { + if (verbose) + printf("WARNING: kill couldn't handle signal 0, using signal 1.\n"); + sig= 1; + t++; + continue; + } + return 0; + } + sleep(1); + } + return 1; +} + +void usage(void) +{ + printf("%s version %s by Jani Tolonen\n\n", progname, VER); + printf("usage: %s [options] #pid #time\n\n", progname); + printf("Description: Waits for a program, which program id is #pid, to\n"); + printf("terminate within #time seconds. If the program terminates within\n"); + printf("this time, or if the #pid no longer exists, value 0 is returned.\n"); + printf("Otherwise 1 is returned. Both #pid and #time must be positive\n"); + printf("integer arguments.\n\n"); + printf("Options:\n"); + my_print_help(my_long_options); + exit(-1); +} diff --git a/include/m_ctype.h b/include/m_ctype.h index 85397796e73..ee6a50e6b8d 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -27,6 +27,13 @@ extern "C" { #endif +#define MY_CS_NAME_SIZE 32 +#define MY_CS_CTYPE_TABLE_SIZE 257 +#define MY_CS_TO_LOWER_TABLE_SIZE 256 +#define MY_CS_TO_UPPER_TABLE_SIZE 256 +#define MY_CS_SORT_ORDER_TABLE_SIZE 256 +#define MY_CS_TO_UNI_TABLE_SIZE 256 + #define CHARSET_DIR "charsets/" #define my_wc_t ulong @@ -42,6 +49,9 @@ typedef struct unicase_info_st { #define MY_CS_TOOSMALL -1 #define MY_CS_TOOFEW(n) (-1-(n)) +#define MY_SEQ_INTTAIL 1 +#define MY_SEQ_SPACES 2 + /* My charsets_list flags */ #define MY_NO_SETS 0 #define MY_CS_COMPILED 1 /* compiled-in sets */ @@ -50,6 +60,7 @@ typedef struct unicase_info_st { #define MY_CS_LOADED 8 /* sets that are currently loaded */ #define MY_CS_BINSORT 16 /* if binary sort order */ #define MY_CS_PRIMARY 32 /* if primary collation */ +#define MY_CS_STRNXFRM 64 /* if strnxfrm is used for sort */ #define MY_CHARSET_UNDEFINED 0 #define MY_CHARSET_CURRENT (default_charset_info->number) @@ -126,15 +137,17 @@ typedef struct charset_info_st /* Charset dependant snprintf() */ int (*snprintf)(struct charset_info_st *, char *to, uint n, const char *fmt, ...); - int (*l10tostr)(struct charset_info_st *, char *to, uint n, int radix, long int val); - int (*ll10tostr)(struct charset_info_st *, char *to, uint n, int radix, longlong val); + int (*long10_to_str)(struct charset_info_st *, char *to, uint n, int radix, long int val); + int (*longlong10_to_str)(struct charset_info_st *, char *to, uint n, int radix, longlong val); /* String-to-number convertion routines */ - long (*strntol)(struct charset_info_st *, const char *s, uint l,char **e, int base); - ulong (*strntoul)(struct charset_info_st *, const char *s, uint l, char **e, int base); - longlong (*strntoll)(struct charset_info_st *, const char *s, uint l, char **e, int base); - ulonglong (*strntoull)(struct charset_info_st *, const char *s, uint l, char **e, int base); - double (*strntod)(struct charset_info_st *, const char *s, uint l, char **e); + long (*strntol)(struct charset_info_st *, const char *s, uint l, int base, char **e, int *err); + ulong (*strntoul)(struct charset_info_st *, const char *s, uint l, int base, char **e, int *err); + longlong (*strntoll)(struct charset_info_st *, const char *s, uint l, int base, char **e, int *err); + ulonglong (*strntoull)(struct charset_info_st *, const char *s, uint l, int base, char **e, int *err); + double (*strntod)(struct charset_info_st *, char *s, uint l, char **e, int *err); + + ulong (*scan)(struct charset_info_st *, const char *b, const char *e, int sq); } CHARSET_INFO; @@ -145,7 +158,8 @@ extern CHARSET_INFO *default_charset_info; extern CHARSET_INFO *system_charset_info; extern CHARSET_INFO *all_charsets[256]; extern my_bool init_compiled_charsets(myf flags); - +extern my_bool my_parse_charset_xml(const char *bug, uint len, + int (*add)(CHARSET_INFO *cs)); /* declarations for simple charsets */ extern int my_strnxfrm_simple(CHARSET_INFO *, uchar *, uint, const uchar *, uint); @@ -172,16 +186,18 @@ extern int my_strncasecmp_8bit(CHARSET_INFO * cs, const char *, const char *, ui int my_mb_wc_8bit(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e); int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e); +ulong my_scan_8bit(CHARSET_INFO *cs, const char *b, const char *e, int sq); + int my_snprintf_8bit(struct charset_info_st *, char *to, uint n, const char *fmt, ...); -long my_strntol_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); -ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); -longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); -ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); -double my_strntod_8bit(CHARSET_INFO *, const char *s, uint l,char **e); +long my_strntol_8bit(CHARSET_INFO *, const char *s, uint l, int base, char **e, int *err); +ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, uint l, int base, char **e, int *err); +longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, uint l, int base, char **e, int *err); +ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, uint l, int base, char **e, int *err); +double my_strntod_8bit(CHARSET_INFO *, char *s, uint l,char **e, int *err); -int my_l10tostr_8bit(CHARSET_INFO *, char *to, uint l, int radix, long int val); -int my_ll10tostr_8bit(CHARSET_INFO *, char *to, uint l, int radix, longlong val); +int my_long10_to_str_8bit(CHARSET_INFO *, char *to, uint l, int radix, long int val); +int my_longlong10_to_str_8bit(CHARSET_INFO *, char *to, uint l, int radix, longlong val); my_bool my_like_range_simple(CHARSET_INFO *cs, const char *ptr, uint ptr_length, @@ -245,7 +261,7 @@ int my_wildcmp_mb(CHARSET_INFO *, #define my_isvar(s,c) (my_isalnum(s,c) || (c) == '_') #define my_isvar_start(s,c) (my_isalpha(s,c) || (c) == '_') -#define use_strnxfrm(s) ((s)->strnxfrm != NULL) +#define use_strnxfrm(s) ((s)->state & MY_CS_STRNXFRM) #define my_strnxfrm(s, a, b, c, d) ((s)->strnxfrm((s), (a), (b), (c), (d))) #define my_strnncoll(s, a, b, c, d) ((s)->strnncoll((s), (a), (b), (c), (d))) #define my_like_range(s, a, b, c, d, e, f, g, h, i, j) \ @@ -265,11 +281,11 @@ int my_wildcmp_mb(CHARSET_INFO *, #define my_strcasecmp(s, a, b) ((s)->strcasecmp((s), (a), (b))) #define my_strncasecmp(s, a, b, l) ((s)->strncasecmp((s), (a), (b), (l))) -#define my_strntol(s, a, b, c, d) ((s)->strntol((s),(a),(b),(c),(d))) -#define my_strntoul(s, a, b, c, d) ((s)->strntoul((s),(a),(b),(c),(d))) -#define my_strntoll(s, a, b, c, d) ((s)->strntoll((s),(a),(b),(c),(d))) -#define my_strntoull(s, a, b, c,d) ((s)->strntoull((s),(a),(b),(c),(d))) -#define my_strntod(s, a, b, c ) ((s)->strntod((s),(a),(b),(c))) +#define my_strntol(s, a, b, c, d, e) ((s)->strntol((s),(a),(b),(c),(d),(e))) +#define my_strntoul(s, a, b, c, d, e) ((s)->strntoul((s),(a),(b),(c),(d),(e))) +#define my_strntoll(s, a, b, c, d, e) ((s)->strntoll((s),(a),(b),(c),(d),(e))) +#define my_strntoull(s, a, b, c,d, e) ((s)->strntoull((s),(a),(b),(c),(d),(e))) +#define my_strntod(s, a, b, c, d) ((s)->strntod((s),(a),(b),(c),(d))) /* XXX: still need to take care of this one */ diff --git a/include/m_string.h b/include/m_string.h index c6943613b1a..15a488fe72a 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -31,6 +31,9 @@ #include #endif +/* need by my_vsnprintf */ +#include + /* Correct some things for UNIXWARE7 */ #ifdef HAVE_UNIXWARE7_THREADS #undef HAVE_STRINGS_H @@ -238,6 +241,12 @@ extern ulonglong strtoull(const char *str, char **ptr, int base); #endif #endif +/* my_vsnprintf.c */ + +extern int my_vsnprintf( char *str, size_t n, + const char *format, va_list ap ); +extern int my_snprintf(char* to, size_t n, const char* fmt, ...); + #if defined(__cplusplus) && !defined(OS2) } #endif diff --git a/include/my_base.h b/include/my_base.h index 6efac979a4e..b16a545b937 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -264,6 +264,7 @@ enum ha_base_keytype { #define MBR_EQUAL 8192 #define MBR_DATA 16384 #define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */ +#define SEARCH_NULL_ARE_NOT_EQUAL 65536 /* NULL in keys are not equal */ /* bits in opt_flag */ #define QUICK_USED 1 diff --git a/include/my_sys.h b/include/my_sys.h index 975990ca7fc..3d81a9e9219 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -569,9 +569,6 @@ extern int my_error _VARARGS((int nr,myf MyFlags, ...)); extern int my_printf_error _VARARGS((uint my_err, const char *format, myf MyFlags, ...) __attribute__ ((format (printf, 2, 4)))); -extern int my_vsnprintf( char *str, size_t n, - const char *format, va_list ap ); -extern int my_snprintf(char* to, size_t n, const char* fmt, ...); extern int my_message(uint my_err, const char *str,myf MyFlags); extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); extern int my_message_curses(uint my_err, const char *str,myf MyFlags); diff --git a/include/mysql.h b/include/mysql.h index e43136f8f69..f25ccf79cf6 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -439,13 +439,12 @@ typedef struct st_mysql_bind { long *length; /* output length pointer */ gptr buffer; /* buffer */ - unsigned long buffer_length; /* buffer length */ enum enum_field_types buffer_type; /* buffer type */ - enum enum_field_types field_type; /* field type */ my_bool is_null; /* NULL indicator */ my_bool is_long_data; /* long data indicator */ /* The following are for internal use. Set by mysql_bind_param */ + unsigned long buffer_length; /* buffer length */ long bind_length; /* Default length of data */ my_bool long_ended; /* All data supplied for long */ unsigned int param_number; /* For null count and error messages */ @@ -477,6 +476,7 @@ typedef struct st_mysql_stmt my_bool send_types_to_server; /* to indicate types supply to server */ my_bool param_buffers; /* to indicate the param bound buffers */ my_bool res_buffers; /* to indicate the output bound buffers */ + my_bool result_buffered; /* to indicate the results buffered */ } MYSQL_STMT; @@ -502,15 +502,17 @@ int STDCALL mysql_multi_query(MYSQL *mysql,const char *query, unsigned long len); MYSQL_RES *STDCALL mysql_next_result(MYSQL *mysql); MYSQL_RES *STDCALL mysql_prepare_result(MYSQL_STMT *stmt); +my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt); /* new status messages */ -#define MYSQL_SUCCESS 0 -#define MYSQL_WARNING 1 -#define MYSQL_STATUS_ERROR 2 -#define MYSQL_NO_DATA 100 -#define MYSQL_NEED_DATA 99 -#define MYSQL_NULL_DATA (-1) +#define MYSQL_SUCCESS 0 +#define MYSQL_STATUS_ERROR 1 +#define MYSQL_NO_DATA 100 +#define MYSQL_NEED_DATA 99 +#define MYSQL_NULL_DATA (-1) +#define MYSQL_LONG_DATA (-2) #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 25d2ab77007..972fabc74cf 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -52,6 +52,14 @@ row_mysql_read_var_ref_noninline( ulint* len, /* out: variable-length field length */ byte* field); /* in: field */ /*********************************************************************** +Frees the blob heap in prebuilt when no longer needed. */ + +void +row_mysql_prebuilt_free_blob_heap( +/*==============================*/ + row_prebuilt_t* prebuilt); /* in: prebuilt struct of a + ha_innobase:: table handle */ +/*********************************************************************** Stores a reference to a BLOB in the MySQL format. */ void diff --git a/innobase/include/row0sel.h b/innobase/include/row0sel.h index aa2da6fe5f6..cfc30852b87 100644 --- a/innobase/include/row0sel.h +++ b/innobase/include/row0sel.h @@ -115,7 +115,8 @@ row_search_for_mysql( /*=================*/ /* out: DB_SUCCESS, DB_RECORD_NOT_FOUND, - DB_END_OF_INDEX, or DB_DEADLOCK */ + DB_END_OF_INDEX, DB_DEADLOCK, + or DB_TOO_BIG_RECORD */ byte* buf, /* in/out: buffer for the fetched row in the MySQL format */ ulint mode, /* in: search mode PAGE_CUR_L, ... */ diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h index 09e0d800685..d3d04d58596 100644 --- a/innobase/include/ut0mem.h +++ b/innobase/include/ut0mem.h @@ -50,6 +50,16 @@ ut_malloc( /* out, own: allocated memory */ ulint n); /* in: number of bytes to allocate */ /************************************************************************** +Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs +out. It cannot be used if we want to return an error message. Prints to +stderr a message if fails. */ + +ibool +ut_test_malloc( +/*===========*/ + /* out: TRUE if succeeded */ + ulint n); /* in: try to allocate this many bytes */ +/************************************************************************** Frees a memory bloock allocated with ut_malloc. */ void diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 7b08d6b89b8..d4329c4873c 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -3602,7 +3602,8 @@ lock_release_off_kernel( ut_ad(lock_get_type(lock) == LOCK_TABLE); if (lock_get_mode(lock) != LOCK_IS - && (trx->insert_undo || trx->update_undo)) { + && 0 != ut_dulint_cmp(trx->undo_no, + ut_dulint_zero)) { /* The trx may have modified the table. We block the use of the MySQL query cache diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index ba56b3071cd..7cef63d1337 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -58,6 +58,19 @@ row_mysql_read_var_ref_noninline( return(row_mysql_read_var_ref(len, field)); } +/*********************************************************************** +Frees the blob heap in prebuilt when no longer needed. */ + +void +row_mysql_prebuilt_free_blob_heap( +/*==============================*/ + row_prebuilt_t* prebuilt) /* in: prebuilt struct of a + ha_innobase:: table handle */ +{ + mem_heap_free(prebuilt->blob_heap); + prebuilt->blob_heap = NULL; +} + /*********************************************************************** Stores a reference to a BLOB in the MySQL format. */ diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index ea5b3020c08..34f951b0c8a 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2039,9 +2039,12 @@ Note that the template in prebuilt may advise us to copy only a few columns to mysql_rec, other columns are left blank. All columns may not be needed in the query. */ static -void +ibool row_sel_store_mysql_rec( /*====================*/ + /* out: TRUE if success, FALSE + if could not allocate memory for a + BLOB */ byte* mysql_rec, /* out: row in the MySQL format */ row_prebuilt_t* prebuilt, /* in: prebuilt struct */ rec_t* rec) /* in: Innobase record in the index @@ -2092,7 +2095,19 @@ row_sel_store_mysql_rec( if (templ->type == DATA_BLOB) { ut_a(prebuilt->templ_contains_blob); - + + /* A heuristic test that we can allocate + the memory for a big BLOB. We have a safety + margin of 1000000 bytes. Since the test + takes some CPU time, we do not use for small + BLOBs. */ + + if (len > 2000000 + && !ut_test_malloc(len + 1000000)) { + + return(FALSE); + } + /* Copy the BLOB data to the BLOB heap of prebuilt */ @@ -2142,6 +2157,8 @@ row_sel_store_mysql_rec( } } } + + return(TRUE); } /************************************************************************* @@ -2526,7 +2543,8 @@ row_search_for_mysql( /*=================*/ /* out: DB_SUCCESS, DB_RECORD_NOT_FOUND, - DB_END_OF_INDEX, or DB_DEADLOCK */ + DB_END_OF_INDEX, DB_DEADLOCK, + or DB_TOO_BIG_RECORD */ byte* buf, /* in/out: buffer for the fetched row in the MySQL format */ ulint mode, /* in: search mode PAGE_CUR_L, ... */ @@ -2758,7 +2776,12 @@ row_search_for_mysql( #ifdef UNIV_SEARCH_DEBUG ut_a(0 == cmp_dtuple_rec(search_tuple, rec)); #endif - row_sel_store_mysql_rec(buf, prebuilt, rec); + if (!row_sel_store_mysql_rec(buf, prebuilt, + rec)) { + err = DB_TOO_BIG_RECORD; + + goto lock_wait_or_error; + } mtr_commit(&mtr); @@ -3200,7 +3223,11 @@ rec_loop: rec_get_size(rec)); mach_write_to_4(buf, rec_get_extra_size(rec) + 4); } else { - row_sel_store_mysql_rec(buf, prebuilt, rec); + if (!row_sel_store_mysql_rec(buf, prebuilt, rec)) { + err = DB_TOO_BIG_RECORD; + + goto lock_wait_or_error; + } } if (prebuilt->clust_index_was_generated) { diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index 03f15031fdf..a5991d5683d 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -77,8 +77,9 @@ ut_malloc_low( ret = malloc(n + sizeof(ut_mem_block_t)); if (ret == NULL) { + ut_print_timestamp(stderr); fprintf(stderr, - "InnoDB: Fatal error: cannot allocate %lu bytes of\n" + " InnoDB: Fatal error: cannot allocate %lu bytes of\n" "InnoDB: memory with malloc! Total allocated memory\n" "InnoDB: by InnoDB %lu bytes. Operating system errno: %d\n" "InnoDB: Cannot continue operation!\n" @@ -134,6 +135,40 @@ ut_malloc( return(ut_malloc_low(n, TRUE)); } +/************************************************************************** +Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs +out. It cannot be used if we want to return an error message. Prints to +stderr a message if fails. */ + +ibool +ut_test_malloc( +/*===========*/ + /* out: TRUE if succeeded */ + ulint n) /* in: try to allocate this many bytes */ +{ + void* ret; + + ret = malloc(n); + + if (ret == NULL) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: cannot allocate %lu bytes of memory for\n" + "InnoDB: a BLOB with malloc! Total allocated memory\n" + "InnoDB: by InnoDB %lu bytes. Operating system errno: %d\n" + "InnoDB: Check if you should increase the swap file or\n" + "InnoDB: ulimits of your operating system.\n" + "InnoDB: On FreeBSD check you have compiled the OS with\n" + "InnoDB: a big enough maximum process size.\n", + n, ut_total_allocated_memory, errno); + return(FALSE); + } + + free(ret); + + return(TRUE); +} + /************************************************************************** Frees a memory block allocated with ut_malloc. */ diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 4d8b703fb2d..47b582bc78e 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -37,12 +37,12 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \ int2str.lo str2int.lo strinstr.lo strcont.lo \ strcend.lo bcmp.lo \ bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \ - strtoull.lo strtoll.lo llstr.lo \ + strtoull.lo strtoll.lo llstr.lo my_vsnprintf.lo \ ctype.lo ctype-simple.lo ctype-bin.lo ctype-mb.lo \ ctype-big5.lo ctype-czech.lo ctype-euc_kr.lo \ ctype-win1250ch.lo ctype-utf8.lo \ ctype-gb2312.lo ctype-gbk.lo ctype-latin1_de.lo \ - ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo + ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo xml.lo mystringsextra= strto.c dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo @@ -58,9 +58,9 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ mf_loadpath.lo my_pthread.lo my_thr_init.lo \ thr_mutex.lo mulalloc.lo string.lo default.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \ - charset.lo xml.lo hash.lo mf_iocache.lo \ + charset.lo hash.lo mf_iocache.lo \ mf_iocache2.lo my_seek.lo \ - my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo sha1.lo\ + my_pread.lo mf_cache.lo md5.lo sha1.lo\ my_getopt.lo my_gethostbyname.lo my_port.lo sqlobjects = net.lo diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 5cae0a3813d..37eed9ab1b2 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -115,6 +115,7 @@ static sig_handler pipe_sig_handler(int sig); static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list); +static unsigned int get_binary_length(uint type); static my_bool org_my_init_done=0; @@ -3839,7 +3840,7 @@ static my_bool read_prepare_result(MYSQL_STMT *stmt) if ((length= net_safe_read(mysql)) == packet_error) DBUG_RETURN(1); - pos=(uchar*) mysql->net.read_pos; + pos= (uchar*) mysql->net.read_pos; stmt->stmt_id= uint4korr(pos); pos+=4; field_count= uint2korr(pos); pos+=2; param_count= uint2korr(pos); pos+=2; @@ -3865,10 +3866,10 @@ static my_bool read_prepare_result(MYSQL_STMT *stmt) set_stmt_error(stmt, CR_OUT_OF_MEMORY); DBUG_RETURN(0); } - stmt->bind= (stmt->params + stmt->param_count); - stmt->field_count= (uint) field_count; - stmt->param_count= (ulong) param_count; - stmt->mysql->status= MYSQL_STATUS_READY; + stmt->bind= (stmt->params + param_count); + stmt->field_count= (uint) field_count; + stmt->param_count= (ulong) param_count; + mysql->status= MYSQL_STATUS_READY; DBUG_RETURN(0); } @@ -4097,13 +4098,23 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) DBUG_PRINT("enter",("type: %d, buffer:%lx, length: %d", param->buffer_type, param->buffer ? param->buffer : "0", *param->length)); - if (param->is_null || param->buffer_type == MYSQL_TYPE_NULL || + if (param->buffer_type == MYSQL_TYPE_NULL || *param->length == MYSQL_NULL_DATA) store_param_null(net, param); else { - /* Allocate for worst case (long string) */ - if ((my_realloc_str(net, 9 + *param->length))) + unsigned int length; + + /* + Allocate for worst case (long string), ignore the length + buffer for numeric/double types by assigning the default + length using get_binary_length + */ + + if (!(length= get_binary_length(param->buffer_type))) + length= *param->length; + + if ((my_realloc_str(net, 9 + length))) DBUG_RETURN(1); (*param->store_param_func)(net, param); } @@ -4133,6 +4144,8 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length) } stmt->state= MY_ST_EXECUTE; mysql_free_result(stmt->result); + stmt->result= (MYSQL_RES *)0; + stmt->result_buffered= 0; DBUG_RETURN(0); } @@ -4190,7 +4203,7 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt) for (param= stmt->params; param < param_end; param++) { /* Check for long data which has not been propery given/terminated */ - if (param->is_long_data) + if (*param->length == MYSQL_LONG_DATA) { if (!param->long_ended) DBUG_RETURN(MYSQL_NEED_DATA); @@ -4225,6 +4238,14 @@ ulong STDCALL mysql_param_count(MYSQL_STMT * stmt) DBUG_RETURN(stmt->param_count); } +/* + Return total affected rows from the last statement +*/ + +my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt) +{ + return stmt->mysql->last_used_con->affected_rows; +} /* Setup the parameter data buffers from application @@ -4258,7 +4279,7 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) param++) { param->param_number= count++; - if (param->is_long_data && + if (param->length && *param->length == MYSQL_LONG_DATA && (param->buffer_type < MYSQL_TYPE_TINY_BLOB || param->buffer_type > MYSQL_TYPE_STRING)) { @@ -4281,7 +4302,7 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) /* Setup data copy functions for the different supported types */ switch (param->buffer_type) { case MYSQL_TYPE_NULL: - param->is_null=1; + param->bind_length= MYSQL_NULL_DATA; break; case MYSQL_TYPE_TINY: param->bind_length= 1; @@ -4412,41 +4433,32 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, 1 Error (Can't alloc net->buffer) ****************************************************************************/ - -static ulong get_field_length(uint type) +/* Return the default binary data length for the common types */ +static unsigned int get_binary_length(uint type) { - ulong length; - - switch (type) { - + switch(type) { case MYSQL_TYPE_TINY: - length= 1; - break; + return 1; case MYSQL_TYPE_SHORT: case MYSQL_TYPE_YEAR: - length= 2; - break; + return 2; case MYSQL_TYPE_LONG: case MYSQL_TYPE_FLOAT: - length= 4; - break; + return 4; case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_DOUBLE: - length= 8; - break; + return 8; default: - length= 0; + return 0; } - return length; } +/* Convert Numeric to buffer types */ static void send_data_long(MYSQL_BIND *param, longlong value) { char *buffer= param->buffer; - *param->length= get_field_length(param->buffer_type); switch(param->buffer_type) { - case MYSQL_TYPE_TINY: *param->buffer= (uchar) value; break; @@ -4480,13 +4492,12 @@ static void send_data_long(MYSQL_BIND *param, longlong value) } } +/* Convert Double to buffer types */ static void send_data_double(MYSQL_BIND *param, double value) { char *buffer= param->buffer; - *param->length= get_field_length(param->buffer_type); switch(param->buffer_type) { - case MYSQL_TYPE_TINY: *buffer= (uchar)value; break; @@ -4520,63 +4531,65 @@ static void send_data_double(MYSQL_BIND *param, double value) } } -static void send_data_str(MYSQL_BIND *param, char *value, uint src_length) +/* Convert string to buffer types */ +static void send_data_str(MYSQL_BIND *param, char *value, uint length) { char *buffer= param->buffer; + int err=0; - *param->length= get_field_length(param->buffer_type); switch(param->buffer_type) { - case MYSQL_TYPE_TINY: - *buffer= (char)*value; + { + uchar data= (uchar)my_strntol(system_charset_info,value,length,10,NULL,&err); + *buffer= data; break; + } case MYSQL_TYPE_SHORT: { - short data= (short)sint2korr(value); + short data= (short)my_strntol(system_charset_info,value,length,10,NULL,&err); int2store(buffer, data); break; } case MYSQL_TYPE_LONG: { - int32 data= (int32)sint4korr(value); + int32 data= (int32)my_strntol(system_charset_info,value,length,10,NULL,&err); int4store(buffer, data); break; } case MYSQL_TYPE_LONGLONG: { - longlong data= sint8korr(value); + longlong data= my_strntoll(system_charset_info,value,length,10,NULL,&err); int8store(buffer, data); break; } case MYSQL_TYPE_FLOAT: { - float data; - float4get(data, value); + float data = (float)my_strntod(system_charset_info,value,length,NULL,&err); float4store(buffer, data); break; } case MYSQL_TYPE_DOUBLE: { - double data; - float8get(data, value); + double data= my_strntod(system_charset_info,value,length,NULL,&err); float8store(buffer, data); break; } default: - *param->length= src_length; - memcpy(buffer, value, src_length); - buffer[src_length]='\0'; + *param->length= length; + memcpy(buffer, value, length); + buffer[length]='\0'; } } +/* Fetch data to buffers */ static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, uint field_type, uchar **row) { ulong length; - - length= get_field_length(field_type); + + length= (ulong)get_binary_length(field_type); + switch (field_type) { - case MYSQL_TYPE_TINY: { uchar value= (uchar) **row; @@ -4698,7 +4711,7 @@ static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, */ sprintf(stmt->last_error, ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), - param->buffer_type, param->param_number); + param->buffer_type, param->param_number); return 1; } arg_length= 0; @@ -4798,6 +4811,11 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) DBUG_ASSERT(stmt != 0); #ifdef CHECK_EXTRA_ARGUMENTS + if (stmt->state == MY_ST_UNKNOWN) + { + set_stmt_error(stmt, CR_NO_PREPARE_STMT); + DBUG_RETURN(1); + } if (!bind) { set_stmt_error(stmt, CR_NULL_POINTER); @@ -4813,27 +4831,21 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) /* Setup data copy functions for the different supported types */ switch (param->buffer_type) { case MYSQL_TYPE_TINY: - param->bind_length= 1; param->fetch_result= fetch_result_tinyint; break; case MYSQL_TYPE_SHORT: - param->bind_length= 2; param->fetch_result= fetch_result_short; break; case MYSQL_TYPE_LONG: - param->bind_length= 4; param->fetch_result= fetch_result_int32; break; case MYSQL_TYPE_LONGLONG: - param->bind_length= 8; param->fetch_result= fetch_result_int64; break; case MYSQL_TYPE_FLOAT: - param->bind_length= 4; param->fetch_result= fetch_result_float; break; case MYSQL_TYPE_DOUBLE: - param->bind_length= 8; param->fetch_result= fetch_result_double; break; case MYSQL_TYPE_TINY_BLOB: @@ -4842,7 +4854,6 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: - param->bind_length= 0; param->fetch_result= fetch_result_str; break; default: @@ -4852,6 +4863,7 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) } if (!param->length) param->length= ¶m->bind_length; + *param->length= (long)get_binary_length(param->buffer_type); } stmt->res_buffers= 1; DBUG_RETURN(0); @@ -4861,12 +4873,14 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) Fetch row data to bind buffers */ -static void -stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) +static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) { MYSQL_BIND *bind, *end; MYSQL_FIELD *field, *field_end; uchar *null_ptr, bit; + + if (!row || !stmt->res_buffers) + return 0; null_ptr= row; row+= (stmt->field_count+9)/8; /* skip null bits */ @@ -4886,7 +4900,7 @@ stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) if (field->type == bind->buffer_type) (*bind->fetch_result)(bind, &row); else if (fetch_results(stmt, bind, field->type, &row)) - break; + return 1; } if (! (bit<<=1) & 255) { @@ -4894,23 +4908,9 @@ stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) null_ptr++; } } -} - -static int read_binary_data(MYSQL *mysql) -{ - /* TODO : Changes needed based on logic of use_result/store_result - Currently by default it is use_result. In case of - store_result, the data packet must point to already - read data. - */ - if (packet_error == net_safe_read(mysql)) - return -1; - if (mysql->net.read_pos[0] == 254) - return 1; /* End of data */ return 0; } - /* Fetch and return row data to bound buffers, if any */ @@ -4918,26 +4918,155 @@ static int read_binary_data(MYSQL *mysql) int STDCALL mysql_fetch(MYSQL_STMT *stmt) { MYSQL *mysql= stmt->mysql; - int res; + uchar *row; DBUG_ENTER("mysql_fetch"); - if (!(res= read_binary_data(mysql))) + row= (uchar *)0; + if (stmt->result_buffered) /* buffered */ { - if (stmt->res_buffers) - stmt_fetch_row(stmt, mysql->net.read_pos+1); - DBUG_RETURN(0); + MYSQL_RES *res; + + if (!(res= stmt->result) || !res->data_cursor) + goto no_data; + + row= (uchar *)res->data_cursor->data; + res->data_cursor= res->data_cursor->next; + res->current_row= (MYSQL_ROW)row; } - mysql->status= MYSQL_STATUS_READY; - if (res < 0) /* Network error */ + else /* un-buffered */ { - set_stmt_errmsg(stmt,(char *)mysql->net.last_error, - mysql->net.last_errno); - DBUG_RETURN(MYSQL_STATUS_ERROR); + if (packet_error == net_safe_read(mysql)) + { + set_stmt_errmsg(stmt,(char *)mysql->net.last_error, + mysql->net.last_errno); + DBUG_RETURN(1); + } + if (mysql->net.read_pos[0] == 254) + { + mysql->status= MYSQL_STATUS_READY; + goto no_data; + } + row= mysql->net.read_pos+1; } + DBUG_RETURN(stmt_fetch_row(stmt, row)); + +no_data: DBUG_PRINT("info", ("end of data")); DBUG_RETURN(MYSQL_NO_DATA); /* no more data */ } +/* + Read all rows of data from server (binary format) +*/ + +static MYSQL_DATA *read_binary_rows(MYSQL_STMT *stmt) +{ + ulong pkt_len; + uchar *cp; + MYSQL *mysql= stmt->mysql; + MYSQL_DATA *result; + MYSQL_ROWS *cur, **prev_ptr; + NET *net = &mysql->net; + DBUG_ENTER("read_binary_rows"); + + mysql= mysql->last_used_con; + if ((pkt_len= net_safe_read(mysql)) == packet_error) + { + set_stmt_errmsg(stmt,(char *)mysql->net.last_error, + mysql->net.last_errno); + DBUG_RETURN(0); + } + if (mysql->net.read_pos[0] == 254) /* end of data */ + return 0; + + if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), + MYF(MY_WME | MY_ZEROFILL)))) + { + net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->last_error,ER(net->last_errno)); + DBUG_RETURN(0); + } + init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */ + result->alloc.min_malloc= sizeof(MYSQL_ROWS); + prev_ptr= &result->data; + result->rows= 0; + + while (*(cp=net->read_pos) != 254 || pkt_len >= 8) + { + result->rows++; + + if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,sizeof(MYSQL_ROWS))) || + !(cur->data= ((MYSQL_ROW) alloc_root(&result->alloc, pkt_len)))) + { + free_rows(result); + net->last_errno=CR_OUT_OF_MEMORY; + strmov(net->last_error,ER(net->last_errno)); + DBUG_RETURN(0); + } + *prev_ptr= cur; + prev_ptr= &cur->next; + memcpy(cur->data, (char*)cp+1, pkt_len-1); + + if ((pkt_len=net_safe_read(mysql)) == packet_error) + { + free_rows(result); + DBUG_RETURN(0); + } + } + *prev_ptr= 0; + if (pkt_len > 1) + { + mysql->warning_count= uint2korr(cp+1); + DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count)); + } + DBUG_PRINT("exit",("Got %d rows",result->rows)); + DBUG_RETURN(result); +} + +/* + Store or buffer the binary results to stmt +*/ + +int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) +{ + MYSQL *mysql= stmt->mysql; + MYSQL_RES *result; + DBUG_ENTER("mysql_stmt_tore_result"); + + mysql= mysql->last_used_con; + + if (!stmt->field_count) + DBUG_RETURN(0); + if (mysql->status != MYSQL_STATUS_GET_RESULT) + { + strmov(mysql->net.last_error, + ER(mysql->net.last_errno= CR_COMMANDS_OUT_OF_SYNC)); + DBUG_RETURN(0); + } + mysql->status= MYSQL_STATUS_READY; /* server is ready */ + if (!(result= (MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+ + sizeof(ulong) * + stmt->field_count), + MYF(MY_WME | MY_ZEROFILL)))) + { + mysql->net.last_errno= CR_OUT_OF_MEMORY; + strmov(mysql->net.last_error, ER(mysql->net.last_errno)); + DBUG_RETURN(1); + } + stmt->result_buffered= 1; + if (!(result->data= read_binary_rows(stmt))) + { + my_free((gptr) result,MYF(0)); + DBUG_RETURN(0); + } + mysql->affected_rows= result->row_count= result->data->rows; + result->data_cursor= result->data->data; + result->fields= stmt->fields; + result->field_count= stmt->field_count; + stmt->result= result; + DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_fetch() */ +} + /******************************************************************** Misc function implementations diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index f9c276de32f..858a8dcbe06 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -97,6 +97,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, SEARCH_FIND | SEARCH_PREFIX, aio->key_root); + aio->info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */ while (!r) { diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 1ca342f3998..28c28e628ea 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -601,7 +601,8 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, if (*keys != 1L) /* not first_key */ { uint diff; - ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,SEARCH_FIND, + ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, + SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff); param->unique_count[diff-1]++; } diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 8429b22dad4..75057dd4e6a 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -55,12 +55,17 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) /* Free buffers and reset the following flags: EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK + + If the row buffer cache is large (for dynamic tables), reduce it + to save memory. */ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) { info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); error=end_io_cache(&info->rec_cache); } + if (share->base.blobs) + mi_alloc_rec_buff(info, -1, &info->rec_buff); #if defined(HAVE_MMAP) && defined(HAVE_MADVICE) if (info->opt_flag & MEMMAP_USED) madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM); diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 8f0da612c3a..ef1906e0c00 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -573,28 +573,36 @@ err: DBUG_RETURN (NULL); } /* mi_open */ + byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf) { uint extra; + uint32 old_length; + LINT_INIT(old_length); - if (! *buf || length > mi_get_rec_buff_len(info, *buf)) + if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf))) { byte *newptr = *buf; /* to simplify initial init of info->rec_buf in mi_open and mi_extra */ if (length == (ulong) -1) + { length= max(info->s->base.pack_reclength+info->s->base.pack_bits, info->s->base.max_key_length); + /* Avoid unnecessary realloc */ + if (newptr && length == old_length) + return newptr; + } extra= ((info->s->options & HA_OPTION_PACK_RECORD) ? ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+ MI_REC_BUFF_OFFSET : 0); if (extra && newptr) - newptr-=MI_REC_BUFF_OFFSET; + newptr-= MI_REC_BUFF_OFFSET; if (!(newptr=(byte*) my_realloc((gptr)newptr, length+extra+8, MYF(MY_ALLOW_ZERO_PTR)))) return newptr; - *((uint *)newptr)=length; + *((uint32 *) newptr)= (uint32) length; *buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0); } return *buf; diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 8aeccbbf559..04803d7a901 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -260,9 +260,11 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, uchar *key, uint key_len, uint nextflag, uchar **ret_pos, uchar *buff, my_bool *last_key) { - /* my_flag is raw comparison result to be changed according to - SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags. - flag is the value returned by ha_key_cmp and as treated as final */ + /* + my_flag is raw comparison result to be changed according to + SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags. + flag is the value returned by ha_key_cmp and as treated as final + */ int flag=0, my_flag=-1; uint nod_flag, length, len, matched, cmplen, kseg_len; uint prefix_len,suffix_len; diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index e5cac1f090e..005c36271bf 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -385,7 +385,7 @@ typedef struct st_mi_sort_param #define MI_DYN_ALIGN_SIZE 4 /* Align blocks on this */ #define MI_MAX_DYN_HEADER_BYTE 13 /* max header byte for dynamic rows */ #define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1))) -#define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint)) +#define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint32)) #define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */ @@ -554,7 +554,7 @@ extern byte *mi_alloc_rec_buff(MI_INFO *,ulong, byte**); ((((info)->s->options & HA_OPTION_PACK_RECORD) && (buf)) ? \ (buf) - MI_REC_BUFF_OFFSET : (buf)) #define mi_get_rec_buff_len(info,buf) \ - (*((uint *)(mi_get_rec_buff_ptr(info,buf)))) + (*((uint32 *)(mi_get_rec_buff_ptr(info,buf)))) extern ulong _mi_rec_unpack(MI_INFO *info,byte *to,byte *from, ulong reclength); diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 34f3d365d7d..edd573f50a3 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -88,6 +88,7 @@ sleep_until_file_created () wait_for_pid() { pid=$1 + #$WAIT_PID pid $SLEEP_TIME_FOR_DELETE } # No paths below as we can't be sure where the program is! @@ -347,9 +348,9 @@ while test $# -gt 0; do ;; --debug) EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \ - --debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/master.trace" + --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/master.trace" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \ - --debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/slave.trace" + --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/slave.trace" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT --debug" ;; --fast) @@ -423,6 +424,7 @@ if [ x$SOURCE_DIST = x1 ] ; then fi MYSQLADMIN="$BASEDIR/client/mysqladmin" + WAIT_PID="$BASEDIR/extra/mysql_waitpid" MYSQL_MANAGER_CLIENT="$BASEDIR/client/mysqlmanagerc" MYSQL_MANAGER="$BASEDIR/tools/mysqlmanager" MYSQL_MANAGER_PWGEN="$BASEDIR/client/mysqlmanager-pwgen" @@ -439,6 +441,7 @@ else fi MYSQL_TEST="$BASEDIR/bin/mysqltest" MYSQLADMIN="$BASEDIR/bin/mysqladmin" + WAIT_PID="$BASEDIR/bin/mysql_waitpid" MYSQL_MANAGER="$BASEDIR/bin/mysqlmanager" MYSQL_MANAGER_CLIENT="$BASEDIR/bin/mysqlmanagerc" MYSQL_MANAGER_PWGEN="$BASEDIR/bin/mysqlmanager-pwgen" @@ -753,9 +756,9 @@ manager_term() { pid=$1 ident=$2 - shift if [ $USE_MANAGER = 0 ] ; then - $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=5 --shutdown_timeout=20 shutdown >> $MYSQL_MANAGER_LOG 2>&1 + # Shutdown time must be high as slave may be in reconnect + $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=5 --shutdown_timeout=70 shutdown >> $MYSQL_MANAGER_LOG 2>&1 res=$? # Some systems require an extra connect $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=1 ping >> $MYSQL_MANAGER_LOG 2>&1 @@ -875,8 +878,8 @@ start_slave() [ x$SKIP_SLAVE = x1 ] && return eval "this_slave_running=\$SLAVE$1_RUNNING" [ x$this_slave_running = 1 ] && return - #when testing fail-safe replication, we will have more than one slave - #in this case, we start secondary slaves with an argument + # When testing fail-safe replication, we will have more than one slave + # in this case, we start secondary slaves with an argument slave_ident="slave$1" if [ -n "$1" ] ; then @@ -984,9 +987,12 @@ EOF mysql_start () { - $ECHO "Starting MySQL daemon" - start_master - start_slave +# We should not start the deamon here as we don't know the argumens +# for the test. Better to let the test start the deamon + +# $ECHO "Starting MySQL daemon" +# start_master +# start_slave cd $MYSQL_TEST_DIR return 1 } @@ -1087,8 +1093,6 @@ run_testcase () slave_init_script=$TESTDIR/$tname-slave.sh slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt echo $tname > $CURRENT_TEST - echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR - echo "CURRENT_TEST: $tname" >> $MASTER_MYERR SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0` if [ $USE_MANAGER = 1 ] ; then many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0` @@ -1125,13 +1129,17 @@ run_testcase () then EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"` stop_master + echo "CURRENT_TEST: $tname" >> $MASTER_MYERR start_master else if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] ; then EXTRA_MASTER_OPT="" stop_master + echo "CURRENT_TEST: $tname" >> $MASTER_MYERR start_master + else + echo "CURRENT_TEST: $tname" >> $MASTER_MYERR fi fi @@ -1161,7 +1169,10 @@ run_testcase () if [ x$do_slave_restart = x1 ] ; then stop_slave + echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR start_slave + else + echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR fi if [ x$many_slaves = x1 ]; then start_slave 1 diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index a4be4195ac8..456dfa860df 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -53,7 +53,7 @@ SHOW FULL COLUMNS FROM t1; Field Type Collation Null Key Default Extra Privileges Comment GROUP_ID int(10) unsigned binary PRI 0 select,insert,update,references LANG_ID smallint(5) unsigned binary PRI 0 select,insert,update,references -NAME char(80) character set latin1 latin1 MUL select,insert,update,references +NAME char(80) latin1 MUL select,insert,update,references DROP TABLE t1; create table t1 (n int); insert into t1 values(9),(3),(12),(10); @@ -120,5 +120,5 @@ alter table t2 rename t1, add c char(10) comment "no comment"; show columns from t1; Field Type Collation Null Key Default Extra i int(10) unsigned binary PRI NULL auto_increment -c char(10) character set latin1 latin1 YES NULL +c char(10) latin1 YES NULL drop table t1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index affda14b4ba..5228ae50a83 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2; +drop table if exists t1,t2,t3; create table t1 (b char(0)); insert into t1 values (""),(null); select * from t1; @@ -76,10 +76,10 @@ create table t1(x varchar(50) ); create table t2 select x from t1 where 1=2; describe t1; Field Type Collation Null Key Default Extra -x varchar(50) character set latin1 latin1 YES NULL +x varchar(50) latin1 YES NULL describe t2; Field Type Collation Null Key Default Extra -x char(50) character set latin1 latin1 YES NULL +x char(50) latin1 YES NULL drop table t2; create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f; describe t2; @@ -181,7 +181,7 @@ show create table t3; Table Create Table t3 CREATE TABLE `t3` ( `id` int(11) NOT NULL default '0', - `name` char(20) character set latin1 default NULL + `name` char(20) default NULL ) TYPE=MyISAM CHARSET=latin1 select * from t3; id name @@ -204,7 +204,7 @@ show create table t3; Table Create Table t3 CREATE TABLE `t3` ( `id` int(11) NOT NULL default '0', - `name` char(20) character set latin1 default NULL + `name` char(20) default NULL ) TYPE=MyISAM CHARSET=latin1 select * from t3; id name @@ -219,14 +219,14 @@ show create table t3; Table Create Table t3 CREATE TEMPORARY TABLE `t3` ( `id` int(11) NOT NULL default '0', - `name` char(20) character set latin1 default NULL + `name` char(20) default NULL ) TYPE=MyISAM CHARSET=latin1 create table t2 like t3; show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `id` int(11) NOT NULL default '0', - `name` char(20) character set latin1 default NULL + `name` char(20) default NULL ) TYPE=MyISAM CHARSET=latin1 select * from t2; id name diff --git a/mysql-test/r/ctype_many.result b/mysql-test/r/ctype_many.result index 3a9d0ec5da5..91a43634bcb 100644 --- a/mysql-test/r/ctype_many.result +++ b/mysql-test/r/ctype_many.result @@ -22,23 +22,23 @@ Table Create Table t1 CREATE TABLE `t1` ( `comment` char(32) character set latin2 NOT NULL default '', `koi8_ru_f` char(32) character set koi8r NOT NULL default '', - `latin5_f` char(32) character set latin5 NOT NULL default '' + `latin5_f` char(32) NOT NULL default '' ) TYPE=MyISAM CHARSET=latin5 ALTER TABLE t1 CHARSET=latin2; ALTER TABLE t1 ADD latin2_f CHAR(32) NOT NULL; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `comment` char(32) character set latin2 NOT NULL default '', + `comment` char(32) NOT NULL default '', `koi8_ru_f` char(32) character set koi8r NOT NULL default '', `latin5_f` char(32) character set latin5 NOT NULL default '', - `latin2_f` char(32) character set latin2 NOT NULL default '' + `latin2_f` char(32) NOT NULL default '' ) TYPE=MyISAM CHARSET=latin2 ALTER TABLE t1 DROP latin2_f, DROP latin5_f; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `comment` char(32) character set latin2 NOT NULL default '', + `comment` char(32) NOT NULL default '', `koi8_ru_f` char(32) character set koi8r NOT NULL default '' ) TYPE=MyISAM CHARSET=latin2 INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A'); diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 66aa7311542..1382c31d145 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -141,7 +141,7 @@ show create table t2; Table Create Table t2 CREATE TABLE `t2` ( `ticket` int(11) default NULL, - `inhalt` text character set latin1, + `inhalt` text, KEY `tig` (`ticket`), FULLTEXT KEY `tix` (`inhalt`) ) TYPE=MyISAM CHARSET=latin1 diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 110b8707bc8..f5bbf082730 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -805,7 +805,7 @@ create table t1 (a char(20), index (a(5))) type=innodb; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` char(20) character set latin1 default NULL, + `a` char(20) default NULL, KEY `a` (`a`) ) TYPE=InnoDB CHARSET=latin1 drop table t1; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 772ed0349da..9199f291c08 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -172,7 +172,7 @@ show create table t3; Table Create Table t3 CREATE TABLE `t3` ( `a` int(11) NOT NULL default '0', - `b` char(20) character set latin1 default NULL, + `b` char(20) default NULL, KEY `a` (`a`) ) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2) create table t4 (a int not null, b char(10), key(a)) type=MERGE UNION=(t1,t2); diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index f06194bb412..23610be36c4 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1,t2; CREATE TABLE t1 ( STRING_DATA char(255) default NULL, KEY string_data (STRING_DATA) @@ -316,3 +316,51 @@ CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255)); ALTER TABLE t1 ADD INDEX t1 (a, b, c); Specified key was too long. Max key length is 500 DROP TABLE t1; +CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a)); +INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4); +create table t2 (a int not null, b int, c int, key(b), key(c), key(a)); +INSERT into t2 values (1,1,1), (2,2,2); +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 b 1 b A 5 NULL NULL YES BTREE +t1 1 c 1 c A 5 NULL NULL YES BTREE +t1 1 a 1 a A 1 NULL NULL BTREE +t1 1 a 2 b A 5 NULL NULL YES BTREE +t1 1 c_2 1 c A 5 NULL NULL YES BTREE +t1 1 c_2 2 a A 5 NULL NULL BTREE +explain select * from t1,t2 where t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 5 +1 SIMPLE t2 ALL a NULL NULL NULL 2 Using where +explain select * from t1,t2 force index(a) where t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL a NULL NULL NULL 2 +1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where +explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL a NULL NULL NULL 2 +1 SIMPLE t1 ref a a 4 t2.a 3 +explain select * from t1,t2 where t1.b=t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL b NULL NULL NULL 2 +1 SIMPLE t1 ref b b 5 t2.b 1 Using where +explain select * from t1,t2 force index(c) where t1.a=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 5 +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where +explain select * from t1 where a=0 or a=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where +explain select * from t1 force index (a) where a=0 or a=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 4 NULL 4 Using where +explain select * from t1 where c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c,c_2 c 5 const 1 Using where +explain select * from t1 use index() where c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +drop table t1,t2; diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index 470a6302a2b..c3243d3a227 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -22,7 +22,7 @@ f 7 show binlog events; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 4 Start 1 4 Server ver: 4.1.0-alpha-debug-log, Binlog ver: 3 +master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 master-bin.000001 79 Query 1 79 use `test`; create table t1(f int) master-bin.000001 136 Query 1 136 use `test`; create table t2(f int) master-bin.000001 193 Query 1 193 use `test`; insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index bba10f408cb..9ed54f7c253 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3221,17 +3221,17 @@ Field Type Collation Null Key Default Extra Privileges Comment auto int(11) binary PRI NULL auto_increment select,insert,update,references fld1 int(6) unsigned zerofill binary UNI 000000 select,insert,update,references companynr tinyint(2) unsigned zerofill binary 00 select,insert,update,references -fld3 char(30) character set latin1 latin1 MUL select,insert,update,references -fld4 char(35) character set latin1 latin1 select,insert,update,references -fld5 char(35) character set latin1 latin1 select,insert,update,references -fld6 char(4) character set latin1 latin1 select,insert,update,references +fld3 char(30) latin1 MUL select,insert,update,references +fld4 char(35) latin1 select,insert,update,references +fld5 char(35) latin1 select,insert,update,references +fld6 char(4) latin1 select,insert,update,references show full columns from t2 from test like 'f%'; Field Type Collation Null Key Default Extra Privileges Comment fld1 int(6) unsigned zerofill binary UNI 000000 select,insert,update,references -fld3 char(30) character set latin1 latin1 MUL select,insert,update,references -fld4 char(35) character set latin1 latin1 select,insert,update,references -fld5 char(35) character set latin1 latin1 select,insert,update,references -fld6 char(4) character set latin1 latin1 select,insert,update,references +fld3 char(30) latin1 MUL select,insert,update,references +fld4 char(35) latin1 select,insert,update,references +fld5 char(35) latin1 select,insert,update,references +fld6 char(4) latin1 select,insert,update,references show full columns from t2 from test like 's%'; Field Type Collation Null Key Default Extra Privileges Comment show keys from t2; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 94170638730..d2bdc4f9401 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -93,14 +93,14 @@ c int not null comment 'int column' show create table t1 ; Table Create Table t1 CREATE TABLE `t1` ( - `test_set` set('val1','val2','val3') character set latin1 NOT NULL default '', - `name` char(20) character set latin1 default 'O''Brien' COMMENT 'O''Brien as default', + `test_set` set('val1','val2','val3') NOT NULL default '', + `name` char(20) default 'O''Brien' COMMENT 'O''Brien as default', `c` int(11) NOT NULL default '0' COMMENT 'int column' ) TYPE=MyISAM CHARSET=latin1 COMMENT='it''s a table' show full columns from t1; Field Type Collation Null Key Default Extra Privileges Comment -test_set set('val1','val2','val3') character set latin1 latin1 select,insert,update,references -name char(20) character set latin1 latin1 YES O'Brien select,insert,update,references O'Brien as default +test_set set('val1','val2','val3') latin1 select,insert,update,references +name char(20) latin1 YES O'Brien select,insert,update,references O'Brien as default c int(11) binary 0 select,insert,update,references int column drop table t1; create table t1 (a int not null, unique aa (a)); @@ -133,7 +133,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) NOT NULL default '0', - `b` char(10) character set latin1 default NULL, + `b` char(10) default NULL, KEY `b` (`b`) ) TYPE=MyISAM CHARSET=latin1 MIN_ROWS=10 MAX_ROWS=100 AVG_ROW_LENGTH=10 PACK_KEYS=1 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=FIXED COMMENT='test' alter table t1 MAX_ROWS=200 ROW_FORMAT=dynamic PACK_KEYS=0; @@ -141,7 +141,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) NOT NULL default '0', - `b` varchar(10) character set latin1 default NULL, + `b` varchar(10) default NULL, KEY `b` (`b`) ) TYPE=MyISAM CHARSET=latin1 MIN_ROWS=10 MAX_ROWS=200 AVG_ROW_LENGTH=10 PACK_KEYS=0 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC COMMENT='test' ALTER TABLE t1 AVG_ROW_LENGTH=0 CHECKSUM=0 COMMENT="" MIN_ROWS=0 MAX_ROWS=0 PACK_KEYS=DEFAULT DELAY_KEY_WRITE=0 ROW_FORMAT=default; @@ -149,7 +149,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) NOT NULL default '0', - `b` varchar(10) character set latin1 default NULL, + `b` varchar(10) default NULL, KEY `b` (`b`) ) TYPE=MyISAM CHARSET=latin1 drop table t1; diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result new file mode 100644 index 00000000000..8ded3daf114 --- /dev/null +++ b/mysql-test/r/sql_mode.result @@ -0,0 +1,87 @@ +drop table if exists t1; +CREATE TABLE `t1` ( +a int not null auto_increment, +`pseudo` varchar(35) character set latin2 NOT NULL default '', +`email` varchar(60) character set latin2 NOT NULL default '', +PRIMARY KEY (a), +UNIQUE KEY `email` USING BTREE (`email`) +) TYPE=HEAP CHARSET=latin1 ROW_FORMAT DYNAMIC; +set @@sql_mode=""; +show variables like 'sql_mode'; +Variable_name Value +sql_mode +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL auto_increment, + `pseudo` varchar(35) character set latin2 NOT NULL default '', + `email` varchar(60) character set latin2 NOT NULL default '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` TYPE BTREE (`email`) +) TYPE=HEAP CHARSET=latin1 ROW_FORMAT=DYNAMIC +set @@sql_mode="ansi_quotes"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode ANSI_QUOTES +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "a" int(11) NOT NULL auto_increment, + "pseudo" varchar(35) character set latin2 NOT NULL default '', + "email" varchar(60) character set latin2 NOT NULL default '', + PRIMARY KEY ("a"), + UNIQUE KEY "email" TYPE BTREE ("email") +) TYPE=HEAP CHARSET=latin1 ROW_FORMAT=DYNAMIC +set @@sql_mode="no_table_options"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode NO_TABLE_OPTIONS +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL auto_increment, + `pseudo` varchar(35) character set latin2 NOT NULL default '', + `email` varchar(60) character set latin2 NOT NULL default '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` TYPE BTREE (`email`) +) +set @@sql_mode="no_key_options"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode NO_KEY_OPTIONS +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL auto_increment, + `pseudo` varchar(35) character set latin2 NOT NULL default '', + `email` varchar(60) character set latin2 NOT NULL default '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` (`email`) +) TYPE=HEAP CHARSET=latin1 ROW_FORMAT=DYNAMIC +set @@sql_mode="no_field_options,mysql323,mysql40"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode NO_FIELD_OPTIONS,MYSQL323,MYSQL40 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL auto_increment, + `pseudo` varchar(35) NOT NULL default '', + `email` varchar(60) NOT NULL default '', + PRIMARY KEY (`a`), + UNIQUE KEY `email` (`email`) +) TYPE=HEAP ROW_FORMAT=DYNAMIC +set @@sql_mode="postgresql,oracle,mssql,db2,sapdb"; +show variables like 'sql_mode'; +Variable_name Value +sql_mode POSTGRESQL,ORACLE,MSSQL,DB2,SAPDB +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "a" int(11) NOT NULL, + "pseudo" varchar(35) NOT NULL default '', + "email" varchar(60) NOT NULL default '', + PRIMARY KEY ("a"), + UNIQUE KEY "email" ("email") +) +drop table t1; diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 3248e3c5c80..ba8e01d6319 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -3,10 +3,10 @@ CREATE TABLE t1 (a blob, b text, c blob(250), d text(70000), e text(70000000)); show columns from t1; Field Type Collation Null Key Default Extra a blob binary YES NULL -b text character set latin1 latin1 YES NULL +b text latin1 YES NULL c blob binary YES NULL -d mediumtext character set latin1 latin1 YES NULL -e longtext character set latin1 latin1 YES NULL +d mediumtext latin1 YES NULL +e longtext latin1 YES NULL CREATE TABLE t2 (a char(257), b varchar(70000) binary, c varchar(70000000)); Warnings: Warning 1244 Converting column 'a' from CHAR to TEXT @@ -14,14 +14,14 @@ Warning 1244 Converting column 'b' from CHAR to BLOB Warning 1244 Converting column 'c' from CHAR to TEXT show columns from t2; Field Type Collation Null Key Default Extra -a text character set latin1 latin1 YES NULL +a text latin1 YES NULL b mediumblob binary YES NULL -c longtext character set latin1 latin1 YES NULL +c longtext latin1 YES NULL create table t3 (a long, b long byte); show create TABLE t3; Table Create Table t3 CREATE TABLE `t3` ( - `a` mediumtext character set latin1, + `a` mediumtext, `b` mediumblob ) TYPE=MyISAM CHARSET=latin1 drop table t1,t2,t3 @@ -70,15 +70,15 @@ update t1 set c="",b=null where c="1"; lock tables t1 READ; show full fields from t1; Field Type Collation Null Key Default Extra Privileges Comment -t text character set latin1 latin1 YES NULL select,insert,update,references -c varchar(10) character set latin1 latin1 YES NULL select,insert,update,references +t text latin1 YES NULL select,insert,update,references +c varchar(10) latin1 YES NULL select,insert,update,references b blob binary YES NULL select,insert,update,references d varchar(10) binary binary YES NULL select,insert,update,references lock tables t1 WRITE; show full fields from t1; Field Type Collation Null Key Default Extra Privileges Comment -t text character set latin1 latin1 YES NULL select,insert,update,references -c varchar(10) character set latin1 latin1 YES NULL select,insert,update,references +t text latin1 YES NULL select,insert,update,references +c varchar(10) latin1 YES NULL select,insert,update,references b blob binary YES NULL select,insert,update,references d varchar(10) binary binary YES NULL select,insert,update,references unlock tables; diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index 51e11d259eb..c0f0be246c9 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -1626,13 +1626,13 @@ create table t1 (a enum (' ','a','b') not null); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` enum('','a','b') character set latin1 NOT NULL default '' + `a` enum('','a','b') NOT NULL default '' ) TYPE=MyISAM CHARSET=latin1 drop table t1; create table t1 (a enum (' ','a','b ') not null default 'b '); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` enum('','a','b') character set latin1 NOT NULL default 'b' + `a` enum('','a','b') NOT NULL default 'b' ) TYPE=MyISAM CHARSET=latin1 drop table t1; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index b570513a5e7..19f1ac2b4d7 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -40,7 +40,7 @@ KEY (options,flags) show full fields from t1; Field Type Collation Null Key Default Extra Privileges Comment auto int(5) unsigned binary PRI NULL auto_increment select,insert,update,references -string varchar(10) character set latin1 latin1 YES hello select,insert,update,references +string varchar(10) latin1 YES hello select,insert,update,references tiny tinyint(4) binary MUL 0 select,insert,update,references short smallint(6) binary MUL 1 select,insert,update,references medium mediumint(8) binary MUL 0 select,insert,update,references @@ -61,8 +61,8 @@ blob_col blob binary YES NULL select,insert,update,references tinyblob_col tinyblob binary YES NULL select,insert,update,references mediumblob_col mediumblob binary select,insert,update,references longblob_col longblob binary select,insert,update,references -options enum('one','two','tree') character set latin1 latin1 MUL one select,insert,update,references -flags set('one','two','tree') character set latin1 latin1 select,insert,update,references +options enum('one','two','tree') latin1 MUL one select,insert,update,references +flags set('one','two','tree') latin1 select,insert,update,references show keys from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 0 PRIMARY 1 auto A 0 NULL NULL BTREE @@ -170,7 +170,7 @@ update t2 set string="changed" where auto=16; show full columns from t1; Field Type Collation Null Key Default Extra Privileges Comment auto int(5) unsigned binary MUL NULL auto_increment select,insert,update,references -string varchar(10) character set latin1 latin1 YES new defaul select,insert,update,references +string varchar(10) latin1 YES new defaul select,insert,update,references tiny tinyint(4) binary MUL 0 select,insert,update,references short smallint(6) binary MUL 0 select,insert,update,references medium mediumint(8) binary MUL 0 select,insert,update,references @@ -184,19 +184,19 @@ umedium mediumint(8) unsigned binary MUL 0 select,insert,update,references ulong int(11) unsigned binary MUL 0 select,insert,update,references ulonglong bigint(13) unsigned binary MUL 0 select,insert,update,references time_stamp timestamp latin1 YES NULL select,insert,update,references -date_field varchar(10) character set latin1 latin1 YES NULL select,insert,update,references +date_field varchar(10) latin1 YES NULL select,insert,update,references time_field time latin1 YES NULL select,insert,update,references date_time datetime latin1 YES NULL select,insert,update,references -new_blob_col varchar(20) character set latin1 latin1 YES NULL select,insert,update,references +new_blob_col varchar(20) latin1 YES NULL select,insert,update,references tinyblob_col tinyblob binary YES NULL select,insert,update,references mediumblob_col mediumblob binary select,insert,update,references -options enum('one','two','tree') character set latin1 latin1 MUL one select,insert,update,references -flags set('one','two','tree') character set latin1 latin1 select,insert,update,references -new_field varchar(10) character set latin1 latin1 new select,insert,update,references +options enum('one','two','tree') latin1 MUL one select,insert,update,references +flags set('one','two','tree') latin1 select,insert,update,references +new_field varchar(10) latin1 new select,insert,update,references show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment auto int(5) unsigned binary 0 select,insert,update,references -string varchar(10) character set latin1 latin1 YES new defaul select,insert,update,references +string varchar(10) latin1 YES new defaul select,insert,update,references tiny tinyint(4) binary 0 select,insert,update,references short smallint(6) binary 0 select,insert,update,references medium mediumint(8) binary 0 select,insert,update,references @@ -210,15 +210,15 @@ umedium mediumint(8) unsigned binary 0 select,insert,update,references ulong int(11) unsigned binary 0 select,insert,update,references ulonglong bigint(13) unsigned binary 0 select,insert,update,references time_stamp timestamp latin1 YES NULL select,insert,update,references -date_field varchar(10) character set latin1 latin1 YES NULL select,insert,update,references +date_field varchar(10) latin1 YES NULL select,insert,update,references time_field time latin1 YES NULL select,insert,update,references date_time datetime latin1 YES NULL select,insert,update,references -new_blob_col varchar(20) character set latin1 latin1 YES NULL select,insert,update,references +new_blob_col varchar(20) latin1 YES NULL select,insert,update,references tinyblob_col tinyblob binary YES NULL select,insert,update,references mediumblob_col mediumblob binary select,insert,update,references -options enum('one','two','tree') character set latin1 latin1 one select,insert,update,references -flags set('one','two','tree') character set latin1 latin1 select,insert,update,references -new_field varchar(10) character set latin1 latin1 new select,insert,update,references +options enum('one','two','tree') latin1 one select,insert,update,references +flags set('one','two','tree') latin1 select,insert,update,references +new_field varchar(10) latin1 new select,insert,update,references select t1.auto,t2.auto from t1,t2 where t1.auto=t2.auto and ((t1.string<>t2.string and (t1.string is not null or t2.string is not null)) or (t1.tiny<>t2.tiny and (t1.tiny is not null or t2.tiny is not null)) or (t1.short<>t2.short and (t1.short is not null or t2.short is not null)) or (t1.medium<>t2.medium and (t1.medium is not null or t2.medium is not null)) or (t1.long_int<>t2.long_int and (t1.long_int is not null or t2.long_int is not null)) or (t1.longlong<>t2.longlong and (t1.longlong is not null or t2.longlong is not null)) or (t1.real_float<>t2.real_float and (t1.real_float is not null or t2.real_float is not null)) or (t1.real_double<>t2.real_double and (t1.real_double is not null or t2.real_double is not null)) or (t1.utiny<>t2.utiny and (t1.utiny is not null or t2.utiny is not null)) or (t1.ushort<>t2.ushort and (t1.ushort is not null or t2.ushort is not null)) or (t1.umedium<>t2.umedium and (t1.umedium is not null or t2.umedium is not null)) or (t1.ulong<>t2.ulong and (t1.ulong is not null or t2.ulong is not null)) or (t1.ulonglong<>t2.ulonglong and (t1.ulonglong is not null or t2.ulonglong is not null)) or (t1.time_stamp<>t2.time_stamp and (t1.time_stamp is not null or t2.time_stamp is not null)) or (t1.date_field<>t2.date_field and (t1.date_field is not null or t2.date_field is not null)) or (t1.time_field<>t2.time_field and (t1.time_field is not null or t2.time_field is not null)) or (t1.date_time<>t2.date_time and (t1.date_time is not null or t2.date_time is not null)) or (t1.new_blob_col<>t2.new_blob_col and (t1.new_blob_col is not null or t2.new_blob_col is not null)) or (t1.tinyblob_col<>t2.tinyblob_col and (t1.tinyblob_col is not null or t2.tinyblob_col is not null)) or (t1.mediumblob_col<>t2.mediumblob_col and (t1.mediumblob_col is not null or t2.mediumblob_col is not null)) or (t1.options<>t2.options and (t1.options is not null or t2.options is not null)) or (t1.flags<>t2.flags and (t1.flags is not null or t2.flags is not null)) or (t1.new_field<>t2.new_field and (t1.new_field is not null or t2.new_field is not null))); auto auto 16 16 @@ -231,8 +231,8 @@ show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment auto bigint(17) unsigned binary PRI 0 select,insert,update,references t1 bigint(1) binary 0 select,insert,update,references -t2 char(1) character set latin1 latin1 select,insert,update,references -t3 mediumtext character set latin1 latin1 select,insert,update,references +t2 char(1) latin1 select,insert,update,references +t3 mediumtext latin1 select,insert,update,references t4 mediumblob binary select,insert,update,references select * from t2; auto t1 t2 t3 t4 diff --git a/mysql-test/r/type_set.result b/mysql-test/r/type_set.result index 256937c586a..b0ea1b69e59 100644 --- a/mysql-test/r/type_set.result +++ b/mysql-test/r/type_set.result @@ -3,13 +3,13 @@ create table t1 (a set (' ','a','b') not null); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` set('','a','b') character set latin1 NOT NULL default '' + `a` set('','a','b') NOT NULL default '' ) TYPE=MyISAM CHARSET=latin1 drop table t1; create table t1 (a set (' ','a','b ') not null default 'b '); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` set('','a','b') character set latin1 NOT NULL default 'b' + `a` set('','a','b') NOT NULL default 'b' ) TYPE=MyISAM CHARSET=latin1 drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 94f304c77b1..e546a8c8284 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -85,7 +85,7 @@ a b 2 b 1 a (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; -Table 't1' from one of SELECT's can not be used in order clause +Table 't1' from one of SELECT's can not be used in global ORDER clause explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index 06be16aad48..f2a105827da 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -13,3 +13,20 @@ set SQL_WARNINGS=0; drop temporary table if exists not_exists; Warnings: Note 1051 Unknown table 'not_exists' +drop table if exists not_exists_table; +Warnings: +Note 1051 Unknown table 'not_exists_table' +show warnings limit 1; +Level Code Message +Note 1051 Unknown table 'not_exists_table' +drop database if exists not_exists_db; +Warnings: +Note 1008 Can't drop database 'not_exists_db'. Database doesn't exist +show count(*) warnings; +@@session.warning_count +1 +create table t1(id int); +create table if not exists t1(id int); +select @@warning_count; +@@warning_count +0 diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 0a3bd4e97a1..70a589c4be6 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1,t2; +drop table if exists t1,t2,t3; --enable_warnings create table t1 (b char(0)); diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 780a060e204..ed08b1cbacb 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -2,10 +2,15 @@ # Test bugs in the MyISAM code # +# Initialise --disable_warnings -drop table if exists t1; +drop table if exists t1,t2; --enable_warnings +# +# Test problem with CHECK TABLE; +# + CREATE TABLE t1 ( STRING_DATA char(255) default NULL, KEY string_data (STRING_DATA) @@ -327,3 +332,23 @@ CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255)); ALTER TABLE t1 ADD INDEX t1 (a, b, c); DROP TABLE t1; +# +# Test of cardinality of keys with NULL +# + +CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a)); +INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4); +create table t2 (a int not null, b int, c int, key(b), key(c), key(a)); +INSERT into t2 values (1,1,1), (2,2,2); +optimize table t1; +show index from t1; +explain select * from t1,t2 where t1.a=t2.a; +explain select * from t1,t2 force index(a) where t1.a=t2.a; +explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a; +explain select * from t1,t2 where t1.b=t2.b; +explain select * from t1,t2 force index(c) where t1.a=t2.a; +explain select * from t1 where a=0 or a=2; +explain select * from t1 force index (a) where a=0 or a=2; +explain select * from t1 where c=1; +explain select * from t1 use index() where c=1; +drop table t1,t2; diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 75519b75f75..f91880537e6 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -3,6 +3,8 @@ source include/master-slave.inc; connect (con1,localhost,root,,); connect (con2,localhost,root,,); +let $VERSION=`select version()`; + --disable_warnings drop table if exists t1,t2; --enable_warnings @@ -38,6 +40,7 @@ drop temporary table t3; select * from t2; +--replace_result $VERSION VERSION show binlog events; drop table t1, t2; diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test new file mode 100644 index 00000000000..fd464f74de4 --- /dev/null +++ b/mysql-test/t/sql_mode.test @@ -0,0 +1,30 @@ +--disable_warnings +drop table if exists t1; +--enable_warnings + +CREATE TABLE `t1` ( + a int not null auto_increment, + `pseudo` varchar(35) character set latin2 NOT NULL default '', + `email` varchar(60) character set latin2 NOT NULL default '', + PRIMARY KEY (a), + UNIQUE KEY `email` USING BTREE (`email`) +) TYPE=HEAP CHARSET=latin1 ROW_FORMAT DYNAMIC; +set @@sql_mode=""; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="ansi_quotes"; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="no_table_options"; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="no_key_options"; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="no_field_options,mysql323,mysql40"; +show variables like 'sql_mode'; +show create table t1; +set @@sql_mode="postgresql,oracle,mssql,db2,sapdb"; +show variables like 'sql_mode'; +show create table t1; +drop table t1; diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test index eeb45eaba56..8cff8706c43 100644 --- a/mysql-test/t/warnings.test +++ b/mysql-test/t/warnings.test @@ -19,3 +19,10 @@ set SQL_WARNINGS=0; # Test other warnings drop temporary table if exists not_exists; +drop table if exists not_exists_table; +show warnings limit 1; +drop database if exists not_exists_db; +show count(*) warnings; +create table t1(id int); +create table if not exists t1(id int); +select @@warning_count; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index c8b7987a506..b93ddd2241d 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -50,7 +50,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ my_getopt.c my_mkdir.c \ default.c my_compress.c checksum.c raid.cc \ my_net.c my_semaphore.c my_port.c \ - my_vsnprintf.c charset.c xml.c my_bitmap.c my_bit.c md5.c \ + charset.c my_bitmap.c my_bit.c md5.c \ my_gethostbyname.c rijndael.c my_aes.c sha1.c \ my_handler.c EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ diff --git a/mysys/charset.c b/mysys/charset.c index 8d852fd99c2..591ba568e3d 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -22,391 +22,18 @@ #include -static void set_max_sort_char(CHARSET_INFO *cs); -static my_bool create_fromuni(CHARSET_INFO *cs); +/* - -#define MY_CHARSET_INDEX "Index.xml" - -const char *charsets_dir= NULL; -static int charset_initialized=0; - -#define MAX_LINE 1024 - -#define CTYPE_TABLE_SIZE 257 -#define TO_LOWER_TABLE_SIZE 256 -#define TO_UPPER_TABLE_SIZE 256 -#define SORT_ORDER_TABLE_SIZE 256 -#define TO_UNI_TABLE_SIZE 256 - - -char *get_charsets_dir(char *buf) -{ - const char *sharedir= SHAREDIR; - DBUG_ENTER("get_charsets_dir"); - - if (charsets_dir != NULL) - strmake(buf, charsets_dir, FN_REFLEN-1); - else - { - if (test_if_hard_path(sharedir) || - is_prefix(sharedir, DEFAULT_CHARSET_HOME)) - strxmov(buf, sharedir, "/", CHARSET_DIR, NullS); - else - strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR, - NullS); - } - convert_dirname(buf,buf,NullS); - DBUG_PRINT("info",("charsets dir: '%s'", buf)); - DBUG_RETURN(strend(buf)); -} - - -#define MAX_BUF 1024*16 - -#ifndef DBUG_OFF -static void mstr(char *str,const char *src,uint l1,uint l2) -{ - l1= l1str; s++) - { - if (!strncmp(attr,s->str,len)) - return s; - } - return NULL; -} - -#define CS_MAX_NM_LEN 32 - -struct my_cs_file_info -{ - char csname[CS_MAX_NM_LEN]; - char name[CS_MAX_NM_LEN]; - uchar ctype[CTYPE_TABLE_SIZE]; - uchar to_lower[TO_LOWER_TABLE_SIZE]; - uchar to_upper[TO_UPPER_TABLE_SIZE]; - uchar sort_order[SORT_ORDER_TABLE_SIZE]; - uint16 tab_to_uni[TO_UNI_TABLE_SIZE]; - CHARSET_INFO cs; - myf myflags; -}; - -static void simple_cs_init_functions(CHARSET_INFO *cs) -{ - cs->like_range = my_like_range_simple; - cs->wildcmp = my_wildcmp_8bit; - cs->strnncoll = my_strnncoll_simple; - cs->caseup_str = my_caseup_str_8bit; - cs->casedn_str = my_casedn_str_8bit; - cs->caseup = my_caseup_8bit; - cs->casedn = my_casedn_8bit; - cs->tosort = my_tosort_8bit; - cs->strcasecmp = my_strcasecmp_8bit; - cs->strncasecmp = my_strncasecmp_8bit; - cs->mb_wc = my_mb_wc_8bit; - cs->wc_mb = my_wc_mb_8bit; - cs->hash_caseup = my_hash_caseup_simple; - cs->hash_sort = my_hash_sort_simple; - cs->snprintf = my_snprintf_8bit; - cs->strntol = my_strntol_8bit; - cs->strntoul = my_strntoul_8bit; - cs->strntoll = my_strntoll_8bit; - cs->strntoull = my_strntoull_8bit; - cs->strntod = my_strntod_8bit; - cs->mbmaxlen = 1; -} - - -static void simple_cs_copy_data(CHARSET_INFO *to, CHARSET_INFO *from) -{ - to->number= from->number ? from->number : to->number; - to->state|= from->state; - - if (from->csname) - to->csname= my_once_strdup(from->csname,MYF(MY_WME)); + The code below implements this functionality: - if (from->name) - to->name= my_once_strdup(from->name,MYF(MY_WME)); - - if (from->ctype) - to->ctype= (uchar*) my_once_memdup((char*) from->ctype, - CTYPE_TABLE_SIZE, MYF(MY_WME)); - if (from->to_lower) - to->to_lower= (uchar*) my_once_memdup((char*) from->to_lower, - TO_LOWER_TABLE_SIZE, MYF(MY_WME)); - if (from->to_upper) - to->to_upper= (uchar*) my_once_memdup((char*) from->to_upper, - TO_UPPER_TABLE_SIZE, MYF(MY_WME)); - if (from->sort_order) - { - to->sort_order= (uchar*) my_once_memdup((char*) from->sort_order, - SORT_ORDER_TABLE_SIZE, - MYF(MY_WME)); - set_max_sort_char(to); - } - if (from->tab_to_uni) - { - uint sz=TO_UNI_TABLE_SIZE*sizeof(uint16); - to->tab_to_uni= (uint16*) my_once_memdup((char*)from->tab_to_uni, sz, - MYF(MY_WME)); - create_fromuni(to); - } -} + - Initializing charset related structures + - Loading dynamic charsets + - Searching for a proper CHARSET_INFO + using charset name, collation name or collatio ID + - Setting server default character set +*/ -static my_bool simple_cs_is_full(CHARSET_INFO *cs) -{ - return ((cs->csname && cs->tab_to_uni && cs->ctype && cs->to_upper && - cs->to_lower) && - (cs->number && cs->name && cs->sort_order)); -} - - -static int fill_uchar(uchar *a,uint size,const char *str, uint len) -{ - uint i= 0; - const char *s, *b, *e=str+len; - - for (s=str ; s < e ; i++) - { - for ( ; (s < e) && strchr(" \t\r\n",s[0]); s++) ; - b=s; - for ( ; (s < e) && !strchr(" \t\r\n",s[0]); s++) ; - if (s == b || i > size) - break; - a[i]= my_strntoul(my_charset_latin1,b,s-b,NULL,16); - } - return 0; -} - -static int fill_uint16(uint16 *a,uint size,const char *str, uint len) -{ - uint i= 0; - const char *s, *b, *e=str+len; - for (s=str ; s < e ; i++) - { - for ( ; (s < e) && strchr(" \t\r\n",s[0]); s++) ; - b=s; - for ( ; (s < e) && !strchr(" \t\r\n",s[0]); s++) ; - if (s == b || i > size) - break; - a[i]= my_strntol(my_charset_latin1,b,s-b,NULL,16); - } - return 0; -} - - -static int cs_enter(MY_XML_PARSER *st,const char *attr, uint len) -{ - struct my_cs_file_info *i= (struct my_cs_file_info *)st->user_data; - struct my_cs_file_section_st *s= cs_file_sec(attr,len); - - if ( s && (s->state == _CS_CHARSET)) - { - bzero(&i->cs,sizeof(i->cs)); - } - return MY_XML_OK; -} - - -static int cs_leave(MY_XML_PARSER *st,const char *attr, uint len) -{ - struct my_cs_file_info *i= (struct my_cs_file_info *)st->user_data; - struct my_cs_file_section_st *s= cs_file_sec(attr,len); - int state= s ? s->state : 0; - - if (state == _CS_COLLATION) - { - if (i->cs.name && (i->cs.number || - (i->cs.number=get_charset_number(i->cs.name)))) - { - if (!all_charsets[i->cs.number]) - { - if (!(all_charsets[i->cs.number]= - (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),i->myflags))) - return MY_XML_ERROR; - bzero((void*)all_charsets[i->cs.number],sizeof(CHARSET_INFO)); - } - - if (!(all_charsets[i->cs.number]->state & MY_CS_COMPILED)) - { - simple_cs_copy_data(all_charsets[i->cs.number],&i->cs); - if (simple_cs_is_full(all_charsets[i->cs.number])) - { - simple_cs_init_functions(all_charsets[i->cs.number]); - all_charsets[i->cs.number]->state |= MY_CS_LOADED; - } - } - i->cs.number= 0; - i->cs.name= NULL; - i->cs.state= 0; - i->cs.sort_order= NULL; - i->cs.state= 0; - } - } - return MY_XML_OK; -} - - -static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) -{ - struct my_cs_file_info *i= (struct my_cs_file_info *)st->user_data; - struct my_cs_file_section_st *s; - int state= (s=cs_file_sec(st->attr,strlen(st->attr))) ? s->state : 0; - -#ifndef DBUG_OFF - if(0){ - char str[1024]; - mstr(str,attr,len,sizeof(str)-1); - printf("VALUE %d %s='%s'\n",state,st->attr,str); - } -#endif - - switch (state) { - case _CS_ID: - i->cs.number= my_strntoul(my_charset_latin1,attr,len,(char**)NULL,0); - break; - case _CS_COLNAME: - memcpy(i->name,attr,len=min(len,CS_MAX_NM_LEN-1)); - i->name[len]='\0'; - i->cs.name=i->name; - break; - case _CS_NAME: - memcpy(i->csname,attr,len=min(len,CS_MAX_NM_LEN-1)); - i->csname[len]='\0'; - i->cs.csname=i->csname; - break; - case _CS_FLAG: - if (!strncmp("primary",attr,len)) - i->cs.state|= MY_CS_PRIMARY; - break; - case _CS_UPPERMAP: - fill_uchar(i->to_upper,TO_UPPER_TABLE_SIZE,attr,len); - i->cs.to_upper=i->to_upper; - break; - case _CS_LOWERMAP: - fill_uchar(i->to_lower,TO_LOWER_TABLE_SIZE,attr,len); - i->cs.to_lower=i->to_lower; - break; - case _CS_UNIMAP: - fill_uint16(i->tab_to_uni,TO_UNI_TABLE_SIZE,attr,len); - i->cs.tab_to_uni=i->tab_to_uni; - break; - case _CS_COLLMAP: - fill_uchar(i->sort_order,SORT_ORDER_TABLE_SIZE,attr,len); - i->cs.sort_order=i->sort_order; - break; - case _CS_CTYPEMAP: - fill_uchar(i->ctype,CTYPE_TABLE_SIZE,attr,len); - i->cs.ctype=i->ctype; - break; - } - return MY_XML_OK; -} - - -static my_bool read_charset_index(const char *filename, myf myflags) -{ - char *buf; - int fd; - uint len; - MY_XML_PARSER p; - struct my_cs_file_info i; - - if (!(buf= (char *)my_malloc(MAX_BUF,myflags))) - return FALSE; - - strmov(get_charsets_dir(buf), filename); - - if ((fd=my_open(buf,O_RDONLY,myflags)) < 0) - { - my_free(buf,myflags); - return TRUE; - } - - len=read(fd,buf,MAX_BUF); - my_xml_parser_create(&p); - my_close(fd,myflags); - - my_xml_set_enter_handler(&p,cs_enter); - my_xml_set_value_handler(&p,cs_value); - my_xml_set_leave_handler(&p,cs_leave); - my_xml_set_user_data(&p,(void*)&i); - - if (my_xml_parse(&p,buf,len) != MY_XML_OK) - { -#ifdef NOT_YET - printf("ERROR at line %d pos %d '%s'\n", - my_xml_error_lineno(&p)+1, - my_xml_error_pos(&p), - my_xml_error_string(&p)); -#endif - } - - my_xml_parser_free(&p); - my_free(buf, myflags); - return FALSE; -} - static void set_max_sort_char(CHARSET_INFO *cs) { uchar max_char; @@ -426,48 +53,35 @@ static void set_max_sort_char(CHARSET_INFO *cs) } } -static my_bool init_available_charsets(myf myflags) + +static void simple_cs_init_functions(CHARSET_INFO *cs) { - my_bool error=FALSE; - /* - We have to use charset_initialized to not lock on THR_LOCK_charset - inside get_internal_charset... - */ - if (!charset_initialized) - { - CHARSET_INFO **cs; - /* - To make things thread safe we are not allowing other threads to interfere - while we may changing the cs_info_table - */ - pthread_mutex_lock(&THR_LOCK_charset); - - bzero(&all_charsets,sizeof(all_charsets)); - init_compiled_charsets(myflags); - - /* Copy compiled charsets */ - for (cs=all_charsets; cs < all_charsets+255 ; cs++) - { - if (*cs) - set_max_sort_char(*cs); - } - error= read_charset_index(MY_CHARSET_INDEX,myflags); - charset_initialized=1; - pthread_mutex_unlock(&THR_LOCK_charset); - } - return error; -} - - -void free_charsets(void) -{ - charset_initialized=0; -} - - -static void get_charset_conf_name(const char *cs_name, char *buf) -{ - strxmov(get_charsets_dir(buf), cs_name, ".conf", NullS); + + cs->strnxfrm = my_strnxfrm_simple; + cs->strnncoll = my_strnncoll_simple; + cs->like_range = my_like_range_simple; + cs->wildcmp = my_wildcmp_8bit; + cs->mb_wc = my_mb_wc_8bit; + cs->wc_mb = my_wc_mb_8bit; + cs->caseup_str = my_caseup_str_8bit; + cs->casedn_str = my_casedn_str_8bit; + cs->caseup = my_caseup_8bit; + cs->casedn = my_casedn_8bit; + cs->tosort = my_tosort_8bit; + cs->strcasecmp = my_strcasecmp_8bit; + cs->strncasecmp = my_strncasecmp_8bit; + cs->hash_caseup = my_hash_caseup_simple; + cs->hash_sort = my_hash_sort_simple; + cs->snprintf = my_snprintf_8bit; + cs->long10_to_str= my_long10_to_str_8bit; + cs->longlong10_to_str= my_longlong10_to_str_8bit; + cs->strntol = my_strntol_8bit; + cs->strntoul = my_strntoul_8bit; + cs->strntoll = my_strntoll_8bit; + cs->strntoull = my_strntoull_8bit; + cs->strntod = my_strntod_8bit; + cs->scan = my_scan_8bit; + cs->mbmaxlen = 1; } @@ -563,6 +177,190 @@ static my_bool create_fromuni(CHARSET_INFO *cs) } +static void simple_cs_copy_data(CHARSET_INFO *to, CHARSET_INFO *from) +{ + to->number= from->number ? from->number : to->number; + to->state|= from->state; + + if (from->csname) + to->csname= my_once_strdup(from->csname,MYF(MY_WME)); + + if (from->name) + to->name= my_once_strdup(from->name,MYF(MY_WME)); + + if (from->ctype) + to->ctype= (uchar*) my_once_memdup((char*) from->ctype, + MY_CS_CTYPE_TABLE_SIZE, MYF(MY_WME)); + if (from->to_lower) + to->to_lower= (uchar*) my_once_memdup((char*) from->to_lower, + MY_CS_TO_LOWER_TABLE_SIZE, MYF(MY_WME)); + if (from->to_upper) + to->to_upper= (uchar*) my_once_memdup((char*) from->to_upper, + MY_CS_TO_UPPER_TABLE_SIZE, MYF(MY_WME)); + if (from->sort_order) + { + to->sort_order= (uchar*) my_once_memdup((char*) from->sort_order, + MY_CS_SORT_ORDER_TABLE_SIZE, + MYF(MY_WME)); + set_max_sort_char(to); + } + if (from->tab_to_uni) + { + uint sz= MY_CS_TO_UNI_TABLE_SIZE*sizeof(uint16); + to->tab_to_uni= (uint16*) my_once_memdup((char*)from->tab_to_uni, sz, + MYF(MY_WME)); + create_fromuni(to); + } +} + + +static my_bool simple_cs_is_full(CHARSET_INFO *cs) +{ + return ((cs->csname && cs->tab_to_uni && cs->ctype && cs->to_upper && + cs->to_lower) && + (cs->number && cs->name && cs->sort_order)); +} + + +static int add_collation(CHARSET_INFO *cs) +{ + if (cs->name && (cs->number || (cs->number=get_charset_number(cs->name)))) + { + if (!all_charsets[cs->number]) + { + if (!(all_charsets[cs->number]= + (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),MYF(0)))) + return MY_XML_ERROR; + bzero((void*)all_charsets[cs->number],sizeof(CHARSET_INFO)); + } + + if (!(all_charsets[cs->number]->state & MY_CS_COMPILED)) + { + simple_cs_copy_data(all_charsets[cs->number],cs); + if (simple_cs_is_full(all_charsets[cs->number])) + { + simple_cs_init_functions(all_charsets[cs->number]); + all_charsets[cs->number]->state |= MY_CS_LOADED; + } + } + cs->number= 0; + cs->name= NULL; + cs->state= 0; + cs->sort_order= NULL; + cs->state= 0; + } + return MY_XML_OK; +} + + +#define MAX_BUF 1024*16 +#define MY_CHARSET_INDEX "Index.xml" + +const char *charsets_dir= NULL; +static int charset_initialized=0; + + +static my_bool my_read_charset_file(const char *filename, myf myflags) +{ + char *buf; + int fd; + uint len; + + if (!(buf= (char *)my_malloc(MAX_BUF,myflags))) + return FALSE; + + if ((fd=my_open(filename,O_RDONLY,myflags)) < 0) + { + my_free(buf,myflags); + return TRUE; + } + len=read(fd,buf,MAX_BUF); + my_close(fd,myflags); + + if (my_parse_charset_xml(buf,len,add_collation)) + { +#ifdef NOT_YET + printf("ERROR at line %d pos %d '%s'\n", + my_xml_error_lineno(&p)+1, + my_xml_error_pos(&p), + my_xml_error_string(&p)); +#endif + } + + my_free(buf, myflags); + return FALSE; +} + + +char *get_charsets_dir(char *buf) +{ + const char *sharedir= SHAREDIR; + DBUG_ENTER("get_charsets_dir"); + + if (charsets_dir != NULL) + strmake(buf, charsets_dir, FN_REFLEN-1); + else + { + if (test_if_hard_path(sharedir) || + is_prefix(sharedir, DEFAULT_CHARSET_HOME)) + strxmov(buf, sharedir, "/", CHARSET_DIR, NullS); + else + strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR, + NullS); + } + convert_dirname(buf,buf,NullS); + DBUG_PRINT("info",("charsets dir: '%s'", buf)); + DBUG_RETURN(strend(buf)); +} + +static my_bool init_available_charsets(myf myflags) +{ + char fname[FN_REFLEN]; + my_bool error=FALSE; + /* + We have to use charset_initialized to not lock on THR_LOCK_charset + inside get_internal_charset... + */ + if (!charset_initialized) + { + CHARSET_INFO **cs; + /* + To make things thread safe we are not allowing other threads to interfere + while we may changing the cs_info_table + */ + pthread_mutex_lock(&THR_LOCK_charset); + + bzero(&all_charsets,sizeof(all_charsets)); + init_compiled_charsets(myflags); + + /* Copy compiled charsets */ + for (cs=all_charsets; cs < all_charsets+255 ; cs++) + { + if (*cs) + set_max_sort_char(*cs); + } + + strmov(get_charsets_dir(fname), MY_CHARSET_INDEX); + error= my_read_charset_file(fname,myflags); + charset_initialized=1; + pthread_mutex_unlock(&THR_LOCK_charset); + } + return error; +} + + +void free_charsets(void) +{ + charset_initialized=0; +} + + +static void get_charset_conf_name(const char *cs_name, char *buf) +{ + strxmov(get_charsets_dir(buf), cs_name, ".conf", NullS); +} + + uint get_charset_number(const char *charset_name) { CHARSET_INFO **cs; @@ -606,8 +404,8 @@ static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags) if (cs && !(cs->state & (MY_CS_COMPILED | MY_CS_LOADED))) { - strxmov(buf, cs->csname, ".xml", NullS); - read_charset_index(buf,flags); + strxmov(get_charsets_dir(buf), cs->csname, ".xml", NullS); + my_read_charset_file(buf,flags); cs= (cs->state & MY_CS_LOADED) ? cs : NULL; } pthread_mutex_unlock(&THR_LOCK_charset); diff --git a/mysys/my_handler.c b/mysys/my_handler.c index 2d51ab13f69..2fd7f1fcdee 100644 --- a/mysys/my_handler.c +++ b/mysys/my_handler.c @@ -40,15 +40,33 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, return (int) (a_length-b_length); } -#define FCMP(A,B) ((int) (A) - (int) (B)) /* Compare two keys - Returns <0, 0, >0 acording to which is bigger - Key_length specifies length of key to use. Number-keys can't be splited - If flag <> SEARCH_FIND compare also position + + SYNOPSIS + ha_key_cmp() + keyseg Key segments of key to compare + a First key to compare, in format from _mi_pack_key() + This is normally key specified by user + b Second key to compare. This is always from a row + key_length Length of key to compare. This can be shorter than + a to just compare sub keys + next_flag How keys should be compared + If bit SEARCH_FIND is not set the keys includes the row + position and this should also be compared + + NOTES + Number-keys can't be splited + + RETURN VALUES + <0 If a < b + 0 If a == b + >0 If a > b */ +#define FCMP(A,B) ((int) (A) - (int) (B)) + int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, register uchar *b, uint key_length, uint nextflag, uint *diff_pos) @@ -59,9 +77,10 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, uint32 u_1,u_2; float f_1,f_2; double d_1,d_2; + uint next_key_length; *diff_pos=0; - for ( ; (int) key_length >0 ; keyseg++) + for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++) { uchar *end; uint piks=! (keyseg->flag & HA_NO_SORT); @@ -81,10 +100,21 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, { if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) nextflag=SEARCH_SAME; /* Allow duplicate keys */ + else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL) + { + /* + This is only used from mi_check() to calculate cardinality. + It can't be used when searching for a key as this would cause + compare of (a,b) and (b,a) to return the same value. + */ + return -1; + } + next_key_length=key_length; continue; /* To next key part */ } } end= a+ min(keyseg->length,key_length); + next_key_length=key_length-keyseg->length; switch ((enum ha_base_keytype) keyseg->type) { case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ @@ -93,12 +123,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && - (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + (flag=mi_compare_text(keyseg->charset,a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -107,7 +137,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, else { uint length=(uint) (end-a), a_length=length, b_length=length; - key_length-= keyseg->length; if (!(nextflag & SEARCH_PREFIX)) { while (a_length && a[a_length-1] == ' ') @@ -116,9 +145,9 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, b_length--; } if (piks && - (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + (flag= mi_compare_text(keyseg->charset, a, a_length, b, b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a=end; b+=length; @@ -130,12 +159,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && (flag=compare_bin(a,a_length,b,b_length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -144,11 +173,10 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, else { uint length=keyseg->length; - key_length-= keyseg->length; if (piks && (flag=compare_bin(a,length,b,length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=length; b+=length; @@ -159,12 +187,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -176,12 +204,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && (flag=compare_bin(a,a_length,b,b_length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -196,7 +224,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b++; - key_length-= keyseg->length; break; } case HA_KEYTYPE_SHORT_INT: @@ -206,7 +233,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 2; /* sizeof(short int); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_USHORT_INT: { @@ -217,7 +243,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+=2; /* sizeof(short int); */ - key_length-= keyseg->length; break; } case HA_KEYTYPE_LONG_INT: @@ -227,7 +252,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_ULONG_INT: u_1= mi_sint4korr(a); @@ -236,7 +260,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_INT24: l_1=mi_sint3korr(a); @@ -245,7 +268,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; - key_length-= keyseg->length; break; case HA_KEYTYPE_UINT24: l_1=mi_uint3korr(a); @@ -254,7 +276,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; - key_length-= keyseg->length; break; case HA_KEYTYPE_FLOAT: mi_float4get(f_1,a); @@ -263,7 +284,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(float); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_DOUBLE: mi_float8get(d_1,a); @@ -272,13 +292,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; /* sizeof(double); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_NUM: /* Numeric key */ { int swap_flag= 0; int alength,blength; - + if (keyseg->flag & HA_REVERSE_SORT) { swap(uchar*,a,b); @@ -289,7 +308,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, { alength= *a++; blength= *b++; end=a+alength; - key_length-= blength + 1; + next_key_length=key_length-blength-1; } else { @@ -298,9 +317,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, /* remove pre space from keys */ for ( ; alength && *a == ' ' ; a++, alength--) ; for ( ; blength && *b == ' ' ; b++, blength--) ; - key_length-= keyseg->length; } - if (piks) { if (*a == '-') @@ -350,7 +367,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; - key_length-= keyseg->length; break; } case HA_KEYTYPE_ULONGLONG: @@ -362,7 +378,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; - key_length-= keyseg->length; break; } #endif diff --git a/readline/Makefile.am b/readline/Makefile.am index 018df11be7d..7c4fe8eeb91 100644 --- a/readline/Makefile.am +++ b/readline/Makefile.am @@ -2,7 +2,8 @@ # Makefile for the GNU readline library. # Copyright (C) 1994,1996,1997 Free Software Foundation, Inc. -INCLUDES = -I$(top_srcdir)/include +# Last -I$(top_srcdir) needed for RedHat! +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir) noinst_LIBRARIES = libreadline.a diff --git a/sql-bench/bench-init.pl.sh b/sql-bench/bench-init.pl.sh index 9b999ee7f95..b7d2b962e13 100644 --- a/sql-bench/bench-init.pl.sh +++ b/sql-bench/bench-init.pl.sh @@ -48,7 +48,10 @@ $opt_optimization="None"; $opt_hw=""; $opt_threads=5; -$opt_time_limit=10*60; # Don't wait more than 10 min for some tests +if (!defined($opt_time_limit)) +{ + $opt_time_limit=10*60; # Don't wait more than 10 min for some tests +} $log_prog_args=join(" ", skip_arguments(\@ARGV,"comments","cmp","server", "user", "host", "database", "password", diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh index ea18431f8da..130816de0be 100644 --- a/sql-bench/crash-me.sh +++ b/sql-bench/crash-me.sh @@ -39,7 +39,7 @@ # as such, and clarify ones such as "mediumint" with comments such as # "3-byte int" or "same as xxx". -$version="1.59"; +$version="1.60"; use DBI; use Getopt::Long; @@ -50,7 +50,7 @@ $opt_server="mysql"; $opt_host="localhost"; $opt_database="test"; $opt_dir="limits"; $opt_user=$opt_password="";$opt_verbose=""; $opt_debug=$opt_help=$opt_Information=$opt_restart=$opt_force=$opt_quick=0; -$opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=0; +$opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=$opt_version=0; $opt_db_start_cmd=""; # the db server start command $opt_check_server=0; # Check if server is alive before each query $opt_sleep=10; # time to sleep while starting the db server @@ -68,8 +68,10 @@ GetOptions("Information","help","server=s","debug","user=s","password=s", "database=s","restart","force","quick","log-all-queries","comment=s", "host=s","fix-limit-file","dir=s","db-start-cmd=s","sleep=s","suffix=s", "batch-mode","config-file=s","log-queries-to-file=s","check-server", +"version", "verbose!" => \$opt_verbose) || usage(); usage() if ($opt_help || $opt_Information); +version() && exit(0) if ($opt_version); $opt_suffix = '-'.$opt_suffix if (length($opt_suffix) != 0); $opt_config_file = "$pwd/$opt_dir/$opt_server$opt_suffix.cfg" @@ -1190,7 +1192,7 @@ else # Test: NOROUND { - my $resultat = 'undefined'; + my $result = 'undefined'; my $error; print "NOROUND: "; save_incomplete('func_extra_noround','Function NOROUND'); @@ -1199,21 +1201,25 @@ else $error = safe_query_l('func_extra_noround',"select noround(22.6) $end_query"); if ($error ne 1) # syntax error -- noround is not supported { - $resultat = 'no' - } else # Ok, now check if it really works - { + $result = 'no' + } + else # Ok, now check if it really works + { $error=safe_query_l('func_extra_noround', ["create table crash_me_nr (a int)", "insert into crash_me_nr values(noround(10.2))", "drop table crash_me_nr $drop_attr"]); - if ($error eq 1) { - $resultat = "syntax only"; - } else { - $resultat = 'yes'; - } - } - print "$resultat\n"; - save_config_data('func_extra_noround',$resultat,"Function NOROUND"); + if ($error == 1) + { + $result= "syntax only"; + } + else + { + $result= 'yes'; + } + } + print "$result\n"; + save_config_data('func_extra_noround',$result,"Function NOROUND"); } check_parenthesis("func_sql_","CURRENT_USER"); @@ -1377,7 +1383,7 @@ if ($limits{'type_sql_date'} eq 'yes') # Test: WEEK() { - my $resultat="no"; + my $result="no"; my $error; print "WEEK:"; save_incomplete('func_odbc_week','WEEK'); @@ -1388,17 +1394,17 @@ if ($limits{'type_sql_date'} eq 'yes') # and 0 - EURO weeks if ($error == -1) { if ($last_result == 4) { - $resultat = 'USA'; + $result = 'USA'; } else { - $resultat='error'; + $result='error'; add_log('func_odbc_week', " must return 4 or 5, but $last_result"); } } elsif ($error == 0) { - $resultat = 'EURO'; + $result = 'EURO'; } - print " $resultat\n"; - save_config_data('func_odbc_week',$resultat,"WEEK"); + print " $result\n"; + save_config_data('func_odbc_week',$result,"WEEK"); } my $insert_query ='insert into crash_me_d values('. @@ -1498,7 +1504,7 @@ if ($limits{'type_sql_date'} eq 'yes') # NOT id BETWEEN a and b if ($limits{'func_where_not_between'} eq 'yes') { - my $resultat = 'error'; + my $result = 'error'; my $err; my $key='not_id_between'; my $prompt='NOT ID BETWEEN interprets as ID NOT BETWEEN'; @@ -1512,15 +1518,15 @@ if ($limits{'func_where_not_between'} eq 'yes') 5,0); if ($err eq 1) { if (not defined($last_result)) { - $resultat='no'; + $result='no'; }; }; if ( $err eq 0) { - $resultat = 'yes'; + $result = 'yes'; }; safe_query_l($key,["drop table crash_me_b"]); - save_config_data($key,$resultat,$prompt); - print "$resultat\n"; + save_config_data($key,$result,$prompt); + print "$result\n"; }; @@ -2018,37 +2024,44 @@ report("views","views", # Test: foreign key { - my $resultat = 'undefined'; + my $result = 'undefined'; my $error; print "foreign keys: "; save_incomplete('foreign_key','foreign keys'); # 1) check if foreign keys are supported - safe_query_l('foreign_key',create_table("crash_me_qf",["a integer not null"], - ["primary key (a)"])); - $error = safe_query_l('foreign_key', - create_table("crash_me_qf2",["a integer not null", - "foreign key (a) references crash_me_qf (a)"], [])); - - if ($error eq 1) # OK -- syntax is supported + safe_query_l('foreign_key', + create_table("crash_me_qf", + ["a integer not null"], + ["primary key (a)"])); + $error= safe_query_l('foreign_key', + create_table("crash_me_qf2", + ["a integer not null", + "foreign key (a) references crash_me_qf (a)"], + [])); + + if ($error == 1) # OK -- syntax is supported { - $resultat = 'error'; + $result = 'error'; # now check if foreign key really works safe_query_l('foreign_key', "insert into crash_me_qf values (1)"); - if (safe_query_l('foreign_key', "insert into crash_me_qf2 values (2)") eq 1) + if (safe_query_l('foreign_key', "insert into crash_me_qf2 values (2)") eq 1) { - $resultat = 'syntax only'; - } else { - $resultat = 'yes'; - } - - } else { - $resultat = "no"; - } - safe_query_l('foreign_key', - "drop table crash_me_qf2 $drop_attr","drop table crash_me_qf $drop_attr"); - print "$resultat\n"; - save_config_data('foreign_key',$resultat,"foreign keys"); + $result = 'syntax only'; + } + else + { + $result = 'yes'; + } + } + else + { + $result = "no"; + } + safe_query_l('foreign_key', "drop table crash_me_qf2 $drop_attr"); + safe_query_l('foreign_key', "drop table crash_me_qf $drop_attr"); + print "$result\n"; + save_config_data('foreign_key',$result,"foreign keys"); } report("Create SCHEMA","create_schema", @@ -2607,7 +2620,7 @@ sub detect_null_position sub check_parenthesis { my $prefix=shift; my $fn=shift; - my $resultat='no'; + my $result='no'; my $param_name=$prefix.lc($fn); my $r; @@ -2616,18 +2629,18 @@ sub check_parenthesis { add_log($param_name,$safe_query_log); if ($r == 1) { - $resultat="yes"; + $result="yes"; } else{ $r = safe_query("select $fn() $end_query"); add_log($param_name,$safe_query_log); if ( $r == 1) { - $resultat="with_parenthesis"; + $result="with_parenthesis"; } } - save_config_data($param_name,$resultat,$fn); + save_config_data($param_name,$result,$fn); } sub check_constraint { @@ -2699,10 +2712,16 @@ sub make_date { } +sub version +{ + print "$0 Ver $version\n"; +} + + sub usage { + version(); print <finish; } diff --git a/sql-bench/test-alter-table.sh b/sql-bench/test-alter-table.sh index cc6453188de..f338792e9ef 100644 --- a/sql-bench/test-alter-table.sh +++ b/sql-bench/test-alter-table.sh @@ -27,6 +27,7 @@ $opt_start_field_count=8; # start with this many fields $opt_loop_count=20; # How many tests to do $opt_row_count=1000; # Rows in the table $opt_field_count=1000; # Add until this many fields. +$opt_time_limit=10*60; # Don't wait more than 10 min for some tests chomp($pwd = `pwd`); $pwd = "." if ($pwd eq ''); require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n"; @@ -113,10 +114,9 @@ if ($opt_fast) } else { - $add=1 if (!$limits{'alter_add_multi_col'}); + $add=1 if (!$limits->{'alter_add_multi_col'}); } - $count=0; while ($field_count < $opt_field_count) { @@ -131,19 +131,43 @@ while ($field_count < $opt_field_count) $tmp="" if (!$multi_add); # Adabas } do_query($dbh,"ALTER TABLE bench " . substr($fields,1)); + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count, + $opt_field_count/$add+1)); } $end_time=new Benchmark; -print "Time for alter_table_add ($count): " . +if ($estimated) +{ print "Estimated time"; } +else +{ print "Time"; } +print " for alter_table_add ($count): " . timestr(timediff($end_time, $loop_time),"all") . "\n\n"; +# +# If estimated, fix table to have known number of fields +# +if ($estimated && $field_count < $opt_field_count) +{ + $fields=""; + $tmp="ADD "; + while ($field_count < $opt_field_count) + { + $field_count++; + $fields.=",$tmp i${field_count} integer"; + $tmp="" if (!$multi_add); # Adabas + } + do_query($dbh,"ALTER TABLE bench " . substr($fields,1)); +} + #### #### Test adding and deleting index on the first $opt_start_fields #### $loop_time=new Benchmark; -for ($i=1; $i < $opt_start_field_count ; $i++) +$count= 0; +for ($i=1; $i <= $opt_start_field_count ; $i++) { $dbh->do("CREATE INDEX bench_ind$i ON bench (i${i})") || die $DBI::errstr; } @@ -153,7 +177,7 @@ print "Time for create_index ($opt_start_field_count): " . timestr(timediff($end_time, $loop_time),"all") . "\n\n"; $loop_time=new Benchmark; -for ($i=1; $i < $opt_start_field_count ; $i++) +for ($i=1; $i <= $opt_start_field_count ; $i++) { $dbh->do($server->drop_index("bench","bench_ind$i")) || die $DBI::errstr; } @@ -182,10 +206,17 @@ while ($field_count > $opt_start_field_count) } $dbh->do("ALTER TABLE bench " . substr($fields,1) . $server->{'drop_attr'}) || die $DBI::errstr; + $end_time=new Benchmark; + last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count, + $opt_field_count/$add+1)); } $end_time=new Benchmark; -print "Time for alter_table_drop ($count): " . +if ($estimated) +{ print "Estimated time"; } +else +{ print "Time"; } +print " for alter_table_drop ($count): " . timestr(timediff($end_time, $loop_time),"all") . "\n\n"; skip_dropcol: diff --git a/sql-bench/test-insert.sh b/sql-bench/test-insert.sh index 93bc2840b3b..c26ed42f7ed 100644 --- a/sql-bench/test-insert.sh +++ b/sql-bench/test-insert.sh @@ -21,10 +21,11 @@ # $opt_loop_count rows in random order # # changes made for Oracle compatibility -# - $limits{'func_odbc_mod'} is OK from crash-me, but it fails here so set we +# - $limits->{'func_odbc_mod'} is OK from crash-me, but it fails here so set we # set it to 0 in server-cfg -# - the default server config runs out of rollback segments, so I added a couple -# of disconnect/connects to reset +# - the default server config runs out of rollback segments, so we added a +# couple of disconnect/connects to reset +# ##################### Standard benchmark inits ############################## use DBI; diff --git a/sql/field.cc b/sql/field.cc index 21330a2ffaa..1b388287811 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -34,8 +34,6 @@ // Maximum allowed exponent value for converting string to decimal #define MAX_EXPONENT 1024 - - /***************************************************************************** Instansiate templates and static variables *****************************************************************************/ @@ -67,39 +65,44 @@ void Field_num::prepend_zeros(String *value) /* Test if given number is a int (or a fixed format float with .000) - This is only used to give warnings in ALTER TABLE or LOAD DATA... + + SYNOPSIS + test_if_int() + str String to test + end Pointer to char after last used digit + cs Character set + + NOTES + This is called after one has called my_strntol() or similar function. + This is only used to give warnings in ALTER TABLE or LOAD DATA... + + TODO + Make this multi-byte-character safe + + RETURN + 0 ok + 1 error */ -bool test_if_int(const char *str,int length, CHARSET_INFO *cs) +bool test_if_int(const char *str, int length, const char *int_end, + CHARSET_INFO *cs) { + if (str == int_end) + return 0; // Empty string const char *end=str+length; + if ((str= int_end) == end) + return 1; // All digits was used - cs=system_charset_info; // QQ move test_if_int into CHARSET_INFO struct - - // Allow start space - while (str != end && my_isspace(cs,*str)) - str++; /* purecov: inspected */ - if (str != end && (*str == '-' || *str == '+')) - str++; - if (str == end) - return 0; // Error: Empty string - for (; str != end ; str++) + /* Allow end .0000 */ + if (*str == '.') { - if (!my_isdigit(cs,*str)) - { - if (*str == '.') - { // Allow '.0000' - for (str++ ; str != end && *str == '0'; str++) ; - if (str == end) - return 1; - } - if (!my_isspace(cs,*str)) - return 0; - for (str++ ; str != end ; str++) - if (!my_isspace(cs,*str)) - return 0; - return 1; - } + for (str++ ; str != end && *str == '0'; str++) ; + } + /* Allow end space */ + for (str++ ; str != end ; str++) + { + if (!my_isspace(cs,*str)) + return 0; } return 1; } @@ -107,7 +110,7 @@ bool test_if_int(const char *str,int length, CHARSET_INFO *cs) static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) { - cs=system_charset_info; // QQ move test_if_int into CHARSET_INFO struct + cs= system_charset_info; // QQ move test_if_real into CHARSET_INFO struct while (length && my_isspace(cs,*str)) { // Allow start space @@ -207,17 +210,10 @@ bool Field::send_binary(Protocol *protocol) void Field_num::add_zerofill_and_unsigned(String &res) const { - uint oldlen=res.length(); - if (oldlen < res.alloced_length()) - { - uint len=res.alloced_length()-oldlen; - char *end=(char*)(res.ptr()+oldlen); - CHARSET_INFO *cs=res.charset(); - len=cs->snprintf(cs,end,len,"%s%s", - unsigned_flag ? " unsigned" : "", - zerofill ? " zerofill" : ""); - res.length(len+oldlen); - } + if (unsigned_flag) + res.append(" unsigned"); + if (zerofill) + res.append(" zerofill"); } void Field_num::make_field(Send_field *field) @@ -247,19 +243,23 @@ void Field_str::make_field(Send_field *field) field->decimals=0; } + void Field_str::add_binary_or_charset(String &res) const { - uint oldlen=res.length(); - if (oldlen < res.alloced_length()) + if (binary()) + res.append(" binary"); + else if (field_charset != table->table_charset && + !(current_thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS) && + !(current_thd->variables.sql_mode & MODE_MYSQL323) && + !(current_thd->variables.sql_mode & MODE_MYSQL40) && + !(current_thd->variables.sql_mode & MODE_POSTGRESQL) && + !(current_thd->variables.sql_mode & MODE_ORACLE) && + !(current_thd->variables.sql_mode & MODE_MSSQL) && + !(current_thd->variables.sql_mode & MODE_DB2) && + !(current_thd->variables.sql_mode & MODE_SAPDB)) { - CHARSET_INFO *cs=res.charset(); - uint len=res.alloced_length() - oldlen; - char *end=(char*)(res.ptr()+oldlen); - if (binary()) - len=cs->snprintf(cs,end,len," binary"); - else - len=cs->snprintf(cs,end,len," character set %s",field_charset->csname); - res.length(oldlen+len); + res.append(" character set "); + res.append(field_charset->csname); } } @@ -287,7 +287,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) bool Field::get_date(TIME *ltime,bool fuzzydate) { char buff[40]; - String tmp(buff,sizeof(buff),my_charset_latin1),tmp2,*res; + String tmp(buff,sizeof(buff),my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE) return 1; @@ -297,7 +297,7 @@ bool Field::get_date(TIME *ltime,bool fuzzydate) bool Field::get_time(TIME *ltime) { char buff[40]; - String tmp(buff,sizeof(buff),my_charset_latin1),tmp2,*res; + String tmp(buff,sizeof(buff),my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || str_to_time(res->ptr(),res->length(),ltime)) return 1; @@ -311,23 +311,23 @@ void Field::store_time(TIME *ltime,timestamp_type type) char buff[25]; switch (type) { case TIMESTAMP_NONE: - store("",0,my_charset_latin1); // Probably an error + store("",0,my_charset_bin); // Probably an error break; case TIMESTAMP_DATE: sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day); - store(buff,10,my_charset_latin1); + store(buff,10,my_charset_bin); break; case TIMESTAMP_FULL: sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", ltime->year,ltime->month,ltime->day, ltime->hour,ltime->minute,ltime->second); - store(buff,19,my_charset_latin1); + store(buff,19,my_charset_bin); break; case TIMESTAMP_TIME: { ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d", ltime->hour,ltime->minute,ltime->second)); - store(buff,(uint) length, my_charset_latin1); + store(buff,(uint) length, my_charset_bin); break; } } @@ -340,15 +340,12 @@ bool Field::optimize_range(uint idx) } /**************************************************************************** - Functions for the Field_null + Field_null, a field that always return NULL ****************************************************************************/ void Field_null::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); - uint len; - len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),"null"); - res.length(len); + res.set_latin1("null", 4); } @@ -360,7 +357,7 @@ void Field_null::sql_type(String &res) const void Field_decimal::reset(void) { - Field_decimal::store("0",1,my_charset_latin1); + Field_decimal::store("0",1,my_charset_bin); } void Field_decimal::overflow(bool negative) @@ -404,11 +401,16 @@ void Field_decimal::overflow(bool negative) int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) { - String l1from; + char buff[80]; + String tmp(buff,sizeof(buff), my_charset_bin); - l1from.copy(from,len,cs,my_charset_latin1); - from=l1from.ptr(); - len=l1from.length(); + /* Convert character set if the old one is multi byte */ + if (cs->mbmaxlen > 1) + { + tmp.copy(from, len, cs, my_charset_bin); + from= tmp.ptr(); + len= tmp.length(); + } const char *end= from+len; /* The pointer where the field value starts (i.e., "where to write") */ @@ -461,7 +463,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) There are three steps in this function : - parse the input string - modify the position of digits around the decimal dot '.' - according to the exponent value (if specified) + according to the exponent value (if specified) - write the formatted number */ @@ -469,7 +471,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) tmp_dec++; /* skip pre-space */ - while (from != end && my_isspace(my_charset_latin1,*from)) + while (from != end && my_isspace(my_charset_bin,*from)) from++; if (from == end) { @@ -506,13 +508,13 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) for (; from!=end && *from == '0'; from++) ; // Read prezeros pre_zeros_end=int_digits_from=from; /* Read non zero digits at the left of '.'*/ - for (; from != end && my_isdigit(my_charset_latin1, *from) ; from++) ; + for (; from != end && my_isdigit(my_charset_bin, *from) ; from++) ; int_digits_end=from; if (from!=end && *from == '.') // Some '.' ? from++; frac_digits_from= from; /* Read digits at the right of '.' */ - for (;from!=end && my_isdigit(my_charset_latin1, *from); from++) ; + for (;from!=end && my_isdigit(my_charset_bin, *from); from++) ; frac_digits_end=from; // Some exponentiation symbol ? if (from != end && (*from == 'e' || *from == 'E')) @@ -528,7 +530,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) exponents will become small (e.g. 1e4294967296 will become 1e0, and the field will finally contain 1 instead of its max possible value). */ - for (;from!=end && my_isdigit(my_charset_latin1, *from); from++) + for (;from!=end && my_isdigit(my_charset_bin, *from); from++) { exponent=10*exponent+(*from-'0'); if (exponent>MAX_EXPONENT) @@ -546,7 +548,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) if (current_thd->count_cuted_fields) { // Skip end spaces - for (;from != end && my_isspace(my_charset_latin1, *from); from++) ; + for (;from != end && my_isspace(my_charset_bin, *from); from++) ; if (from != end) // If still something left, warn { current_thd->cuted_fields++; @@ -838,30 +840,33 @@ int Field_decimal::store(longlong nr) double Field_decimal::val_real(void) { - CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr,field_length,NULL); + int not_used; + return my_strntod(my_charset_bin, ptr, field_length, NULL, ¬_used); } longlong Field_decimal::val_int(void) { - CHARSET_INFO *cs=charset(); + int not_used; if (unsigned_flag) - return my_strntoull(cs,ptr,field_length,NULL,10); + return my_strntoull(my_charset_bin, ptr, field_length, 10, NULL, + ¬_used); else - return my_strntoll(cs,ptr,field_length,NULL,10); + return my_strntoll( my_charset_bin, ptr, field_length, 10, NULL, + ¬_used); } + String *Field_decimal::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { char *str; - CHARSET_INFO *cs=current_thd->variables.thd_charset; for (str=ptr ; *str == ' ' ; str++) ; uint tmp_length=(uint) (str-ptr); + val_ptr->set_charset(my_charset_bin); if (field_length < tmp_length) // Error in data val_ptr->length(0); else - val_ptr->copy((const char*) str,field_length-tmp_length,my_charset_latin1,cs); + val_ptr->set_latin1((const char*) str, field_length-tmp_length); return val_ptr; } @@ -878,9 +883,9 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr) for (end=a_ptr+field_length; a_ptr != end && (*a_ptr == *b_ptr || - ((my_isspace(my_charset_latin1,*a_ptr) || *a_ptr == '+' || + ((my_isspace(my_charset_bin,*a_ptr) || *a_ptr == '+' || *a_ptr == '0') && - (my_isspace(my_charset_latin1,*b_ptr) || *b_ptr == '+' || + (my_isspace(my_charset_bin,*b_ptr) || *b_ptr == '+' || *b_ptr == '0'))); a_ptr++,b_ptr++) { @@ -908,7 +913,7 @@ void Field_decimal::sort_string(char *to,uint length) char *str,*end; for (str=ptr,end=ptr+length; str != end && - ((my_isspace(my_charset_latin1,*str) || *str == '+' || + ((my_isspace(my_charset_bin,*str) || *str == '+' || *str == '0')) ; str++) *to++=' '; @@ -920,7 +925,7 @@ void Field_decimal::sort_string(char *to,uint length) *to++=1; // Smaller than any number str++; while (str != end) - if (my_isdigit(my_charset_latin1,*str)) + if (my_isdigit(my_charset_bin,*str)) *to++= (char) ('9' - *str++); else *to++= *str++; @@ -933,14 +938,12 @@ void Field_decimal::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); uint tmp=field_length; - uint len; if (!unsigned_flag) tmp--; if (dec) tmp--; - len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "decimal(%d,%d)",tmp,dec); - res.length(len); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "decimal(%d,%d)",tmp,dec)); add_zerofill_and_unsigned(res); } @@ -951,7 +954,9 @@ void Field_decimal::sql_type(String &res) const int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) { - long tmp= my_strntol(cs,from,len,(char **)NULL,10); + int not_used; // We can ignore result from str2int + char *end; + long tmp= my_strntol(cs, from, len, 10, &end, ¬_used); int error= 0; if (unsigned_flag) @@ -968,7 +973,7 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) current_thd->cuted_fields++; error= 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs)) + else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { current_thd->cuted_fields++; error= 1; @@ -988,7 +993,7 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) current_thd->cuted_fields++; error= 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs)) + else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { current_thd->cuted_fields++; error= 1; @@ -1098,16 +1103,16 @@ longlong Field_tiny::val_int(void) String *Field_tiny::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { - CHARSET_INFO *cs=current_thd->variables.thd_charset; + CHARSET_INFO *cs= my_charset_bin; uint length; uint mlength=max(field_length+1,5*cs->mbmaxlen); val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); if (unsigned_flag) - length= (uint) cs->l10tostr(cs,to,mlength, 10,(long) *((uchar*) ptr)); + length= (uint) cs->long10_to_str(cs,to,mlength, 10,(long) *((uchar*) ptr)); else - length= (uint) cs->l10tostr(cs,to,mlength,-10,(long) *((signed char*) ptr)); + length= (uint) cs->long10_to_str(cs,to,mlength,-10,(long) *((signed char*) ptr)); val_buffer->length(length); if (zerofill) @@ -1140,23 +1145,22 @@ void Field_tiny::sort_string(char *to,uint length __attribute__((unused))) void Field_tiny::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "tinyint(%d)",(int) field_length); - res.length(len); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "tinyint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } /**************************************************************************** -** short int + Field type short int (2 byte) ****************************************************************************/ - -// Note: Sometimes this should be fixed to check for garbage after number. - int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) { - long tmp= my_strntol(cs,from,len,NULL,10); + int not_used; // We can ignore result from str2int + char *end; + long tmp= my_strntol(cs, from, len, 10, &end, ¬_used); int error= 0; + if (unsigned_flag) { if (tmp < 0) @@ -1171,7 +1175,7 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) current_thd->cuted_fields++; error= 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs)) + else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { current_thd->cuted_fields++; error= 1; @@ -1191,7 +1195,7 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) current_thd->cuted_fields++; error= 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs)) + else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { current_thd->cuted_fields++; error= 1; @@ -1337,7 +1341,7 @@ longlong Field_short::val_int(void) String *Field_short::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { - CHARSET_INFO *cs=current_thd->variables.thd_charset; + CHARSET_INFO *cs= my_charset_bin; uint length; uint mlength=max(field_length+1,7*cs->mbmaxlen); val_buffer->alloc(mlength); @@ -1351,9 +1355,9 @@ String *Field_short::val_str(String *val_buffer, shortget(j,ptr); if (unsigned_flag) - length=(uint) cs->l10tostr(cs,to,mlength, 10, (long) (uint16) j); + length=(uint) cs->long10_to_str(cs, to, mlength, 10, (long) (uint16) j); else - length=(uint) cs->l10tostr(cs,to,mlength,-10, (long) j); + length=(uint) cs->long10_to_str(cs, to, mlength,-10, (long) j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -1414,22 +1418,21 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused))) void Field_short::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "smallint(%d)",(int) field_length); - res.length(len); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "smallint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } /**************************************************************************** -** medium int + Field type medium int (3 byte) ****************************************************************************/ -// Note: Sometimes this should be fixed to check for garbage after number. - int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) { - long tmp= my_strntol(cs,from,len,NULL,10); + int not_used; // We can ignore result from str2int + char *end; + long tmp= my_strntol(cs, from, len, 10, &end, ¬_used); int error= 0; if (unsigned_flag) @@ -1446,7 +1449,7 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) current_thd->cuted_fields++; error= 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs)) + else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { current_thd->cuted_fields++; error= 1; @@ -1466,7 +1469,7 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) current_thd->cuted_fields++; error= 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs)) + else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { current_thd->cuted_fields++; error= 1; @@ -1572,23 +1575,25 @@ double Field_medium::val_real(void) return (double) j; } + longlong Field_medium::val_int(void) { long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr); return (longlong) j; } + String *Field_medium::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { - CHARSET_INFO *cs=current_thd->variables.thd_charset; + CHARSET_INFO *cs= my_charset_bin; uint length; uint mlength=max(field_length+1,10*cs->mbmaxlen); val_buffer->alloc(mlength); char *to=(char*) val_buffer->ptr(); long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr); - length=(uint) cs->l10tostr(cs,to,mlength,-10,j); + length=(uint) cs->long10_to_str(cs,to,mlength,-10,j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); /* purecov: inspected */ @@ -1632,9 +1637,8 @@ void Field_medium::sort_string(char *to,uint length __attribute__((unused))) void Field_medium::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "mediumint(%d)",(int) field_length); - res.length(len); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "mediumint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } @@ -1643,39 +1647,35 @@ void Field_medium::sql_type(String &res) const ****************************************************************************/ -// Note: Sometimes this should be fixed to check for garbage after number. - int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) { + long tmp; + int error= 0; char *end; + /* TODO: Make multi-byte-character safe */ while (len && my_isspace(cs,*from)) { len--; from++; } - long tmp; - String tmp_str(from, len, cs); - from= tmp_str.c_ptr(); // Add end null if needed - int error= 0; - errno=0; + my_errno=0; if (unsigned_flag) { if (!len || *from == '-') { tmp=0; // Set negative to 0 - errno=ERANGE; + my_errno=ERANGE; error= 1; } else - tmp=(long) my_strntoul(cs,from,len,&end,10); + tmp=(long) my_strntoul(cs,from,len,10,&end,&error); } else - tmp=my_strntol(cs,from,len,&end,10); - if (errno || + tmp=my_strntol(cs,from,len,10,&end,&error); + if (error || (from+len != end && current_thd->count_cuted_fields && - !test_if_int(from,len,cs))) + !test_if_int(from,len,end,cs))) { current_thd->cuted_fields++; - error= 1; } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -1817,7 +1817,7 @@ longlong Field_long::val_int(void) String *Field_long::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { - CHARSET_INFO *cs=current_thd->variables.thd_charset; + CHARSET_INFO *cs= my_charset_bin; uint length; uint mlength=max(field_length+1,12*cs->mbmaxlen); val_buffer->alloc(mlength); @@ -1831,9 +1831,9 @@ String *Field_long::val_str(String *val_buffer, longget(j,ptr); if (unsigned_flag) - length=cs->l10tostr(cs,to,mlength, 10,(long) (uint32)j); + length=cs->long10_to_str(cs,to,mlength, 10,(long) (uint32)j); else - length=cs->l10tostr(cs,to,mlength,-10,(long) j); + length=cs->long10_to_str(cs,to,mlength,-10,(long) j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -1896,44 +1896,42 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused))) void Field_long::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "int(%d)",(int) field_length); - res.length(len); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "int(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } /**************************************************************************** -** longlong int + Field type longlong int (8 bytes) ****************************************************************************/ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) { + longlong tmp; + int error= 0; char *end; + /* TODO: Make multi byte safe */ while (len && my_isspace(cs,*from)) { // For easy error check len--; from++; } - longlong tmp; - String tmp_str(from, len, cs); - from= tmp_str.c_ptr(); // Add end null if needed - int error= 0; - errno=0; + my_errno=0; if (unsigned_flag) { if (!len || *from == '-') { tmp=0; // Set negative to 0 - errno=ERANGE; + my_errno= ERANGE; error= 1; } else - tmp=(longlong) my_strntoull(cs,from,len,&end,10); + tmp=(longlong) my_strntoull(cs,from,len,10,&end,&error); } else - tmp=my_strntoll(cs,from,len,&end,10); - if (errno || + tmp=my_strntoll(cs,from,len,10,&end,&error); + if (error || (from+len != end && current_thd->count_cuted_fields && - !test_if_int(from,len,cs))) + !test_if_int(from,len,end,cs))) current_thd->cuted_fields++; #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -2042,7 +2040,7 @@ longlong Field_longlong::val_int(void) String *Field_longlong::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { - CHARSET_INFO *cs=current_thd->variables.thd_charset; + CHARSET_INFO *cs= my_charset_bin; uint length; uint mlength=max(field_length+1,22*cs->mbmaxlen); val_buffer->alloc(mlength); @@ -2055,7 +2053,7 @@ String *Field_longlong::val_str(String *val_buffer, #endif longlongget(j,ptr); - length=(uint) cs->ll10tostr(cs,to,mlength,unsigned_flag ? 10 : -10, j); + length=(uint) cs->longlong10_to_str(cs,to,mlength,unsigned_flag ? 10 : -10, j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -2128,9 +2126,8 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused))) void Field_longlong::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "bigint(%d)",(int) field_length); - res.length(len); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "bigint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } @@ -2140,14 +2137,14 @@ void Field_longlong::sql_type(String &res) const int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) { - errno=0; - Field_float::store(my_strntod(cs,from,len,(char**)NULL)); - if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) + int err; + Field_float::store(my_strntod(cs,(char*) from,len,(char**)NULL,&err)); + if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) { current_thd->cuted_fields++; return 1; } - return (errno) ? 1 : 0; + return (err) ? 1 : 0; } @@ -2394,18 +2391,16 @@ bool Field_float::send_binary(Protocol *protocol) void Field_float::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); - uint len; if (dec == NOT_FIXED_DEC) { - len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),"float"); + res.set_latin1("float", 5); } else { - len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "float(%d,%d)",(int) field_length,dec); + CHARSET_INFO *cs= res.charset(); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "float(%d,%d)",(int) field_length,dec)); } - res.length(len); add_zerofill_and_unsigned(res); } @@ -2415,19 +2410,17 @@ void Field_float::sql_type(String &res) const int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) { - errno=0; - int error= 0; - double j= my_strntod(cs,from,len,(char**)0); - if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) + int err; + double j= my_strntod(cs,(char*) from,len,(char**)0,&err); + if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) { current_thd->cuted_fields++; - error= 1; } if (unsigned_flag && j < 0) { current_thd->cuted_fields++; j=0; - error= 1; + err= 1; } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -2437,7 +2430,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) else #endif doublestore(ptr,j); - return error; + return err; } @@ -2655,17 +2648,15 @@ void Field_double::sort_string(char *to,uint length __attribute__((unused))) void Field_double::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - uint len; if (dec == NOT_FIXED_DEC) { - len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),"double"); + res.set_latin1("double",6); } else { - len=cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), - "double(%d,%d)",(int) field_length,dec); + res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + "double(%d,%d)",(int) field_length,dec)); } - res.length(len); add_zerofill_and_unsigned(res); } @@ -2722,9 +2713,9 @@ int Field_timestamp::store(double nr) /* -** Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to -** YYYYMMDDHHMMSS. The high date '99991231235959' is checked before this -** function. + Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to + YYYYMMDDHHMMSS. The high date '99991231235959' is checked before this + function. */ static longlong fix_datetime(longlong nr) @@ -2854,9 +2845,10 @@ String *Field_timestamp::val_str(String *val_buffer, if (temp == 0L) { /* Zero time is "000000" */ - strmov(to, "0000-00-00 00:00:00"); - return val_buffer; + val_ptr->set("0000-00-00 00:00:00", 19, my_charset_bin); + return val_ptr; } + val_buffer->set_charset(my_charset_bin); // Safety time_arg=(time_t) temp; localtime_r(&time_arg,&tm_tmp); l_time=&tm_tmp; @@ -2995,9 +2987,7 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) void Field_timestamp::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),"timestamp"); - res.length(len); + res.set_latin1("timestamp", 9); } @@ -3125,6 +3115,12 @@ longlong Field_time::val_int(void) return (longlong) sint3korr(ptr); } + +/* + This function is multi-byte safe as the result string is always of type + my_charset_bin +*/ + String *Field_time::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -3189,9 +3185,7 @@ void Field_time::sort_string(char *to,uint length __attribute__((unused))) void Field_time::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),"time"); - res.length(len); + res.set_latin1("time", 4); } /**************************************************************************** @@ -3202,7 +3196,9 @@ void Field_time::sql_type(String &res) const int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) { - long nr= my_strntol(cs,from,len,NULL,10); + int not_used; // We can ignore result from str2int + char *end; + long nr= my_strntol(cs, from, len, 10, &end, ¬_used); if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { @@ -3210,7 +3206,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) current_thd->cuted_fields++; return 1; } - else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs)) + else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) current_thd->cuted_fields++; if (nr != 0 || len != 4) { @@ -3287,9 +3283,8 @@ String *Field_year::val_str(String *val_buffer, void Field_year::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - ulong len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(), - "year(%d)",(int) field_length); - res.length(len); + res.length(cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(), + "year(%d)",(int) field_length)); } @@ -3375,6 +3370,7 @@ int Field_date::store(longlong nr) return error; } + bool Field_date::send_binary(Protocol *protocol) { longlong tmp= Field_date::val_int(); @@ -3469,9 +3465,7 @@ void Field_date::sort_string(char *to,uint length __attribute__((unused))) void Field_date::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),"date"); - res.length(len); + res.set_latin1("date", 4); } /**************************************************************************** @@ -3639,9 +3633,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused))) void Field_newdate::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),"date"); - res.length(len); + res.set_latin1("date", 4); } @@ -3872,9 +3864,7 @@ void Field_datetime::sort_string(char *to,uint length __attribute__((unused))) void Field_datetime::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); - uint len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),"datetime"); - res.length(len); + res.set_latin1("datetime", 8); } /**************************************************************************** @@ -3929,7 +3919,7 @@ int Field_string::store(double nr) int width=min(field_length,DBL_DIG+5); sprintf(buff,"%-*.*g",width,max(width-5,0),nr); end=strcend(buff,' '); - return Field_string::store(buff,(uint) (end - buff), my_charset_latin1); + return Field_string::store(buff,(uint) (end - buff), my_charset_bin); } @@ -3938,22 +3928,24 @@ int Field_string::store(longlong nr) char buff[64]; int l; CHARSET_INFO *cs=charset(); - l=cs->ll10tostr(cs,buff,sizeof(buff),-10,nr); + l=cs->longlong10_to_str(cs,buff,sizeof(buff),-10,nr); return Field_string::store(buff,(uint)l,cs); } double Field_string::val_real(void) { + int not_used; CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr,field_length,(char**)0); + return my_strntod(cs,ptr,field_length,(char**)0,¬_used); } longlong Field_string::val_int(void) { + int not_used; CHARSET_INFO *cs=charset(); - return my_strntoll(cs,ptr,field_length,NULL,10); + return my_strntoll(cs,ptr,field_length,10,NULL,¬_used); } @@ -3980,23 +3972,11 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr) void Field_string::sort_string(char *to,uint length) { - if (binary()) - memcpy((byte*) to,(byte*) ptr,(size_t) length); - else - { -#ifdef USE_STRCOLL - if (use_strnxfrm(field_charset)) { - uint tmp=my_strnxfrm(field_charset, + uint tmp=my_strnxfrm(field_charset, (unsigned char *)to, length, (unsigned char *) ptr, field_length); - if (tmp < length) - bzero(to + tmp, length - tmp); - } - else -#endif - for (char *from=ptr,*end=ptr+length ; from != end ;) - *to++=(char) field_charset->sort_order[(uint) (uchar) *from++]; - } + if (tmp < length) + bzero(to + tmp, length - tmp); } @@ -4040,12 +4020,6 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length) { uint a_length= (uint) (uchar) *a++; uint b_length= (uint) (uchar) *b++; - - if (binary()) - { - int cmp= memcmp(a,b,min(a_length,b_length)); - return cmp ? cmp : (int) (a_length - b_length); - } return my_strnncoll(field_charset, (const uchar*)a,a_length, (const uchar*)b,b_length); @@ -4059,12 +4033,6 @@ int Field_string::pack_cmp(const char *b, uint length) while (end > ptr && end[-1] == ' ') end--; uint a_length = (uint) (end - ptr); - - if (binary()) - { - int cmp= memcmp(ptr,b,min(a_length,b_length)); - return cmp ? cmp : (int) (a_length - b_length); - } return my_strnncoll(field_charset, (const uchar*)ptr,a_length, (const uchar*)b, b_length); @@ -4118,7 +4086,7 @@ int Field_varstring::store(double nr) int width=min(field_length,DBL_DIG+5); sprintf(buff,"%-*.*g",width,max(width-5,0),nr); end=strcend(buff,' '); - return Field_varstring::store(buff,(uint) (end - buff), my_charset_latin1); + return Field_varstring::store(buff,(uint) (end - buff), my_charset_bin); } @@ -4127,24 +4095,26 @@ int Field_varstring::store(longlong nr) char buff[64]; int l; CHARSET_INFO *cs=charset(); - l=cs->ll10tostr(cs,buff,sizeof(buff),-10,nr); + l=cs->longlong10_to_str(cs,buff,sizeof(buff),-10,nr); return Field_varstring::store(buff,(uint)l,cs); } double Field_varstring::val_real(void) { + int not_used; uint length=uint2korr(ptr)+2; CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr+2,length,(char**)0); + return my_strntod(cs,ptr+2,length,(char**)0, ¬_used); } longlong Field_varstring::val_int(void) { + int not_used; uint length=uint2korr(ptr)+2; CHARSET_INFO *cs=charset(); - return my_strntoll(cs,ptr+2,length,NULL,10); + return my_strntoll(cs,ptr+2,length,10,NULL, ¬_used); } @@ -4171,27 +4141,9 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr) void Field_varstring::sort_string(char *to,uint length) { uint tot_length=uint2korr(ptr); - if (binary()) - memcpy((byte*) to,(byte*) ptr+2,(size_t) tot_length); - else - { -#ifdef USE_STRCOLL - if (use_strnxfrm(field_charset)) - tot_length=my_strnxfrm(field_charset, + tot_length=my_strnxfrm(field_charset, (unsigned char *) to, length, (unsigned char *)ptr+2, tot_length); - else - { -#endif - char *tmp=to; - if (tot_length > length) - tot_length=length; - for (char *from=ptr+2,*end=from+tot_length ; from != end ;) - *tmp++=(char) field_charset->sort_order[(uint) (uchar) *from++]; -#ifdef USE_STRCOLL - } -#endif - } if (tot_length < length) bzero(to+tot_length,length-tot_length); } @@ -4255,11 +4207,6 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length) a_length= (uint) (uchar) *a++; b_length= (uint) (uchar) *b++; } - if (binary()) - { - int cmp= memcmp(a,b,min(a_length,b_length)); - return cmp ? cmp : (int) (a_length - b_length); - } return my_strnncoll(field_charset, (const uchar *)a,a_length, (const uchar *)b,b_length); @@ -4278,11 +4225,6 @@ int Field_varstring::pack_cmp(const char *b, uint key_length) { b_length= (uint) (uchar) *b++; } - if (binary()) - { - int cmp= memcmp(a,b,min(a_length,b_length)); - return cmp ? cmp : (int) (a_length - b_length); - } return my_strnncoll(field_charset, (const uchar *)a,a_length, (const uchar *)b,b_length); @@ -4464,40 +4406,42 @@ int Field_blob::store(const char *from,uint len,CHARSET_INFO *cs) int Field_blob::store(double nr) { - value.set(nr,2,current_thd->variables.thd_charset); - return Field_blob::store(value.ptr(),(uint) value.length(), value.charset()); + CHARSET_INFO *cs=charset(); + value.set(nr, 2, cs); + return Field_blob::store(value.ptr(),(uint) value.length(), cs); } int Field_blob::store(longlong nr) { - value.set(nr,current_thd->variables.thd_charset); - return Field_blob::store(value.ptr(), (uint) value.length(), value.charset()); + CHARSET_INFO *cs=charset(); + value.set(nr, cs); + return Field_blob::store(value.ptr(), (uint) value.length(), cs); } double Field_blob::val_real(void) { + int not_used; char *blob; - memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) return 0.0; uint32 length=get_length(ptr); CHARSET_INFO *cs=charset(); - return my_strntod(cs,blob,length,(char**)0); + return my_strntod(cs,blob,length,(char**)0, ¬_used); } longlong Field_blob::val_int(void) { + int not_used; char *blob; memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) return 0; uint32 length=get_length(ptr); - CHARSET_INFO *cs=charset(); - return my_strntoll(cs,blob,length,NULL,10); + return my_strntoll(charset(),blob,length,10,NULL,¬_used); } @@ -4507,9 +4451,9 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)), char *blob; memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) - val_ptr->set("",0,field_charset); // A bit safer than ->length(0) + val_ptr->set("",0,charset()); // A bit safer than ->length(0) else - val_ptr->set((const char*) blob,get_length(ptr),field_charset); + val_ptr->set((const char*) blob,get_length(ptr),charset()); return val_ptr; } @@ -4567,7 +4511,8 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr, /* The following is used only when comparing a key */ -void Field_blob::get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type) +void Field_blob::get_key_image(char *buff,uint length, + CHARSET_INFO *cs,imagetype type) { length-= HA_KEY_BLOB_LENGTH; uint32 blob_length= get_length(ptr); @@ -4656,61 +4601,44 @@ void Field_blob::sort_string(char *to,uint length) { char *blob; uint blob_length=get_length(); -#ifdef USE_STRCOLL - uint blob_org_length=blob_length; -#endif + if (!blob_length) bzero(to,length); else { - if (blob_length > length) - blob_length=length; memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); - if (binary()) - { - memcpy(to,blob,blob_length); - to+=blob_length; - } - else - { -#ifdef USE_STRCOLL - if (use_strnxfrm(field_charset)) - { - blob_length=my_strnxfrm(field_charset, - (unsigned char *)to, length, - (unsigned char *)blob, blob_org_length); - if (blob_length >= length) - return; - to+=blob_length; - } - else -#endif - for (char *end=blob+blob_length ; blob != end ;) - *to++=(char) field_charset->sort_order[(uint) (uchar) *blob++]; - } - bzero(to,length-blob_length); + + blob_length=my_strnxfrm(field_charset, + (unsigned char *)to, length, + (unsigned char *)blob, blob_length); + if (blob_length < length) + bzero(to+blob_length, length-blob_length); } } void Field_blob::sql_type(String &res) const { - CHARSET_INFO *cs=res.charset(); const char *str; - uint len; + uint length; switch (packlength) { - default: str="tiny"; break; - case 2: str=""; break; - case 3: str="medium"; break; - case 4: str="long"; break; + default: str="tiny"; length=4; break; + case 2: str=""; length=0; break; + case 3: str="medium"; length= 6; break; + case 4: str="long"; length=4; break; + } + res.set_latin1(str,length); + if (binary()) + res.append("blob"); + else + { + res.append("text"); + if (field_charset != table->table_charset) + { + res.append(" character set "); + res.append(field_charset->csname); + } } - - len=cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),"%s%s%s%s", - str, - binary() ? "blob" : "text", - binary() ? "" : " character set ", - binary() ? "" : field_charset->name); - res.length(len); } @@ -4766,11 +4694,6 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length) a_length= (uint) (uchar) *a++; b_length= (uint) (uchar) *b++; } - if (binary()) - { - int cmp= memcmp(a,b,min(a_length,b_length)); - return cmp ? cmp : (int) (a_length - b_length); - } return my_strnncoll(field_charset, (const uchar *)a,a_length, (const uchar *)b,b_length); @@ -4794,11 +4717,6 @@ int Field_blob::pack_cmp(const char *b, uint key_length) { b_length= (uint) (uchar) *b++; } - if (binary()) - { - int cmp= memcmp(a,b,min(a_length,b_length)); - return cmp ? cmp : (int) (a_length - b_length); - } return my_strnncoll(field_charset, (const uchar *)a,a_length, (const uchar *)b,b_length); @@ -4936,7 +4854,7 @@ uint find_enum(TYPELIB *lib,const char *x, uint length) int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) { - int error= 0; + int err= 0; uint tmp=find_enum(typelib,from,length); if (!tmp) { @@ -4944,20 +4862,18 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) { /* This is for reading numbers with LOAD DATA INFILE */ char *end; - my_errno=0; - tmp=(uint) my_strntoul(cs,from,length,&end,10); - if (my_errno || end != from+length || tmp > typelib->count) + tmp=(uint) my_strntoul(cs,from,length,10,&end,&err); + if (err || end != from+length || tmp > typelib->count) { tmp=0; current_thd->cuted_fields++; - error=1; } } else current_thd->cuted_fields++; } store_type((ulonglong) tmp); - return error; + return err; } @@ -5086,38 +5002,52 @@ void Field_enum::sql_type(String &res) const } -/**************************************************************************** -** set type. -** This is a string which can have a collection of different values. -** Each string value is separated with a ','. -** For example "One,two,five" -** If one uses this string in a number context one gets the bits as a longlong -** number. -****************************************************************************/ +/* + set type. + This is a string which can have a collection of different values. + Each string value is separated with a ','. + For example "One,two,five" + If one uses this string in a number context one gets the bits as a longlong + number. -ulonglong find_set(TYPELIB *lib,const char *x,uint length) + If there was a value in string that wasn't in set, the 'err_pos' points to + the last invalid value found. 'err_len' will be set to length of the + error string. +*/ + +ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, + uint *err_len) { - const char *end=x+length; + const char *end= x + length; + *err_pos= 0; // No error yet while (end > x && my_isspace(system_charset_info, end[-1])) end--; - ulonglong found=0; + *err_len= 0; + ulonglong found= 0; if (x != end) { - const char *start=x; + const char *start= x; bool error= 0; for (;;) { - const char *pos=start; - for (; pos != end && *pos != field_separator ; pos++) ; - uint find=find_enum(lib,start,(uint) (pos-start)); + const char *pos= start; + uint var_len; + + for (; pos != end && *pos != field_separator; pos++) ; + var_len= (uint) (pos - start); + uint find= find_enum(lib, start, var_len); if (!find) - error=1; + { + *err_pos= (char*) start; + *err_len= var_len; + error= 1; + } else - found|= ((longlong) 1 << (find-1)); + found|= ((longlong) 1 << (find - 1)); if (pos == end) - break; - start=pos+1; + break; + start= pos + 1; } if (error) current_thd->cuted_fields++; @@ -5128,25 +5058,26 @@ ulonglong find_set(TYPELIB *lib,const char *x,uint length) int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { - int error= 0; - ulonglong tmp=find_set(typelib,from,length); + int err= 0; + char *not_used; + uint not_used2; + + ulonglong tmp= find_set(typelib, from, length, ¬_used, ¬_used2); if (!tmp && length && length < 22) { /* This is for reading numbers with LOAD DATA INFILE */ char *end; - my_errno=0; - tmp=my_strntoull(cs,from,length,&end,10); - if (my_errno || end != from+length || + tmp=my_strntoull(cs,from,length,10,&end,&err); + if (err || end != from+length || tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) { tmp=0; - error=1; } else current_thd->cuted_fields--; // Remove warning from find_set } store_type(tmp); - return error; + return err; } @@ -5452,8 +5383,7 @@ create_field::create_field(Field *old_field,Field *orig_field) orig_field) { char buff[MAX_FIELD_WIDTH],*pos; - CHARSET_INFO *field_charset= charset; - String tmp(buff,sizeof(buff),field_charset); + String tmp(buff,sizeof(buff), charset); /* Get the value from record[2] (the default value row) */ my_ptrdiff_t diff= (my_ptrdiff_t) (orig_field->table->rec_buff_length*2); @@ -5465,7 +5395,7 @@ create_field::create_field(Field *old_field,Field *orig_field) { pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1); pos[tmp.length()]=0; - def=new Item_string(pos,tmp.length(),field_charset); + def=new Item_string(pos,tmp.length(), charset); } } } diff --git a/sql/field.h b/sql/field.h index 67bae7302f9..af479c81b40 100644 --- a/sql/field.h +++ b/sql/field.h @@ -133,7 +133,9 @@ public: tmp->unireg_check=Field::NONE; tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG); +#ifdef PROBABLY_WRONG tmp->table_name= new_table->table_name; +#endif tmp->reset_fields(); } return tmp; @@ -1093,8 +1095,10 @@ uint32 calc_pack_length(enum_field_types type,uint32 length); bool set_field_to_null(Field *field); bool set_field_to_null_with_conversions(Field *field, bool no_conversions); uint find_enum(TYPELIB *typelib,const char *x, uint length); -ulonglong find_set(TYPELIB *typelib,const char *x, uint length); -bool test_if_int(const char *str,int length,CHARSET_INFO *cs); +ulonglong find_set(TYPELIB *typelib,const char *x, uint length, + char **err_pos, uint *err_len); +bool test_if_int(const char *str, int length, const char *int_end, + CHARSET_INFO *cs); /* The following are for the interface with the .frm file diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0d56f216b3b..cb012d33572 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1600,6 +1600,8 @@ build_template( ibool fetch_all_in_key = FALSE; ulint i; + ut_a(templ_type != ROW_MYSQL_REC_FIELDS || thd == current_thd); + clust_index = dict_table_get_first_index_noninline(prebuilt->table); if (!prebuilt->hint_no_need_to_fetch_extra_cols) { @@ -1624,6 +1626,12 @@ build_template( } if (prebuilt->select_lock_type == LOCK_X) { + /* In versions < 3.23.50 we always retrieved the clustered + index record if prebuilt->select_lock_type == LOCK_S, + but there is really not need for that, and in some cases + performance could be seriously degraded because the MySQL + optimizer did not know about our convention! */ + /* We always retrieve the whole clustered index record if we use exclusive row level locks, for example, if the read is done in an UPDATE statement. */ @@ -1632,12 +1640,6 @@ build_template( } if (templ_type == ROW_MYSQL_REC_FIELDS) { - /* In versions < 3.23.50 we always retrieved the clustered - index record if prebuilt->select_lock_type == LOCK_S, - but there is really not need for that, and in some cases - performance could be seriously degraded because the MySQL - optimizer did not know about our convention! */ - index = prebuilt->index; } else { index = clust_index; @@ -2466,7 +2468,9 @@ ha_innobase::index_read_last( } /************************************************************************ -Changes the active index of a handle. */ +Changes the active index of a handle. Note that since we build also the +template for a search, update_thd() must already have been called, in +::external_lock, for example. */ int ha_innobase::change_active_index( @@ -2481,6 +2485,10 @@ ha_innobase::change_active_index( statistic_increment(ha_read_key_count, &LOCK_status); DBUG_ENTER("change_active_index"); + ut_a(prebuilt->trx == + (trx_t*) current_thd->transaction.all.innobase_tid); + ut_a(user_thd == current_thd); + active_index = keynr; if (keynr != MAX_KEY && table->keys > 0) { @@ -2506,11 +2514,13 @@ ha_innobase::change_active_index( dict_index_copy_types(prebuilt->search_tuple, prebuilt->index, prebuilt->index->n_fields); - /* Maybe MySQL changes the active index for a handle also - during some queries, we do not know: then it is safest to build - the template such that all columns will be fetched */ + /* MySQL changes the active index for a handle also during some + queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX() + and then calculates te sum. Previously we played safe and used + the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary + copying. Starting from MySQL-4.1 we use a more efficient flag here. */ - build_template(prebuilt, user_thd, table, ROW_MYSQL_WHOLE_ROW); + build_template(prebuilt, user_thd, table, ROW_MYSQL_REC_FIELDS); DBUG_RETURN(0); } @@ -3742,8 +3752,18 @@ ha_innobase::extra( obsolete! */ switch (operation) { + case HA_EXTRA_FLUSH: + if (prebuilt->blob_heap) { + row_mysql_prebuilt_free_blob_heap(prebuilt); + } + break; case HA_EXTRA_RESET: - case HA_EXTRA_RESET_STATE: + if (prebuilt->blob_heap) { + row_mysql_prebuilt_free_blob_heap(prebuilt); + } + prebuilt->read_just_key = 0; + break; + case HA_EXTRA_RESET_STATE: prebuilt->read_just_key = 0; break; case HA_EXTRA_NO_KEYREAD: diff --git a/sql/item.cc b/sql/item.cc index b0b56bf9101..ecc63aa4b95 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -116,7 +116,7 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const bool Item::get_date(TIME *ltime,bool fuzzydate) { char buff[40]; - String tmp(buff,sizeof(buff),NULL),*res; + String tmp(buff,sizeof(buff), my_charset_bin),*res; if (!(res=val_str(&tmp)) || str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE) { @@ -134,7 +134,7 @@ bool Item::get_date(TIME *ltime,bool fuzzydate) bool Item::get_time(TIME *ltime) { char buff[40]; - String tmp(buff,sizeof(buff),NULL),*res; + String tmp(buff,sizeof(buff),my_charset_bin),*res; if (!(res=val_str(&tmp)) || str_to_time(res->ptr(),res->length(),ltime)) { @@ -378,9 +378,11 @@ int Item_param::save_in_field(Field *field, bool no_conversions) double Item_param::val() { + int err; switch (item_result_type) { case STRING_RESULT: - return (double)my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),(char**)0); + return (double) my_strntod(str_value.charset(), (char*) str_value.ptr(), + str_value.length(), (char**) 0, &err); case INT_RESULT: return (double)int_value; default: @@ -391,9 +393,12 @@ double Item_param::val() longlong Item_param::val_int() { + int err; switch (item_result_type) { case STRING_RESULT: - return my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10); + return my_strntoll(str_value.charset(), + str_value.ptr(),str_value.length(),10, + (char**) 0,&err); case REAL_RESULT: return (longlong) (real_value+(real_value > 0 ? 0.5 : -0.5)); default: @@ -1149,7 +1154,7 @@ Item *resolve_const_item(Item *item,Item *comp_item) if (res_type == STRING_RESULT) { char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),NULL),*result; + String tmp(buff,sizeof(buff),my_charset_bin),*result; result=item->val_str(&tmp); if (item->null_value) { @@ -1204,8 +1209,8 @@ bool field_is_equal_to_item(Field *field,Item *item) { char item_buff[MAX_FIELD_WIDTH]; char field_buff[MAX_FIELD_WIDTH]; - String item_tmp(item_buff,sizeof(item_buff),NULL),*item_result; - String field_tmp(field_buff,sizeof(field_buff),NULL); + String item_tmp(item_buff,sizeof(item_buff),my_charset_bin),*item_result; + String field_tmp(field_buff,sizeof(field_buff),my_charset_bin); item_result=item->val_str(&item_tmp); if (item->null_value) return 1; // This must be true @@ -1262,17 +1267,19 @@ void Item_cache_str::store(Item *item) } double Item_cache_str::val() { + int err; if (value) - return my_strntod(value->charset(), value->ptr(), - value->length(), (char**)0); + return my_strntod(value->charset(), (char*) value->ptr(), + value->length(), (char**) 0, &err); else return (double)0; } longlong Item_cache_str::val_int() { + int err; if (value) return my_strntoll(value->charset(), value->ptr(), - value->length(), (char**) 0, 10); + value->length(), 10, (char**) 0, &err); else return (longlong)0; } diff --git a/sql/item.h b/sql/item.h index 3decdc388eb..03e9a542eea 100644 --- a/sql/item.h +++ b/sql/item.h @@ -344,13 +344,15 @@ public: enum Type type() const { return STRING_ITEM; } double val() { - return my_strntod(str_value.charset(), str_value.ptr(), - str_value.length(), (char**) 0); + int err; + return my_strntod(str_value.charset(), (char*) str_value.ptr(), + str_value.length(), (char**) 0, &err); } longlong val_int() { + int err; return my_strntoll(str_value.charset(), str_value.ptr(), - str_value.length(), (char**) 0, 10); + str_value.length(), 10, (char**) 0, &err); } String *val_str(String*) { return (String*) &str_value; } int save_in_field(Field *field, bool no_conversions); @@ -598,9 +600,17 @@ public: enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return cached_field_type; } double val() - { return null_value ? 0.0 : my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),NULL); } + { + int err; + return (null_value ? 0.0 : + my_strntod(str_value.charset(), (char*) str_value.ptr(), + str_value.length(),NULL,&err)); + } longlong val_int() - { return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10); } + { + int err; + return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err); + } String *val_str(String*); void make_field(Send_field *field) { item->make_field(field); } void copy(); diff --git a/sql/item_func.cc b/sql/item_func.cc index dcf4638c48a..d489ff1055d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -394,7 +394,7 @@ void Item_func_minus::fix_length_and_dec() { Item_num_op::fix_length_and_dec(); if (unsigned_flag && - (current_thd->sql_mode & MODE_NO_UNSIGNED_SUBTRACTION)) + (current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION)) unsigned_flag=0; } @@ -1893,7 +1893,7 @@ longlong Item_func_set_last_insert_id::val_int() longlong Item_func_benchmark::val_int() { char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff), NULL); + String tmp(buff,sizeof(buff), my_charset_bin); THD *thd=current_thd; for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++) @@ -2039,7 +2039,7 @@ Item_func_set_user_var::update() case STRING_RESULT: { char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer,sizeof(buffer),NULL); + String tmp(buffer,sizeof(buffer),my_charset_bin); (void) val_str(&tmp); break; } @@ -2234,7 +2234,7 @@ longlong Item_func_inet_aton::val_int() char c = '.'; // we mark c to indicate invalid IP in case length is 0 char buff[36]; - String *s,tmp(buff,sizeof(buff),NULL); + String *s,tmp(buff,sizeof(buff),my_charset_bin); if (!(s = args[0]->val_str(&tmp))) // If null value goto err; null_value=0; @@ -2288,7 +2288,7 @@ void Item_func_match::init_search(bool no_order) String *ft_tmp= 0; char tmp1[FT_QUERY_MAXLEN]; - String tmp2(tmp1,sizeof(tmp1),NULL); + String tmp2(tmp1,sizeof(tmp1),default_charset_info); // MATCH ... AGAINST (NULL) is meaningless, but possible if (!(ft_tmp=key_item()->val_str(&tmp2))) diff --git a/sql/item_func.h b/sql/item_func.h index bf64412cab3..a015f6e69ce 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -812,13 +812,15 @@ public: String *val_str(String *); double val() { + int err; String *res; res=val_str(&str_value); - return res ? my_strntod(res->charset(),res->ptr(),res->length(),0) : 0.0; + return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),0,&err) : 0.0; } longlong val_int() { + int err; String *res; res=val_str(&str_value); - return res ? my_strntoll(res->charset(),res->ptr(),res->length(),(char**) 0,10) : (longlong) 0; + return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,(char**) 0,&err) : (longlong) 0; } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7818a23fcd8..2b9bdfe9a1e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -52,16 +52,19 @@ uint nr_of_decimals(const char *str) double Item_str_func::val() { + int err; String *res; res=val_str(&str_value); - return res ? my_strntod(res->charset(),res->ptr(),res->length(),NULL) : 0.0; + return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(), + NULL, &err) : 0.0; } longlong Item_str_func::val_int() { + int err; String *res; res=val_str(&str_value); - return res ? my_strntoll(res->charset(),res->ptr(),res->length(),NULL,10) : (longlong) 0; + return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,NULL,&err) : (longlong) 0; } @@ -1955,6 +1958,7 @@ String *Item_func_conv::val_str(String *str) longlong dec; int from_base= (int) args[1]->val_int(); int to_base= (int) args[2]->val_int(); + int err; if (args[0]->null_value || args[1]->null_value || args[2]->null_value || abs(to_base) > 36 || abs(to_base) < 2 || @@ -1965,9 +1969,9 @@ String *Item_func_conv::val_str(String *str) } null_value=0; if (from_base < 0) - dec= my_strntoll(res->charset(),res->ptr(),res->length(),&endptr,-from_base); + dec= my_strntoll(res->charset(),res->ptr(),res->length(),-from_base,&endptr,&err); else - dec= (longlong) my_strntoull(res->charset(),res->ptr(),res->length(),&endptr,from_base); + dec= (longlong) my_strntoull(res->charset(),res->ptr(),res->length(),from_base,&endptr,&err); ptr= longlong2str(dec,ans,to_base); if (str->copy(ans,(uint32) (ptr-ans), thd_charset())) return &empty_string; @@ -2771,10 +2775,8 @@ String *Item_func_spatial_collection::val_str(String *str) uint32 n_points; double x1, y1, x2, y2; - if (len < WKB_HEADER_SIZE + 4 + 8 + 8) + if (len < 4 + 2 * POINT_DATA_SIZE) goto ret; - data+=WKB_HEADER_SIZE; - len-=WKB_HEADER_SIZE; uint32 llen=len; const char *ldata=data; @@ -2786,10 +2788,6 @@ String *Item_func_spatial_collection::val_str(String *str) float8get(y1,data); data+=8; - len-= 4 + 8 + 8; - - if (len < n_points * POINT_DATA_SIZE) - goto ret; data+=(n_points-2) * POINT_DATA_SIZE; float8get(x2,data); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d78e535010f..2a96594af4e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -336,12 +336,14 @@ void Item_sum_variance::update_field(int offset) double Item_sum_hybrid::val() { + int err; if (null_value) return 0.0; switch (hybrid_type) { case STRING_RESULT: String *res; res=val_str(&str_value); - return res ? my_strntod(res->charset(),res->ptr(),res->length(),(char**)0) : 0.0; + return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(), + (char**) 0, &err) : 0.0); case INT_RESULT: if (unsigned_flag) return ulonglong2double(sum_int); diff --git a/sql/item_sum.h b/sql/item_sum.h index d16a1f2224e..c49311082e8 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -483,13 +483,16 @@ public: String *val_str(String *); double val() { + int err; String *res; res=val_str(&str_value); - return res ? my_strntod(res->charset(),res->ptr(),res->length(),(char**) 0) : 0.0; + return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(), + (char**) 0, &err) : 0.0; } longlong val_int() { + int err; String *res; res=val_str(&str_value); - return res ? my_strntoll(res->charset(),res->ptr(),res->length(),(char**) 0,10) : (longlong) 0; + return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err) : (longlong) 0; } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 796070acb8a..744c0c1fa49 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -529,7 +529,7 @@ void Item_func_now::fix_length_and_dec() { struct tm tm_tmp,*start; time_t query_start=current_thd->query_start(); - CHARSET_INFO *cs=thd_charset(); + CHARSET_INFO *cs=my_charset_bin; decimals=0; max_length=19*cs->mbmaxlen; diff --git a/sql/lex.h b/sql/lex.h index 2ddc540991b..a505911ccf6 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -161,6 +161,7 @@ static SYMBOL symbols[] = { { "FLUSH", SYM(FLUSH_SYM),0,0}, { "FALSE", SYM(FALSE_SYM),0,0}, { "FOREIGN", SYM(FOREIGN),0,0}, + { "FORCE", SYM(FORCE_SYM),0,0}, { "RAID_TYPE", SYM(RAID_TYPE),0,0}, { "RAID_CHUNKS", SYM(RAID_CHUNKS),0,0}, { "RAID_CHUNKSIZE", SYM(RAID_CHUNKSIZE),0,0}, diff --git a/sql/log_event.cc b/sql/log_event.cc index 8f98fa511a0..4ce491d7cc5 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -95,27 +95,29 @@ inline int ignored_error_code(int err_code) ****************************************************************************/ #ifndef MYSQL_CLIENT -static void pretty_print_str(String* packet, char* str, int len) +static char* pretty_print_str(char* packet, char* str, int len) { char* end = str + len; - packet->append('\''); + char* pos= packet; + *pos++= '\''; while (str < end) { char c; switch ((c=*str++)) { - case '\n': packet->append( "\\n"); break; - case '\r': packet->append( "\\r"); break; - case '\\': packet->append( "\\\\"); break; - case '\b': packet->append( "\\b"); break; - case '\t': packet->append( "\\t"); break; - case '\'': packet->append( "\\'"); break; - case 0 : packet->append( "\\0"); break; + case '\n': pos= strmov(pos, "\\n"); break; + case '\r': pos= strmov(pos, "\\r"); break; + case '\\': pos= strmov(pos, "\\\\"); break; + case '\b': pos= strmov(pos, "\\b"); break; + case '\t': pos= strmov(pos, "\\t"); break; + case '\'': pos= strmov(pos, "\\'"); break; + case 0 : pos= strmov(pos, "\\0"); break; default: - packet->append((char)c); + *pos++= (char)c; break; } } - packet->append('\''); + *pos++= '\''; + return pos; } #endif // !MYSQL_CLIENT @@ -294,7 +296,19 @@ Log_event::Log_event(const char* buf, bool old_format) ****************************************************************************/ int Log_event::exec_event(struct st_relay_log_info* rli) { - if (rli) // QQ When is this not true ? + /* + rli is null when (as far as I (Guilhem) know) + the caller is + Load_log_event::exec_event *and* that one is called from + Execute_load_log_event::exec_event. + In this case, we don't do anything here ; + Execute_load_log_event::exec_event will call Log_event::exec_event + again later with the proper rli. + Strictly speaking, if we were sure that rli is null + only in the case discussed above, 'if (rli)' is useless here. + But as we are not 100% sure, keep it for now. + */ + if (rli) { if (rli->inside_transaction) rli->inc_pending(get_event_len()); @@ -558,7 +572,7 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, ev = new Query_log_event(buf, event_len, old_format); break; case LOAD_EVENT: - ev = new Create_file_log_event(buf, event_len, old_format); + ev = new Load_log_event(buf, event_len, old_format); break; case NEW_LOAD_EVENT: ev = new Load_log_event(buf, event_len, old_format); @@ -681,19 +695,24 @@ void Log_event::set_log_pos(MYSQL_LOG* log) ****************************************************************************/ void Query_log_event::pack_info(Protocol *protocol) { - char buf[256]; - String tmp(buf, sizeof(buf), log_cs); - tmp.length(0); + char *buf, *pos; + if (!(buf= my_malloc(9 + db_len + q_len, MYF(MY_WME)))) + return; + pos= buf; if (db && db_len) { - tmp.append("use `", 5); - tmp.append(db, db_len); - tmp.append("`; ", 3); + pos= strmov(buf, "use `"); + memcpy(pos, db, db_len); + pos+= db_len; + pos= strmov(pos, "`; "); } - if (query && q_len) - tmp.append(query, q_len); - protocol->store((char*) tmp.ptr(), tmp.length()); + { + memcpy(pos, query, q_len); + pos+= q_len; + } + protocol->store(buf, pos-buf); + my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } #endif // !MYSQL_CLIENT @@ -952,16 +971,12 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) #ifndef MYSQL_CLIENT void Start_log_event::pack_info(Protocol *protocol) { - char buf1[256]; - String tmp(buf1, sizeof(buf1), log_cs); - tmp.length(0); - char buf[22]; - - tmp.append("Server ver: "); - tmp.append(server_version); - tmp.append(", Binlog ver: "); - tmp.append(llstr(binlog_version, buf)); - protocol->store(tmp.ptr(), tmp.length()); + char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos; + pos= strmov(buf, "Server ver: "); + pos= strmov(pos, server_version); + pos= strmov(pos, ", Binlog ver: "); + pos=int10_to_str(binlog_version, pos, 10); + protocol->store(buf, pos-buf); } #endif // !MYSQL_CLIENT @@ -1063,78 +1078,105 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) #ifndef MYSQL_CLIENT void Load_log_event::pack_info(Protocol *protocol) { - char buf[256]; - String tmp(buf, sizeof(buf), log_cs); - tmp.length(0); + char *buf, *pos; + uint buf_len; + + buf_len= + 5 + db_len + 3 + // "use DB; " + 18 + fname_len + 2 + // "LOAD DATA INFILE 'file''" + 9 + // " REPLACE or IGNORE " + 11 + table_name_len + // "INTO TABLE table" + 21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" + 23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'" + 12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'" + 21 + sql_ex.line_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" + 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'" + 15 + 22 + // " IGNORE xxx LINES" + 3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)" + + buf= my_malloc(buf_len, MYF(MY_WME)); + if (!buf) + return; + pos= buf; if (db && db_len) { - tmp.append("use "); - tmp.append(db, db_len); - tmp.append("; ", 2); + pos= strmov(pos, "use `"); + memcpy(pos, db, db_len); + pos+= db_len; + pos= strmov(pos, "`; "); } - tmp.append("LOAD DATA INFILE '"); - tmp.append(fname, fname_len); - tmp.append("' ", 2); + pos= strmov(pos, "LOAD DATA INFILE '"); + memcpy(pos, fname, fname_len); + pos+= fname_len; + pos= strmov(pos, "' "); + if (sql_ex.opt_flags && REPLACE_FLAG ) - tmp.append(" REPLACE "); + pos= strmov(pos, " REPLACE "); else if (sql_ex.opt_flags && IGNORE_FLAG ) - tmp.append(" IGNORE "); - - tmp.append("INTO TABLE "); - tmp.append(table_name); + pos= strmov(pos, " IGNORE "); + + pos= strmov(pos ,"INTO TABLE "); + memcpy(pos, table_name, table_name_len); + pos+= table_name_len; + if (sql_ex.field_term_len) { - tmp.append(" FIELDS TERMINATED BY "); - pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len); + pos= strmov(pos, " FIELDS TERMINATED BY "); + pos= pretty_print_str(pos, sql_ex.field_term, sql_ex.field_term_len); } if (sql_ex.enclosed_len) { if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) - tmp.append(" OPTIONALLY "); - tmp.append( " ENCLOSED BY "); - pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len); + pos= strmov(pos, " OPTIONALLY "); + pos= strmov(pos, " ENCLOSED BY "); + pos= pretty_print_str(pos, sql_ex.enclosed, sql_ex.enclosed_len); } - + if (sql_ex.escaped_len) { - tmp.append( " ESCAPED BY "); - pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); + pos= strmov(pos, " ESCAPED BY "); + pos= pretty_print_str(pos, sql_ex.escaped, sql_ex.escaped_len); } - + if (sql_ex.line_term_len) { - tmp.append(" LINES TERMINATED BY "); - pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); + pos= strmov(pos, " LINES TERMINATED BY "); + pos= pretty_print_str(pos, sql_ex.line_term, sql_ex.line_term_len); } if (sql_ex.line_start_len) { - tmp.append(" LINES STARTING BY "); - pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); + pos= strmov(pos, " LINES STARTING BY "); + pos= pretty_print_str(pos, sql_ex.line_start, sql_ex.line_start_len); } - + if ((int)skip_lines > 0) - tmp.append( " IGNORE %ld LINES ", (long) skip_lines); + { + pos= strmov(pos, " IGNORE "); + pos= longlong10_to_str((long) skip_lines, pos, 10); + pos= strmov(pos," LINES "); + } if (num_fields) { uint i; const char* field = fields; - tmp.append(" ("); + pos= strmov(pos, " ("); for (i = 0; i < num_fields; i++) { if (i) - tmp.append(" ,"); - tmp.append( field); - + pos= strmov(pos, " ,"); + memcpy(pos, field, field_lens[i]); + pos+= field_lens[i]; field += field_lens[i] + 1; } - tmp.append(')'); + *pos++= ')'; } - protocol->store(tmp.ptr(), tmp.length()); + protocol->store(buf, pos-buf); + my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } #endif // !MYSQL_CLIENT @@ -1289,9 +1331,9 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, bool old_format) { uint data_len; + uint header_len= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; char* buf_end = (char*)buf + event_len; - const char* data_head = buf + ((old_format) ? - OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN); + const char* data_head = buf + header_len; thread_id = uint4korr(data_head + L_THREAD_ID_OFFSET); exec_time = uint4korr(data_head + L_EXEC_TIME_OFFSET); skip_lines = uint4korr(data_head + L_SKIP_LINES_OFFSET); @@ -1300,7 +1342,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET); int body_offset = ((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ? - LOAD_HEADER_LEN + OLD_HEADER_LEN : + LOAD_HEADER_LEN + header_len : get_data_body_offset()); if ((int) event_len < body_offset) @@ -1354,7 +1396,10 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) if (db && db[0] && !same_db) fprintf(file, "use %s;\n", db); - fprintf(file, "LOAD DATA INFILE '%-*s' ", fname_len, fname); + fprintf(file, "LOAD "); + if (check_fname_outside_temp_buf()) + fprintf(file, "LOCAL "); + fprintf(file, "DATA INFILE '%-*s' ", fname_len, fname); if (sql_ex.opt_flags && REPLACE_FLAG ) fprintf(file," REPLACE "); @@ -1435,13 +1480,36 @@ void Load_log_event::set_fields(List &field_list) } #endif // !MYSQL_CLIENT -/***************************************************************************** - - Load_log_event::exec_event() - - ****************************************************************************/ #ifndef MYSQL_CLIENT -int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) + +/* + Does the data loading job when executing a LOAD DATA on the slave + + SYNOPSIS + Load_log_event::exec_event + net + rli + use_rli_only_for_errors - if set to 1, rli is provided to + Load_log_event::exec_event only for this + function to have RPL_LOG_NAME and + rli->last_slave_error, both being used by + error reports. rli's position advancing + is skipped (done by the caller which is + Execute_load_log_event::exec_event). + - if set to 0, rli is provided for full use, + i.e. for error reports and position + advancing. + + DESCRIPTION + Does the data loading job when executing a LOAD DATA on the slave + + RETURN VALUE + 0 Success + 1 Failure +*/ + +int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, + bool use_rli_only_for_errors) { init_sql_alloc(&thd->mem_root, 8192,0); thd->db = rewrite_db((char*)db); @@ -1503,9 +1571,15 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) TL_WRITE)) thd->query_error = 1; if (thd->cuted_fields) + { + /* + log_pos is the position of the LOAD + event in the master log + */ sql_print_error("Slave: load data infile at position %s in log \ -'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME, +'%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME, thd->cuted_fields ); + } if (net) net->pkt_nr= thd->net.pkt_nr; } @@ -1544,7 +1618,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) return 1; } - return Log_event::exec_event(rli); + return ( use_rli_only_for_errors ? 0 : Log_event::exec_event(rli) ); } #endif // !MYSQL_CLIENT @@ -1565,15 +1639,18 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) #ifndef MYSQL_CLIENT void Rotate_log_event::pack_info(Protocol *protocol) { - char buf1[256], buf[22]; - String tmp(buf1, sizeof(buf1), log_cs); - tmp.length(0); - tmp.append(new_log_ident, ident_len); - tmp.append(";pos="); - tmp.append(llstr(pos,buf)); + char *buf, *b_pos; + if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME)))) + return; + b_pos= buf; + memcpy(buf, new_log_ident, ident_len); + b_pos+= ident_len; + b_pos= strmov(b_pos, ";pos="); + b_pos=int10_to_str(pos, b_pos, 10); if (flags & LOG_EVENT_FORCED_ROTATE_F) - tmp.append("; forced by master"); - protocol->store(tmp.ptr(), tmp.length()); + b_pos= strmov(b_pos ,"; forced by master"); + protocol->store(buf, b_pos-buf); + my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } #endif // !MYSQL_CLIENT @@ -1703,13 +1780,11 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) #ifndef MYSQL_CLIENT void Intvar_log_event::pack_info(Protocol *protocol) { - char buf1[256], buf[22]; - String tmp(buf1, sizeof(buf1), log_cs); - tmp.length(0); - tmp.append(get_var_type_name()); - tmp.append('='); - tmp.append(llstr(val, buf)); - protocol->store(tmp.ptr(), tmp.length()); + char buf[64], *pos; + pos= strmov(buf, get_var_type_name()); + *(pos++)='='; + pos=int10_to_str(val, pos, -10); + protocol->store(buf, pos-buf); } #endif // !MYSQL_CLIENT @@ -1911,19 +1986,16 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli) #ifndef MYSQL_CLIENT void Slave_log_event::pack_info(Protocol *protocol) { - char buf1[256], buf[22], *end; - String tmp(buf1, sizeof(buf1), log_cs); - tmp.length(0); - tmp.append("host="); - tmp.append(master_host); - tmp.append(",port="); - end= int10_to_str((long) master_port, buf, 10); - tmp.append(buf, (uint32) (end-buf)); - tmp.append(",log="); - tmp.append(master_log); - tmp.append(",pos="); - tmp.append(llstr(master_pos,buf)); - protocol->store(tmp.ptr(), tmp.length()); + char buf[256], *pos; + pos= strmov(buf, "host="); + pos= strnmov(pos, master_host, HOSTNAME_LENGTH); + pos= strmov(pos, ",port="); + pos= int10_to_str((long) master_port, pos, 10); + pos= strmov(pos, ",log="); + pos= strmov(pos, master_log); + pos= strmov(pos, ",pos="); + pos= int10_to_str(master_pos, pos, 10); + protocol->store(buf, pos-buf); } #endif // !MYSQL_CLIENT @@ -2241,13 +2313,31 @@ Create_file_log_event::Create_file_log_event(const char* buf, int len, ****************************************************************************/ #ifdef MYSQL_CLIENT +void Create_file_log_event::print(FILE* file, bool short_form, + char* last_db, bool enable_local) +{ + if (short_form) + { + if (enable_local && check_fname_outside_temp_buf()) + Load_log_event::print(file, 1, last_db); + return; + } + + if (enable_local) + { + if (!check_fname_outside_temp_buf()) + fprintf(file, "#"); + Load_log_event::print(file, 1, last_db); + fprintf(file, "#"); + } + + fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); +} + void Create_file_log_event::print(FILE* file, bool short_form, char* last_db) { - if (short_form) - return; - Load_log_event::print(file, 1, last_db); - fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); + print(file,short_form,last_db,0); } #endif // MYSQL_CLIENT @@ -2259,20 +2349,18 @@ void Create_file_log_event::print(FILE* file, bool short_form, #ifndef MYSQL_CLIENT void Create_file_log_event::pack_info(Protocol *protocol) { - char buf1[256],buf[22], *end; - String tmp(buf1, sizeof(buf1), log_cs); - tmp.length(0); - tmp.append("db="); - tmp.append(db, db_len); - tmp.append(";table="); - tmp.append(table_name, table_name_len); - tmp.append(";file_id="); - end= int10_to_str((long) file_id, buf, 10); - tmp.append(buf, (uint32) (end-buf)); - tmp.append(";block_len="); - end= int10_to_str((long) block_len, buf, 10); - tmp.append(buf, (uint32) (end-buf)); - protocol->store((char*) tmp.ptr(), tmp.length()); + char buf[NAME_LEN*2 + 30 + 21*2], *pos; + pos= strmov(buf, "db="); + memcpy(pos, db, db_len); + pos+= db_len; + pos= strmov(pos, ";table="); + memcpy(pos, table_name, table_name_len); + pos+= table_name_len; + pos= strmov(pos, ";file_id="); + pos= int10_to_str((long) file_id, pos, 10); + pos= strmov(pos, ";block_len="); + pos= int10_to_str((long) block_len, pos, 10); + protocol->store(buf, pos-buf); } #endif // !MYSQL_CLIENT @@ -2680,7 +2768,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) save_options = thd->options; thd->options &= ~ (ulong) (OPTION_BIN_LOG); lev->thd = thd; - if (lev->exec_event(0,0)) + /* + lev->exec_event should use rli only for errors + i.e. should not advance rli's position + */ + if (lev->exec_event(0,rli,1)) { slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname); thd->options = save_options; diff --git a/sql/log_event.h b/sql/log_event.h index ec3b4819e74..8046d0abb92 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -447,6 +447,13 @@ public: uint32 skip_lines; sql_ex_info sql_ex; + /* fname doesn't point to memory inside Log_event::temp_buf */ + void set_fname_outside_temp_buf(const char *afname, uint alen) + {fname=afname;fname_len=alen;} + /* fname doesn't point to memory inside Log_event::temp_buf */ + int check_fname_outside_temp_buf() + {return fnametemp_buf+cached_event_len;} + #ifndef MYSQL_CLIENT String field_lens_buf; String fields_buf; @@ -460,9 +467,10 @@ public: const char* get_db() { return db; } int exec_event(struct st_relay_log_info* rli) { - return exec_event(thd->slave_net,rli); + return exec_event(thd->slave_net,rli,0); } - int exec_event(NET* net, struct st_relay_log_info* rli); + int exec_event(NET* net, struct st_relay_log_info* rli, + bool use_rli_only_for_errors); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); #endif @@ -689,6 +697,7 @@ public: int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); + void print(FILE* file, bool short_form, char* last_db, bool enable_local); #endif Create_file_log_event(const char* buf, int event_len, bool old_format); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 655e4d7b972..fc34cce8882 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -209,6 +209,11 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #define MODE_MSSQL 512 #define MODE_DB2 1024 #define MODE_SAPDB 2048 +#define MODE_NO_KEY_OPTIONS 4096 +#define MODE_NO_TABLE_OPTIONS 8192 +#define MODE_NO_FIELD_OPTIONS 16384 +#define MODE_MYSQL323 32768 +#define MODE_MYSQL40 65536 #define RAID_BLOCK_SIZE 1024 @@ -235,6 +240,10 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); #define SHOW_LOG_STATUS_FREE "FREE" #define SHOW_LOG_STATUS_INUSE "IN USE" +/* Options to add_table_to_list() */ +#define TL_OPTION_UPDATING 1 +#define TL_OPTION_FORCE_INDEX 2 + /* Some portable defines */ #define portable_sizeof_char_ptr 8 @@ -820,7 +829,6 @@ uint calc_week(TIME *ltime, bool with_year, bool sunday_first_day_of_week, void find_date(char *pos,uint *vek,uint flag); TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end); TYPELIB *typelib(List &strings); -void clean_up(bool print_message=1); ulong get_form_pos(File file, uchar *head, TYPELIB *save_names); ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames, const char *newname); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d6a5c0b8412..f30034049f0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -424,12 +424,12 @@ double log_10[32]; /* 10 potences */ I_List threads,thread_cache; time_t start_time; -ulong opt_sql_mode = 0L; const char *sql_mode_names[] = { "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", - "POSTGRESQL", "ORACLE", "MSSQL", "SAPDB", + "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS", + "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", NullS }; TYPELIB sql_mode_typelib= {array_elements(sql_mode_names)-1,"", @@ -491,6 +491,7 @@ extern "C" pthread_handler_decl(handle_slave,arg); static uint set_maximum_open_files(uint max_file_limit); #endif static ulong find_bit_type(const char *x, TYPELIB *bit_lib); +static void clean_up(bool print_message); /**************************************************************************** ** Code to end mysqld @@ -763,13 +764,13 @@ void kill_mysql(void) #if defined(OS2) extern "C" void kill_server(int sig_ptr) -#define RETURN_FROM_KILL_SERVER return +#define RETURN_FROM_KILL_SERVER DBUG_RETURN #elif !defined(__WIN__) static void *kill_server(void *sig_ptr) -#define RETURN_FROM_KILL_SERVER return 0 +#define RETURN_FROM_KILL_SERVER DBUG_RETURN(0) #else static void __cdecl kill_server(int sig_ptr) -#define RETURN_FROM_KILL_SERVER return +#define RETURN_FROM_KILL_SERVER DBUG_RETURN #endif { int sig=(int) (long) sig_ptr; // This is passed a int @@ -848,7 +849,7 @@ extern "C" sig_handler print_signal_warning(int sig) void unireg_end(void) { - clean_up(); + clean_up(1); my_thread_end(); #ifdef SIGNALS_DONT_BREAK_READ exit(0); @@ -863,7 +864,7 @@ extern "C" void unireg_abort(int exit_code) DBUG_ENTER("unireg_abort"); if (exit_code) sql_print_error("Aborting\n"); - clean_up(); /* purecov: inspected */ + clean_up(1); /* purecov: inspected */ DBUG_PRINT("quit",("done with cleanup in unireg_abort")); my_thread_end(); exit(exit_code); /* purecov: inspected */ @@ -908,12 +909,12 @@ void clean_up(bool print_message) regex_end(); #endif + if (print_message && errmesg) + sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname); #if !defined(__WIN__) && !defined(EMBEDDED_LIBRARY) if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist #endif - if (print_message && errmesg) - sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname); x_free((gptr) my_errmsg[ERRMAPP]); /* Free messages */ DBUG_PRINT("quit", ("Error messages freed")); /* Tell main we are ready */ @@ -923,6 +924,10 @@ void clean_up(bool print_message) /* do the broadcast inside the lock to ensure that my_end() is not called */ (void) pthread_cond_broadcast(&COND_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count); + /* + The following lines may never be executed as the main thread may have + killed us + */ DBUG_PRINT("quit", ("done with cleanup")); } /* clean_up */ @@ -1502,7 +1507,7 @@ static void init_signals(void) /* Change limits so that we will get a core file */ struct rlimit rl; rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; - if (setrlimit(RLIMIT_CORE, &rl)) + if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings) sql_print_error("Warning: setrlimit could not change the size of core files to 'infinity'; We may not be able to generate a core file on signals"); } #endif @@ -1571,8 +1576,11 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) my_thread_init(); // Init new thread DBUG_ENTER("signal_hand"); SIGNAL_THD; - /* Setup alarm handler */ - init_thr_alarm(max_connections+max_insert_delayed_threads); + /* + Setup alarm handler + The two extra handlers are for slave threads + */ + init_thr_alarm(max_connections+max_insert_delayed_threads+2); #if SIGINT != THR_KILL_SIGNAL (void) sigemptyset(&set); // Setup up SIGINT for debug (void) sigaddset(&set,SIGINT); // For debugging @@ -1660,12 +1668,15 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) } break; case SIGHUP: - reload_acl_and_cache((THD*) 0, - (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST | - REFRESH_STATUS | REFRESH_GRANT | REFRESH_THREADS | - REFRESH_HOSTS), - (TABLE_LIST*) 0); // Flush logs - mysql_print_status((THD*) 0); // Send debug some info + if (!abort_loop) + { + reload_acl_and_cache((THD*) 0, + (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST | + REFRESH_STATUS | REFRESH_GRANT | + REFRESH_THREADS | REFRESH_HOSTS), + (TABLE_LIST*) 0); // Flush logs + mysql_print_status((THD*) 0); // Send debug some info + } break; #ifdef USE_ONE_SIGNAL_HAND case THR_SERVER_ALARM: @@ -4290,9 +4301,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_endinfo=1; /* unireg: memory allocation */ break; case 'a': - opt_sql_mode = (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | - MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE | - MODE_ONLY_FULL_GROUP_BY); + global_system_variables.sql_mode= + (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | + MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE | + MODE_ONLY_FULL_GROUP_BY); global_system_variables.tx_isolation= ISO_SERIALIZABLE; break; case 'b': @@ -4654,8 +4666,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), berkeley_lock_type=berkeley_lock_types[type-1]; else { - if (test_if_int(argument,(uint) strlen(argument), my_charset_latin1)) - berkeley_lock_scan_time=atoi(argument); + int err; + char *end; + uint length= strlen(argument); + long value= my_strntol(my_charset_latin1, argument, length, 10, &end, &err); + if (test_if_int(argument,(uint) length, end, my_charset_latin1)) + berkeley_lock_scan_time= value; else { fprintf(stderr,"Unknown lock type: %s\n",argument); @@ -4716,16 +4732,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } case OPT_SQL_MODE: { - sql_mode_str = argument; - if ((opt_sql_mode = - find_bit_type(argument, &sql_mode_typelib)) == ~(ulong) 0) + sql_mode_str= argument; + if ((global_system_variables.sql_mode= + find_bit_type(argument, &sql_mode_typelib)) == ~(ulong) 0) { fprintf(stderr, "Unknown option to sql-mode: %s\n", argument); exit(1); } - global_system_variables.tx_isolation= ((opt_sql_mode & MODE_SERIALIZABLE) ? - ISO_SERIALIZABLE : - ISO_REPEATABLE_READ); + global_system_variables.tx_isolation= + ((global_system_variables.sql_mode & MODE_SERIALIZABLE) ? + ISO_SERIALIZABLE : + ISO_REPEATABLE_READ); break; } case OPT_MASTER_PASSWORD: diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 887ce6c561a..43066a29624 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -603,12 +603,14 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, records++; /* purecov: inspected */ scan_time=(double) records / TIME_FOR_COMPARE+1; read_time=(double) head->file->scan_time()+ scan_time + 1.0; + if (head->force_index) + scan_time= read_time= DBL_MAX; if (limit < records) read_time=(double) records+scan_time+1; // Force to use index else if (read_time <= 2.0 && !force_quick_range) DBUG_RETURN(0); /* No need for quick select */ - DBUG_PRINT("info",("Time to scan table: %ld",(long) read_time)); + DBUG_PRINT("info",("Time to scan table: %g", read_time)); keys_to_use&=head->keys_in_use_for_query; if (keys_to_use) @@ -2794,7 +2796,7 @@ static void print_key(KEY_PART *key_part,const char *key,uint used_length) { char buff[1024]; - String tmp(buff,sizeof(buff),NULL); + String tmp(buff,sizeof(buff),my_charset_bin); for (uint length=0; length < used_length ; diff --git a/sql/procedure.h b/sql/procedure.h index bc1b6062e1d..03a45488b03 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -59,7 +59,7 @@ public: void set(double nr) { value=nr; } void set(longlong nr) { value=(double) nr; } void set(const char *str,uint length,CHARSET_INFO *cs) - { value=my_strntod(cs,str,length,(char**)0); } + { int err; value=my_strntod(cs,(char*) str,length,(char**)0,&err); } double val() { return value; } longlong val_int() { return (longlong) value; } String *val_str(String *s) { s->set(value,decimals,thd_charset()); return s; } @@ -77,7 +77,7 @@ public: void set(double nr) { value=(longlong) nr; } void set(longlong nr) { value=nr; } void set(const char *str,uint length, CHARSET_INFO *cs) - { value=my_strntoll(cs,str,length,NULL,10); } + { int err; value=my_strntoll(cs,str,length,10,NULL,&err); } double val() { return (double) value; } longlong val_int() { return value; } String *val_str(String *s) { s->set(value, thd_charset()); return s; } @@ -98,13 +98,16 @@ public: { str_value.copy(str,length,cs); } double val() { + int err; CHARSET_INFO *cs=str_value.charset(); - return my_strntod(cs, str_value.ptr(), str_value.length(),(char**)0); + return my_strntod(cs, (char*) str_value.ptr(), str_value.length(), + (char**) 0, &err); } longlong val_int() { + int err; CHARSET_INFO *cs=str_value.charset(); - return my_strntoll(cs,str_value.ptr(),str_value.length(),NULL,10); + return my_strntoll(cs,str_value.ptr(),str_value.length(),10,NULL,&err); } String *val_str(String*) { diff --git a/sql/protocol.cc b/sql/protocol.cc index 15f4ca9ad94..48ef9ecb71e 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -171,7 +171,10 @@ net_printf(THD *thd, uint errcode, ...) { if (thd->bootstrap) { - /* In bootstrap it's ok to print on stderr */ + /* + In bootstrap it's ok to print on stderr + This may also happen when we get an error from a slave thread + */ fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); thd->fatal_error=1; } diff --git a/sql/set_var.cc b/sql/set_var.cc index fc268d314ba..79e9f67e905 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -215,8 +215,10 @@ sys_var_long_ptr sys_slow_launch_time("slow_launch_time", &slow_launch_time); sys_var_thd_ulong sys_sort_buffer("sort_buffer_size", &SV::sortbuff_size); -sys_var_thd_enum sys_table_type("table_type", &SV::table_type, - &ha_table_typelib); +sys_var_thd_sql_mode sys_sql_mode("sql_mode", + &SV::sql_mode); +sys_var_thd_enum sys_table_type("table_type", &SV::table_type, + &ha_table_typelib); sys_var_long_ptr sys_table_cache_size("table_cache", &table_cache_size); sys_var_long_ptr sys_thread_cache_size("thread_cache_size", @@ -391,6 +393,7 @@ sys_var *sys_variables[]= &sys_sql_big_tables, &sys_sql_low_priority_updates, &sys_sql_max_join_size, + &sys_sql_mode, &sys_sql_warnings, &sys_table_cache_size, &sys_table_type, @@ -541,7 +544,7 @@ struct show_var_st init_vars[]= { {"socket", (char*) &mysql_unix_port, SHOW_CHAR_PTR}, #endif {sys_sort_buffer.name, (char*) &sys_sort_buffer, SHOW_SYS}, - {"sql_mode", (char*) &opt_sql_mode, SHOW_LONG}, + {sys_sql_mode.name, (char*) &sys_sql_mode, SHOW_SYS}, {"table_cache", (char*) &table_cache_size, SHOW_LONG}, {sys_table_type.name, (char*) &sys_table_type, SHOW_SYS}, {sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS}, @@ -923,6 +926,44 @@ err: return 1; } + + +bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) +{ + char buff[80], *value, *error= 0; + uint error_len= 0; + String str(buff, sizeof(buff), system_charset_info), *res; + + if (var->value->result_type() == STRING_RESULT) + { + if (!(res= var->value->val_str(&str))) + goto err; + (long) var->save_result.ulong_value= (ulong) + find_set(enum_names, res->c_ptr(), res->length(), &error, &error_len); + if (error_len) + { + strmake(buff, error, min(sizeof(buff), error_len)); + goto err; + } + } + else + { + ulonglong tmp= var->value->val_int(); + if (tmp >= enum_names->count) + { + llstr(tmp, buff); + goto err; + } + var->save_result.ulong_value= (ulong) tmp; // Save for update + } + return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buff); + return 1; +} + + /* Return an Item for a variable. Used with @@[global.]variable_name @@ -999,6 +1040,40 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type) } +byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type) +{ + ulong val; + char buff[256]; + String tmp(buff, sizeof(buff), default_charset_info); + my_bool found= 0; + + tmp.length(0); + val= ((type == OPT_GLOBAL) ? global_system_variables.*offset : + thd->variables.*offset); + for (uint i= 0; val; val>>= 1, i++) + { + if (val & 1) + { + tmp.append(enum_names->type_names[i]); + tmp.append(','); + } + } + if (tmp.length()) + tmp.length(tmp.length() - 1); + return (byte*) thd->strdup(tmp.c_ptr()); +} + + +void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.*offset= 0; + else + thd->variables.*offset= global_system_variables.*offset; +} + + + bool sys_var_thd_bit::update(THD *thd, set_var *var) { int res= (*update_func)(thd, var); diff --git a/sql/set_var.h b/sql/set_var.h index 6f257e1ace3..5d7463d9fa8 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -28,7 +28,7 @@ class sys_var; class set_var; typedef struct system_variables SV; -extern TYPELIB bool_typelib, delay_key_write_typelib; +extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib; enum enum_var_type { @@ -56,6 +56,7 @@ public: virtual ~sys_var() {} virtual bool check(THD *thd, set_var *var) { return 0; } bool check_enum(THD *thd, set_var *var, TYPELIB *enum_names); + bool check_set(THD *thd, set_var *var, TYPELIB *enum_names); virtual bool update(THD *thd, set_var *var)=0; virtual void set_default(THD *thd, enum_var_type type) {} virtual SHOW_TYPE type() { return SHOW_UNDEF; } @@ -273,6 +274,7 @@ public: class sys_var_thd_enum :public sys_var_thd { +protected: ulong SV::*offset; TYPELIB *enum_names; public: @@ -297,6 +299,21 @@ public: }; +class sys_var_thd_sql_mode :public sys_var_thd_enum +{ +public: + sys_var_thd_sql_mode(const char *name_arg, ulong SV::*offset_arg) + :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib) + {} + bool check(THD *thd, set_var *var) + { + return check_set(thd, var, enum_names); + } + void set_default(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type); +}; + + class sys_var_thd_bit :public sys_var_thd { sys_update_func update_func; diff --git a/sql/slave.cc b/sql/slave.cc index 342a35b8821..271fe8bc2d6 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -413,6 +413,7 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) } if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) && mi->slave_running) { + DBUG_PRINT("info",("Terminating IO thread")); mi->abort_slave=1; if ((error=terminate_slave_thread(mi->io_thd,io_lock, io_cond_lock, @@ -423,6 +424,7 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) } if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running) { + DBUG_PRINT("info",("Terminating SQL thread")); DBUG_ASSERT(mi->rli.sql_thd != 0) ; mi->rli.abort_slave=1; if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock, @@ -2572,12 +2574,6 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev) memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1); mi->master_log_pos= rev->pos; - - pthread_mutex_lock(&mi->rli.data_lock); - memcpy(mi->rli.master_log_name, rev->new_log_ident, rev->ident_len+1); - mi->rli.master_log_pos= rev->pos; - pthread_mutex_unlock(&mi->rli.data_lock); - DBUG_PRINT("info", ("master_log_pos: '%s' %d", mi->master_log_name, (ulong) mi->master_log_pos)); #ifndef DBUG_OFF diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b5178076258..db32030efd1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -242,6 +242,7 @@ static void free_cache_entry(TABLE *table) DBUG_VOID_RETURN; } +/* Free resources allocated by filesort() and read_record() */ void free_io_cache(TABLE *table) { @@ -747,7 +748,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->outer_join=table->null_row=table->maybe_null=0; + table->outer_join= table->null_row= table->maybe_null= table->force_index= 0; table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= table->keys_in_use; table->used_keys= table->keys_for_keyread; @@ -906,7 +907,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->outer_join=table->null_row=table->maybe_null=0; + table->outer_join= table->null_row= table->maybe_null= table->force_index= 0; table->status=STATUS_NO_RECORD; table->keys_in_use_for_query= table->keys_in_use; table->used_keys= table->keys_for_keyread; @@ -977,6 +978,7 @@ bool reopen_table(TABLE *table,bool locked) tmp.status= table->status; tmp.keys_in_use_for_query= tmp.keys_in_use; tmp.used_keys= tmp.keys_for_keyread; + tmp.force_index= tmp.force_index; /* Get state */ tmp.key_length= table->key_length; @@ -1748,12 +1750,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, } if (report_error) { - if (thd->lex.current_select->get_master()->order_list.elements) - my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, ER(ER_TABLENAME_NOT_ALLOWED_HERE), - MYF(0), table_name, thd->where); - else - my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), - table_name, thd->where); + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + table_name, thd->where); } else return (Field*) not_found_field; @@ -1969,6 +1967,7 @@ bool setup_tables(TABLE_LIST *tables) table->maybe_null=test(table->outer_join=table_list->outer_join); table->tablenr=tablenr; table->map= (table_map) 1 << tablenr; + table->force_index= table_list->force_index; if (table_list->use_index) { key_map map= get_key_map_from_key_list(table, diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 1cfbbf74da6..9e1d9c0b64c 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -357,12 +357,6 @@ TODO list: #define DUMP(C) #endif -#ifdef FN_NO_CASE_SENCE -#define DB_NAME_PREPROCESS(C) tolower(C) -#else -#define DB_NAME_PREPROCESS(C) (C) -#endif - const char *query_cache_type_names[]= { "OFF", "ON", "DEMAND",NullS }; TYPELIB query_cache_type_typelib= { @@ -2478,12 +2472,18 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, if (tables_used->table->db_type == DB_TYPE_MRG_ISAM || tables_used->table->tmp_table != NO_TMP_TABLE || - (tables_used->db_length == 5 && - DB_NAME_PREPROCESS(tables_used->db[0])=='m' && - DB_NAME_PREPROCESS(tables_used->db[1])=='y' && - DB_NAME_PREPROCESS(tables_used->db[2])=='s' && - DB_NAME_PREPROCESS(tables_used->db[3])=='q' && - DB_NAME_PREPROCESS(tables_used->db[4])=='l')) + (tables_used->db_length == 5 && +#ifdef FN_NO_CASE_SENCE + // TODO: latin1 charset should be replaced with system charset + my_strncasecmp(my_charset_latin1,tables_used->db,"mysql",5) == 0 +#else + tables_used->db[0]=='m' && + tables_used->db[1]=='y' && + tables_used->db[2]=='s' && + tables_used->db[3]=='q' && + tables_used->db[4]=='l' +#endif + )) { DBUG_PRINT("qcache", ("select not cacheable: used MRG_ISAM, temporary or system table(s)")); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ab789370660..5734b340744 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -193,7 +193,6 @@ void THD::init(void) pthread_mutex_unlock(&LOCK_global_system_variables); server_status= SERVER_STATUS_AUTOCOMMIT; options= thd_startup_options; - sql_mode=(uint) opt_sql_mode; open_options=ha_open_options; update_lock_default= (variables.low_priority_updates ? TL_WRITE_LOW_PRIORITY : @@ -526,7 +525,7 @@ bool select_send::send_data(List &items) List_iterator_fast li(items); Protocol *protocol= thd->protocol; char buff[MAX_FIELD_WIDTH]; - String buffer(buff, sizeof(buff), NULL); + String buffer(buff, sizeof(buff), my_charset_bin); DBUG_ENTER("send_data"); protocol->prepare_for_resend(); @@ -649,7 +648,7 @@ bool select_export::send_data(List &items) DBUG_ENTER("send_data"); char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH]; bool space_inited=0; - String tmp(buff,sizeof(buff),NULL),*res; + String tmp(buff,sizeof(buff),my_charset_bin),*res; tmp.length(0); if (unit->offset_limit_cnt) @@ -857,7 +856,7 @@ bool select_dump::send_data(List &items) { List_iterator_fast li(items); char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),NULL),*res; + String tmp(buff,sizeof(buff),my_charset_bin),*res; tmp.length(0); Item *item; DBUG_ENTER("send_data"); diff --git a/sql/sql_class.h b/sql/sql_class.h index 253ec3d2918..227d541807a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -369,6 +369,7 @@ struct system_variables ulong table_type; ulong tmp_table_size; ulong tx_isolation; + ulong sql_mode; /* In slave thread we need to know in behalf of which @@ -431,7 +432,6 @@ public: uint client_capabilities; /* What the client supports */ /* Determines if which non-standard SQL behaviour should be enabled */ - uint sql_mode; ulong max_client_packet_length; ulong master_access; /* Global privileges from mysql.user */ ulong db_access; /* Privileges for current db */ diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 97703cd6b20..0d8af46dbf6 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -109,6 +109,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (cond && (cond->check_cols(1) || cond->fix_fields(thd, tables, &cond))) return -1; + /* InnoDB needs to know that this table handle is used in the HANDLER */ + + table->file->init_table_handle_for_HANDLER(); + if (keyname) { if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0) @@ -131,8 +135,6 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, insert_fields(thd,tables,tables->db,tables->alias,&it); - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it - select_limit+=offset_limit; protocol->send_fields(&list,1); @@ -142,6 +144,12 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!lock) goto err0; // mysql_lock_tables() printed error message already + /* In ::external_lock InnoDB resets the fields which tell it that + the handle is used in the HANDLER interface. Tell it again that + we are using it for HANDLER. */ + + table->file->init_table_handle_for_HANDLER(); + for (num_rows=0; num_rows < select_limit; ) { switch (mode) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 59684955e44..23b207b252c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -107,7 +107,7 @@ void lex_init(void) state_map[i]=(uchar) STATE_CHAR; } state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) STATE_IDENT; - state_map[(uchar)'\'']=state_map[(uchar)'"']=(uchar) STATE_STRING; + state_map[(uchar)'\'']=(uchar) STATE_STRING; state_map[(uchar)'-']=state_map[(uchar)'+']=(uchar) STATE_SIGNED_NUMBER; state_map[(uchar)'.']=(uchar) STATE_REAL_OR_POINT; state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) STATE_CMP_OP; @@ -122,10 +122,7 @@ void lex_init(void) state_map[(uchar)'*']= (uchar) STATE_END_LONG_COMMENT; state_map[(uchar)'@']= (uchar) STATE_USER_END; state_map[(uchar) '`']= (uchar) STATE_USER_VARIABLE_DELIMITER; - if (opt_sql_mode & MODE_ANSI_QUOTES) - { - state_map[(uchar) '"'] = STATE_USER_VARIABLE_DELIMITER; - } + state_map[(uchar)'"']= (uchar) STAT_STRING_OR_DELIMITER; /* Create a second map to make it faster to find identifiers @@ -167,7 +164,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->convert_set= (lex->thd= thd)->variables.convert_set; lex->thd_charset= lex->thd->variables.thd_charset; lex->yacc_yyss=lex->yacc_yyvs=0; - lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE); + lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE); lex->slave_thd_opt=0; lex->sql_command=SQLCOM_END; lex->safe_to_cache_query= 1; @@ -671,12 +668,13 @@ int yylex(void *arg, void *yythd) return(IDENT); case STATE_USER_VARIABLE_DELIMITER: + { + char delim= c; // Used char lex->tok_start=lex->ptr; // Skip first ` #ifdef USE_MB if (use_mb(system_charset_info)) { - while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER && - c != (uchar) NAMES_SEP_CHAR) + while ((c=yyGet()) && c != delim && c != (uchar) NAMES_SEP_CHAR) { if (my_ismbhead(system_charset_info, c)) { @@ -716,10 +714,10 @@ int yylex(void *arg, void *yythd) } if (lex->convert_set) lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen); - if (state_map[c] == STATE_USER_VARIABLE_DELIMITER) + if (c == delim) yySkip(); // Skip end ` return(IDENT); - + } case STATE_SIGNED_NUMBER: // Incomplete signed number if (prev_state == STATE_OPERATOR_OR_IDENT) { @@ -832,6 +830,13 @@ int yylex(void *arg, void *yythd) lex->next_state= STATE_START; // Allow signed numbers return(tokval); + case STAT_STRING_OR_DELIMITER: + if (((THD *) yythd)->variables.sql_mode & MODE_ANSI_QUOTES) + { + state= STATE_USER_VARIABLE_DELIMITER; + break; + } + /* " used for strings */ case STATE_STRING: // Incomplete text string if (!(yylval->lex_str.str = get_text(lex))) { @@ -926,6 +931,7 @@ int yylex(void *arg, void *yythd) switch (state_map[yyPeek()]) { case STATE_STRING: case STATE_USER_VARIABLE_DELIMITER: + case STAT_STRING_OR_DELIMITER: break; case STATE_USER_END: lex->next_state=STATE_SYSTEM_VAR; @@ -980,7 +986,7 @@ int yylex(void *arg, void *yythd) void st_select_lex_node::init_query() { - dependent= 0; + no_table_names_allowed= dependent= 0; } void st_select_lex_node::init_select() @@ -1208,13 +1214,14 @@ List* st_select_lex_node::get_use_index() { return 0; } List* st_select_lex_node::get_ignore_index() { return 0; } TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, - bool updating, + ulong table_join_options, thr_lock_type flags, List *use_index, List *ignore_index) { return 0; } +ulong st_select_lex_node::get_table_join_options() { return 0; } /* This is used for UNION & subselect to create a new table list of all used @@ -1371,6 +1378,11 @@ List* st_select_lex::get_ignore_index() return ignore_index_ptr; } +ulong st_select_lex::get_table_join_options() +{ + return table_join_options; +} + /* There are st_select_lex::add_table_to_list & st_select_lex::set_lock_for_tables in sql_parse.cc diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 9b8f4a47515..5c1c91bbe4a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -86,7 +86,8 @@ enum lex_states STATE_REAL_OR_POINT, STATE_BOOL, STATE_EOL, STATE_ESCAPE, STATE_LONG_COMMENT, STATE_END_LONG_COMMENT, STATE_COLON, STATE_SET_VAR, STATE_USER_END, STATE_HOSTNAME, STATE_SKIP, STATE_USER_VARIABLE_DELIMITER, STATE_SYSTEM_VAR, - STATE_IDENT_OR_KEYWORD, STATE_IDENT_OR_HEX, STATE_IDENT_OR_BIN + STATE_IDENT_OR_KEYWORD, STATE_IDENT_OR_HEX, STATE_IDENT_OR_BIN, + STAT_STRING_OR_DELIMITER }; @@ -212,6 +213,7 @@ public: bool with_sum_func; bool create_refs; bool dependent; /* dependent from outer select subselect */ + bool no_table_names_allowed; /* used for global order by */ static void *operator new(size_t size) { @@ -243,9 +245,10 @@ public: virtual List* get_item_list(); virtual List* get_use_index(); virtual List* get_ignore_index(); + virtual ulong get_table_join_options(); virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, - bool updating, + ulong table_options, thr_lock_type flags= TL_UNLOCK, List *use_index= 0, List *ignore_index= 0); @@ -336,6 +339,7 @@ public: List ftfunc_list_alloc; JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */ const char *type; /* type of select for EXPLAIN */ + ulong table_join_options; uint in_sum_expr; uint select_number; /* number of select (used for EXPLAIN) */ bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ @@ -373,9 +377,10 @@ public: List* get_item_list(); List* get_use_index(); List* get_ignore_index(); + ulong get_table_join_options(); TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, - bool updating, + ulong table_options, thr_lock_type flags= TL_UNLOCK, List *use_index= 0, List *ignore_index= 0); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f6e21e421d9..1e2ce9e9a86 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -518,7 +518,8 @@ check_connections(THD *thd) vio_in_addr(net->vio,&thd->remote.sin_addr); thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); /* Cut very long hostnames to avoid possible overflows */ - thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; + if (thd->host) + thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; if (connect_errors > max_connect_errors) return(ER_HOST_IS_BLOCKED); } @@ -587,7 +588,7 @@ check_connections(THD *thd) thd->client_capabilities=uint2korr(net->read_pos); if (thd->client_capabilities & CLIENT_IGNORE_SPACE) - thd->sql_mode|= MODE_IGNORE_SPACE; + thd->variables.sql_mode|= MODE_IGNORE_SPACE; #ifdef HAVE_OPENSSL DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities)); if (thd->client_capabilities & CLIENT_SSL) @@ -3457,10 +3458,14 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1); if (default_value) { + char *not_used; + uint not_used2; + thd->cuted_fields=0; String str,*res; res=default_value->val_str(&str); - (void) find_set(interval,res->ptr(),res->length()); + (void) find_set(interval, res->ptr(), res->length(), ¬_used, + ¬_used2); if (thd->cuted_fields) { net_printf(thd,ER_INVALID_DEFAULT,field_name); @@ -3597,11 +3602,30 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) } +/* + Add a table to list of used tables + + SYNOPSIS + add_table_to_list() + table Table to add + alias alias for table (or null if no alias) + table_options A set of the following bits: + TL_OPTION_UPDATING Table will be updated + TL_OPTION_FORCE_INDEX Force usage of index + lock_type How table should be locked + use_index List of indexed used in USE INDEX + ignore_index List of indexed used in IGNORE INDEX + + RETURN + 0 Error + # Pointer to TABLE_LIST element added to the total table list +*/ + TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, - bool updating, - thr_lock_type flags, + ulong table_options, + thr_lock_type lock_type, List *use_index, List *ignore_index) { @@ -3658,8 +3682,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } ptr->real_name=table->table.str; ptr->real_name_length=table->table.length; - ptr->lock_type=flags; - ptr->updating=updating; + ptr->lock_type= lock_type; + ptr->updating= test(table_options & TL_OPTION_UPDATING); + ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->derived= (SELECT_LEX_UNIT *) table->sel; if (use_index) ptr->use_index=(List *) thd->memdup((gptr) use_index, @@ -3669,7 +3694,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, sizeof(*ignore_index)); /* check that used name is unique */ - if (flags != TL_IGNORE) + if (lock_type != TL_IGNORE) { for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ; tables ; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 93004ce2937..69228c6ec4c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -321,62 +321,18 @@ static bool setup_params_data(PREP_STMT *stmt) if (!param->long_data_supplied) { if (IS_PARAM_NULL(pos,param_no)) - param->maybe_null=param->null_value=1; + param->maybe_null= param->null_value= 1; else + { + param->maybe_null= param->null_value= 0; param->setup_param_func(param,&read_pos); + } } param_no++; } DBUG_RETURN(0); } -/* - Validates insert fields -*/ - -static int check_prepare_fields(THD *thd,TABLE *table, List &fields, - List &values, ulong counter) -{ - if (fields.elements == 0 && values.elements != 0) - { - if (values.elements != table->fields) - { - my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, - ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0),counter); - return -1; - } - } - else - { - if (fields.elements != values.elements) - { - my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, - ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0),counter); - return -1; - } - TABLE_LIST table_list; - bzero((char*) &table_list,sizeof(table_list)); - table_list.db= table->table_cache_key; - table_list.real_name= table_list.alias= table->table_name; - table_list.table= table; - table_list.grant= table->grant; - - thd->dupp_field=0; - if (setup_tables(&table_list) || - setup_fields(thd,&table_list,fields,1,0,0)) - return -1; - if (thd->dupp_field) - { - my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name); - return -1; - } - } - return 0; -} - - /* Validate the following information for INSERT statement: - field existance @@ -516,21 +472,6 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, DBUG_RETURN(0); } - -/* - Check the access privileges -*/ - -static bool check_prepare_access(THD *thd, TABLE_LIST *tables, - uint type) -{ - if (check_access(thd,type,tables->db,&tables->grant.privilege)) - return 1; - if (grant_option && check_grant(thd,type,tables)) - return 1; - return 0; -} - /* Send the prepare query results back to client */ @@ -625,7 +566,7 @@ static bool parse_prepare_query(PREP_STMT *stmt, Initialize parameter items in statement */ -static bool init_param_items( PREP_STMT *stmt) +static bool init_param_items(PREP_STMT *stmt) { List ¶ms= stmt->thd->lex.param_list; Item_param **to; @@ -639,6 +580,24 @@ static bool init_param_items( PREP_STMT *stmt) return 0; } +/* + Initialize stmt execution +*/ + +static void init_stmt_execute(PREP_STMT *stmt) +{ + THD *thd= stmt->thd; + TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select_lex.table_list.first; + + /* + TODO: When the new table structure is ready, then have a status bit + to indicate the table is altered, and re-do the setup_* + and open the tables back. + */ + if (tables) + tables->table=0; //safety - nasty init +} + /* Parse the query and send the total number of parameters and resultset metadata information back to client (if any), @@ -719,6 +678,8 @@ void mysql_stmt_execute(THD *thd, char *packet) DBUG_VOID_RETURN; } + init_stmt_execute(stmt); + if (stmt->param_count && setup_params_data(stmt)) DBUG_VOID_RETURN; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e7784cad04d..5912f3021dc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2305,7 +2305,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, !(s->quick && best_key && s->quick->index == best_key->key && best_max_key_part >= s->table->quick_key_parts[best_key->key]) && !((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) && - s->table->used_keys && best_key)) + s->table->used_keys && best_key) && + !(s->table->force_index && best_key)) { // Check full join if (s->on_expr) { @@ -6946,7 +6947,7 @@ setup_group(THD *thd,TABLE_LIST *tables,List &fields, if (!order) return 0; /* Everything is ok */ - if (thd->sql_mode & MODE_ONLY_FULL_GROUP_BY) + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) { Item *item; List_iterator li(fields); @@ -6968,7 +6969,7 @@ setup_group(THD *thd,TABLE_LIST *tables,List &fields, return 1; } } - if (thd->sql_mode & MODE_ONLY_FULL_GROUP_BY) + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) { /* Don't allow one to use fields that is not used in GROUP BY */ Item *item; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b01555effa8..3ec45c8eca9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1001,11 +1001,22 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) static void append_identifier(THD *thd, String *packet, const char *name) { + char qtype; + if ((thd->variables.sql_mode & MODE_ANSI_QUOTES) || + (thd->variables.sql_mode & MODE_POSTGRESQL) || + (thd->variables.sql_mode & MODE_ORACLE) || + (thd->variables.sql_mode & MODE_MSSQL) || + (thd->variables.sql_mode & MODE_DB2) || + (thd->variables.sql_mode & MODE_SAPDB)) + qtype= '\"'; + else + qtype= '`'; + if (thd->options & OPTION_QUOTE_SHOW_CREATE) { - packet->append("`", 1); + packet->append(&qtype, 1); packet->append(name); - packet->append("`", 1); + packet->append(&qtype, 1); } else { @@ -1017,6 +1028,16 @@ append_identifier(THD *thd, String *packet, const char *name) static int store_create_info(THD *thd, TABLE *table, String *packet) { + my_bool foreign_db_mode= ((thd->variables.sql_mode & MODE_POSTGRESQL) || + (thd->variables.sql_mode & MODE_ORACLE) || + (thd->variables.sql_mode & MODE_MSSQL) || + (thd->variables.sql_mode & MODE_DB2) || + (thd->variables.sql_mode & MODE_SAPDB)); + my_bool limited_mysql_mode= ((thd->variables.sql_mode & + MODE_NO_FIELD_OPTIONS) || + (thd->variables.sql_mode & MODE_MYSQL323) || + (thd->variables.sql_mode & MODE_MYSQL40)); + DBUG_ENTER("store_create_info"); DBUG_PRINT("enter",("table: %s",table->real_name)); @@ -1057,9 +1078,10 @@ store_create_info(THD *thd, TABLE *table, String *packet) For string types dump collation name only if collation is not primary for the given charset */ - if (!field->binary() && !(field->charset()->state & MY_CS_PRIMARY)) + if (!field->binary() && !(field->charset()->state & MY_CS_PRIMARY) && + !limited_mysql_mode && !foreign_db_mode) { - packet->append(" collate ",9); + packet->append(" collate ", 9); packet->append(field->charset()->name); } if (flags & NOT_NULL_FLAG) @@ -1083,7 +1105,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append(tmp,0); } - if (field->unireg_check == Field::NEXT_NUMBER) + if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode) packet->append(" auto_increment", 15 ); if (field->comment.length) @@ -1117,17 +1139,20 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append("KEY ", 4); if (!found_primary) - append_identifier(thd,packet,key_info->name); - - if (table->db_type == DB_TYPE_HEAP && - key_info->algorithm == HA_KEY_ALG_BTREE) - packet->append(" USING BTREE", 12); - - // +BAR: send USING only in non-default case: non-spatial rtree - if ((key_info->algorithm == HA_KEY_ALG_RTREE) && - !(key_info->flags & HA_SPATIAL)) - packet->append(" USING RTREE",12); + append_identifier(thd, packet, key_info->name); + if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) && + !limited_mysql_mode && !foreign_db_mode) + { + if (table->db_type == DB_TYPE_HEAP && + key_info->algorithm == HA_KEY_ALG_BTREE) + packet->append(" TYPE BTREE", 11); + + // +BAR: send USING only in non-default case: non-spatial rtree + if ((key_info->algorithm == HA_KEY_ALG_RTREE) && + !(key_info->flags & HA_SPATIAL)) + packet->append(" TYPE RTREE", 11); + } packet->append(" (", 2); for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) @@ -1166,67 +1191,72 @@ store_create_info(THD *thd, TABLE *table, String *packet) } packet->append("\n)", 2); - packet->append(" TYPE=", 6); - packet->append(file->table_type()); - char buff[128]; - char* p; - - if (table->table_charset) + if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode) { - packet->append(" CHARSET="); - packet->append(table->table_charset->csname); - if (!(table->table_charset->state & MY_CS_PRIMARY)) + packet->append(" TYPE=", 6); + packet->append(file->table_type()); + char buff[128]; + char* p; + + if (table->table_charset && + !(thd->variables.sql_mode & MODE_MYSQL323) && + !(thd->variables.sql_mode & MODE_MYSQL40)) { - packet->append(" COLLATE="); - packet->append(table->table_charset->name); + packet->append(" CHARSET="); + packet->append(table->table_charset->csname); + if (!(table->table_charset->state & MY_CS_PRIMARY)) + { + packet->append(" COLLATE="); + packet->append(table->table_charset->name); + } } - } - if (table->min_rows) - { - packet->append(" MIN_ROWS="); - p = longlong10_to_str(table->min_rows, buff, 10); - packet->append(buff, (uint) (p - buff)); - } + if (table->min_rows) + { + packet->append(" MIN_ROWS="); + p = longlong10_to_str(table->min_rows, buff, 10); + packet->append(buff, (uint) (p - buff)); + } - if (table->max_rows) - { - packet->append(" MAX_ROWS="); - p = longlong10_to_str(table->max_rows, buff, 10); - packet->append(buff, (uint) (p - buff)); - } - if (table->avg_row_length) - { - packet->append(" AVG_ROW_LENGTH="); - p=longlong10_to_str(table->avg_row_length, buff,10); - packet->append(buff, (uint) (p - buff)); - } + if (table->max_rows) + { + packet->append(" MAX_ROWS="); + p = longlong10_to_str(table->max_rows, buff, 10); + packet->append(buff, (uint) (p - buff)); + } + if (table->avg_row_length) + { + packet->append(" AVG_ROW_LENGTH="); + p=longlong10_to_str(table->avg_row_length, buff,10); + packet->append(buff, (uint) (p - buff)); + } - if (table->db_create_options & HA_OPTION_PACK_KEYS) - packet->append(" PACK_KEYS=1", 12); - if (table->db_create_options & HA_OPTION_NO_PACK_KEYS) - packet->append(" PACK_KEYS=0", 12); - if (table->db_create_options & HA_OPTION_CHECKSUM) - packet->append(" CHECKSUM=1", 11); - if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE) - packet->append(" DELAY_KEY_WRITE=1",18); - if (table->row_type != ROW_TYPE_DEFAULT) - { - packet->append(" ROW_FORMAT=",12); - packet->append(ha_row_type[(uint) table->row_type]); - } - table->file->append_create_info(packet); - if (table->comment && table->comment[0]) - { - packet->append(" COMMENT=", 9); - append_unescaped(packet, table->comment, strlen(table->comment)); - } - if (file->raid_type) - { - char buff[100]; - sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld", - my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE); - packet->append(buff); + if (table->db_create_options & HA_OPTION_PACK_KEYS) + packet->append(" PACK_KEYS=1", 12); + if (table->db_create_options & HA_OPTION_NO_PACK_KEYS) + packet->append(" PACK_KEYS=0", 12); + if (table->db_create_options & HA_OPTION_CHECKSUM) + packet->append(" CHECKSUM=1", 11); + if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE) + packet->append(" DELAY_KEY_WRITE=1",18); + if (table->row_type != ROW_TYPE_DEFAULT) + { + packet->append(" ROW_FORMAT=",12); + packet->append(ha_row_type[(uint) table->row_type]); + } + table->file->append_create_info(packet); + if (table->comment && table->comment[0]) + { + packet->append(" COMMENT=", 9); + append_unescaped(packet, table->comment, strlen(table->comment)); + } + if (file->raid_type) + { + char buff[100]; + sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld", + my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE); + packet->append(buff); + } } DBUG_RETURN(0); } @@ -1497,6 +1527,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_RPL_STATUS: end= strmov(buff, rpl_status_type[(int)rpl_status]); break; +#ifndef EMBEDDED_LIBRARY case SHOW_SLAVE_RUNNING: { LOCK_ACTIVE_MI; @@ -1505,6 +1536,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, UNLOCK_ACTIVE_MI; break; } +#endif case SHOW_OPENTABLES: end= int10_to_str((long) cached_tables(), buff, 10); break; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 5b84b86c277..646621ac2eb 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -30,6 +30,9 @@ extern gptr sql_alloc(unsigned size); extern void sql_element_free(void *ptr); +static uint32 +copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, + const char *from, uint32 from_length, CHARSET_INFO *from_cs); #include "sql_string.h" @@ -97,7 +100,7 @@ bool String::set(longlong num, CHARSET_INFO *cs) if (alloc(l)) return TRUE; - str_length=(uint32) cs->ll10tostr(cs,Ptr,l,-10,num); + str_length=(uint32) cs->longlong10_to_str(cs,Ptr,l,-10,num); str_charset=cs; return FALSE; } @@ -108,7 +111,7 @@ bool String::set(ulonglong num, CHARSET_INFO *cs) if (alloc(l)) return TRUE; - str_length=(uint32) cs->ll10tostr(cs,Ptr,l,10,num); + str_length=(uint32) cs->longlong10_to_str(cs,Ptr,l,10,num); str_charset=cs; return FALSE; } @@ -223,55 +226,51 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) return FALSE; } -/* Copy with charset convertion */ -bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *from, CHARSET_INFO *to) -{ - uint32 new_length=to->mbmaxlen*arg_length; - int cnvres; - my_wc_t wc; - const uchar *s=(const uchar *)str; - const uchar *se=s+arg_length; - uchar *d, *de; + /* Copy with charset convertion */ +bool String::copy(const char *str, uint32 arg_length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +{ + uint32 new_length= to_cs->mbmaxlen*arg_length; if (alloc(new_length)) return TRUE; - - d=(uchar *)Ptr; - de=d+new_length; - - for (str_length=new_length ; s < se && d < de ; ) - { - if ((cnvres=from->mb_wc(from,&wc,s,se)) > 0 ) - { - s+=cnvres; - } - else if (cnvres==MY_CS_ILSEQ) - { - s++; - wc='?'; - } - else - break; - -outp: - if ((cnvres=to->wc_mb(to,wc,d,de)) >0 ) - { - d+=cnvres; - } - else if (cnvres==MY_CS_ILUNI && wc!='?') - { - wc='?'; - goto outp; - } - else - break; - } - Ptr[new_length]=0; - length((uint32) (d-(uchar *)Ptr)); - str_charset=to; + str_length=copy_and_convert((char*) Ptr, new_length, to_cs, + str, arg_length, from_cs); + str_charset=to_cs; return FALSE; } + +/* + Set a string to the value of a latin1-string, keeping the original charset + + SYNOPSIS + copy_or_set() + str String of a simple charset (latin1) + arg_length Length of string + + IMPLEMENTATION + If string object is of a simple character set, set it to point to the + given string. + If not, make a copy and convert it to the new character set. + + RETURN + 0 ok + 1 Could not allocate result buffer + +*/ + +bool String::set_latin1(const char *str, uint32 arg_length) +{ + if (str_charset->mbmaxlen == 1) + { + set(str, arg_length, str_charset); + return 0; + } + return copy(str, arg_length, my_charset_latin1, str_charset); +} + + /* This is used by mysql.cc */ bool String::fill(uint32 max_length,char fill_char) @@ -306,11 +305,26 @@ bool String::append(const String &s) return FALSE; } + +/* + Append a latin1 string to the a string of the current character set +*/ + + bool String::append(const char *s,uint32 arg_length) { if (!arg_length) // Default argument if (!(arg_length= (uint32) strlen(s))) return FALSE; + if (str_charset->mbmaxlen > 1) + { + uint32 add_length=arg_length * str_charset->mbmaxlen; + if (realloc(str_length+ add_length)) + return TRUE; + str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset, + s, arg_length, my_charset_latin1); + return FALSE; + } if (realloc(str_length+arg_length)) return TRUE; memcpy(Ptr+str_length,s,arg_length); @@ -318,6 +332,7 @@ bool String::append(const char *s,uint32 arg_length) return FALSE; } + #ifdef TO_BE_REMOVED bool String::append(FILE* file, uint32 arg_length, myf my_flags) { @@ -658,4 +673,61 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) } +/**************************************************************************** + Help functions +****************************************************************************/ +/* + copy a string from one character set to another + + SYNOPSIS + copy_and_convert() + to Store result here + to_cs Character set of result string + from Copy from here + from_length Length of from string + from_cs From character set + + NOTES + 'to' must be big enough as form_length * to_cs->mbmaxlen + + RETURN + length of bytes copied to 'to' +*/ + + +static uint32 +copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, + const char *from, uint32 from_length, CHARSET_INFO *from_cs) +{ + int cnvres; + my_wc_t wc; + const uchar *from_end= (const uchar*) from+from_length; + char *to_start= to; + uchar *to_end= (uchar*) to+to_length; + + while ((uchar*) from < from_end) + { + if ((cnvres=from_cs->mb_wc(from_cs, &wc, (uchar*) from, from_end)) > 0) + from+= cnvres; + else if (cnvres == MY_CS_ILSEQ) + { + from++; + wc= '?'; + } + else + break; // Impossible char. + +outp: + if ((cnvres= to_cs->wc_mb(to_cs, wc, (uchar*) to, to_end)) > 0) + to+= cnvres; + else if (cnvres == MY_CS_ILUNI && wc != '?') + { + wc= '?'; + goto outp; + } + else + break; + } + return (uint32) (to - to_start); +} diff --git a/sql/sql_string.h b/sql/sql_string.h index afcc3d74530..ad91b20f18c 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -115,6 +115,7 @@ public: Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0; str_charset=cs; } + bool String::set_latin1(const char *str, uint32 arg_length); inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs) { if (!alloced) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index bf98ab7f7cb..3aae6f6f411 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -233,6 +233,7 @@ int mysql_update(THD *thd, } } end_read_record(&info); + if (table->key_read) { table->key_read=0; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0b94f9307f3..f4ae45373f8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2001 MySQL AB +/* 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 @@ -45,7 +45,7 @@ int yylex(void *yylval, void *yythd); inline Item *or_or_concat(THD *thd, Item* A, Item* B) { - return (thd->sql_mode & MODE_PIPES_AS_CONCAT ? + return (thd->variables.sql_mode & MODE_PIPES_AS_CONCAT ? (Item*) new Item_func_concat(A,B) : (Item*) new Item_cond_or(A,B)); } @@ -222,6 +222,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token FIRST_SYM %token FIXED_SYM %token FLOAT_NUM +%token FORCE_SYM %token FOREIGN %token FROM %token FULL @@ -823,7 +824,8 @@ create: ($2 & HA_LEX_CREATE_TMP_TABLE ? &tmp_table_alias : - (LEX_STRING*) 0),1, + (LEX_STRING*) 0), + TL_OPTION_UPDATING, ((using_update_log)? TL_READ_NO_INSERT: TL_READ))) @@ -844,7 +846,8 @@ create: { LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_INDEX; - if (!lex->current_select->add_table_to_list(lex->thd, $7,NULL,1)) + if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL, + TL_OPTION_UPDATING)) YYABORT; lex->create_list.empty(); lex->key_list.empty(); @@ -1128,7 +1131,7 @@ type: | TIME_SYM { $$=FIELD_TYPE_TIME; } | TIMESTAMP { - if (YYTHD->sql_mode & MODE_SAPDB) + if (YYTHD->variables.sql_mode & MODE_SAPDB) $$=FIELD_TYPE_DATETIME; else $$=FIELD_TYPE_TIMESTAMP; @@ -1199,7 +1202,7 @@ int_type: | BIGINT { $$=FIELD_TYPE_LONGLONG; }; real_type: - REAL { $$= YYTHD->sql_mode & MODE_REAL_AS_FLOAT ? + REAL { $$= YYTHD->variables.sql_mode & MODE_REAL_AS_FLOAT ? FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; } | DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; } | DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; }; @@ -1381,7 +1384,8 @@ opt_unique_or_fulltext: key_alg: /* empty */ { $$= HA_KEY_ALG_UNDEF; } - | USING opt_btree_or_rtree { $$= $2; }; + | USING opt_btree_or_rtree { $$= $2; } + | TYPE_SYM opt_btree_or_rtree { $$= $2; }; opt_btree_or_rtree: BTREE_SYM { $$= HA_KEY_ALG_BTREE; } @@ -1415,7 +1419,8 @@ alter: LEX *lex=&thd->lex; lex->sql_command = SQLCOM_ALTER_TABLE; lex->name=0; - if (!lex->select_lex.add_table_to_list(thd, $4, NULL,1)) + if (!lex->select_lex.add_table_to_list(thd, $4, NULL, + TL_OPTION_UPDATING)) YYABORT; lex->drop_primary=0; lex->create_list.empty(); @@ -1681,8 +1686,10 @@ table_to_table: { LEX *lex=Lex; SELECT_LEX_NODE *sl= lex->current_select; - if (!sl->add_table_to_list(lex->thd, $1,NULL,1,TL_IGNORE) || - !sl->add_table_to_list(lex->thd, $3,NULL,1,TL_IGNORE)) + if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING, + TL_IGNORE) || + !sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING, + TL_IGNORE)) YYABORT; }; @@ -2534,12 +2541,14 @@ join_table: { SELECT_LEX *sel= Select->select_lex(); sel->use_index_ptr=sel->ignore_index_ptr=0; + sel->table_join_options= 0; } table_ident opt_table_alias opt_key_definition { LEX *lex= Lex; SELECT_LEX_NODE *sel= lex->current_select; - if (!($$= sel->add_table_to_list(lex->thd, $2, $3, 0, + if (!($$= sel->add_table_to_list(lex->thd, $2, $3, + sel->get_table_join_options(), lex->lock_option, sel->get_use_index(), sel->get_ignore_index()))) @@ -2585,6 +2594,13 @@ opt_key_definition: sel->use_index= *$2; sel->use_index_ptr= &sel->use_index; } + | FORCE_SYM key_usage_list + { + SELECT_LEX *sel= Select->select_lex(); + sel->use_index= *$2; + sel->use_index_ptr= &sel->use_index; + sel->table_join_options|= TL_OPTION_FORCE_INDEX; + } | IGNORE_SYM key_usage_list { SELECT_LEX *sel= Select->select_lex(); @@ -2594,8 +2610,14 @@ opt_key_definition: key_usage_list: key_or_index { Select->select_lex()->interval_list.empty(); } - '(' key_usage_list2 ')' - { $$= &Select->select_lex()->interval_list; }; + '(' key_list_or_empty ')' + { $$= &Select->select_lex()->interval_list; } + ; + +key_list_or_empty: + /* empty */ {} + | key_usage_list2 {} + ; key_usage_list2: key_usage_list2 ',' ident @@ -2956,7 +2978,8 @@ drop: lex->drop_list.empty(); lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, $3.str)); - if (!lex->current_select->add_table_to_list(lex->thd, $5,NULL, 1)) + if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL, + TL_OPTION_UPDATING)) YYABORT; } | DROP DATABASE if_exists ident @@ -2980,7 +3003,11 @@ table_list: table_name: table_ident - { if (!Select->add_table_to_list(YYTHD, $1, NULL, 1)) YYABORT; }; + { + if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING)) + YYABORT; + } + ; if_exists: /* empty */ { $$= 0; } @@ -3215,7 +3242,8 @@ delete: single_multi: FROM table_ident { - if (!Select->add_table_to_list(YYTHD, $2, NULL, 1, Lex->lock_option)) + if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING, + Lex->lock_option)) YYABORT; } where_clause opt_order_clause @@ -3236,14 +3264,15 @@ table_wild_list: table_wild_one: ident opt_wild opt_table_alias { - if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3, 1, - Lex->lock_option)) + if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3, + TL_OPTION_UPDATING, Lex->lock_option)) YYABORT; } | ident '.' ident opt_wild opt_table_alias { if (!Select->add_table_to_list(YYTHD, new Table_ident($1, $3, 0), - $5, 1, Lex->lock_option)) + $5, TL_OPTION_UPDATING, + Lex->lock_option)) YYABORT; } ; @@ -3407,7 +3436,7 @@ show_param: | CREATE TABLE_SYM table_ident { Lex->sql_command = SQLCOM_SHOW_CREATE; - if(!Select->add_table_to_list(YYTHD, $3, NULL,0)) + if (!Select->add_table_to_list(YYTHD, $3, NULL,0)) YYABORT; } | MASTER_SYM STATUS_SYM @@ -3576,14 +3605,14 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term opt_ignore_lines opt_field_spec { - if (!Select->add_table_to_list(YYTHD, $11, NULL, 1)) + if (!Select->add_table_to_list(YYTHD, $11, NULL, TL_OPTION_UPDATING)) YYABORT; } | LOAD TABLE_SYM table_ident FROM MASTER_SYM { Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE; - if (!Select->add_table_to_list(YYTHD, $3, NULL, 1)) + if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING)) YYABORT; } @@ -3713,17 +3742,41 @@ simple_ident: } | ident '.' ident { - SELECT_LEX_NODE *sel=Select; + THD *thd= YYTHD; + LEX *lex= &thd->lex; + SELECT_LEX_NODE *sel= lex->current_select; + if (sel->no_table_names_allowed) + { + my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, + ER(ER_TABLENAME_NOT_ALLOWED_HERE), + MYF(0), $1.str, thd->where); + } $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str); } | '.' ident '.' ident { - SELECT_LEX_NODE *sel=Select; + THD *thd= YYTHD; + LEX *lex= &thd->lex; + SELECT_LEX_NODE *sel= lex->current_select; + if (sel->no_table_names_allowed) + { + my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, + ER(ER_TABLENAME_NOT_ALLOWED_HERE), + MYF(0), $2.str, thd->where); + } $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str); } | ident '.' ident '.' ident { - SELECT_LEX_NODE *sel=Select; + THD *thd= YYTHD; + LEX *lex= &thd->lex; + SELECT_LEX_NODE *sel= lex->current_select; + if (sel->no_table_names_allowed) + { + my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, + ER(ER_TABLENAME_NOT_ALLOWED_HERE), + MYF(0), $3.str, thd->where); + } $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); }; @@ -4508,7 +4561,8 @@ optional_order_or_limit: /* Empty */ {} | { - LEX *lex=Lex; + THD *thd= YYTHD; + LEX *lex= &thd->lex; if (!lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { send_error(lex->thd, ER_SYNTAX_ERROR); @@ -4520,8 +4574,15 @@ optional_order_or_limit: lex->current_select= sel->master_unit(); lex->current_select->select_limit= lex->thd->variables.select_limit; + lex->current_select->no_table_names_allowed= 1; + thd->where= "global ORDER clause"; } order_or_limit + { + THD *thd= YYTHD; + thd->lex.current_select->no_table_names_allowed= 0; + thd->where= ""; + } ; order_or_limit: diff --git a/sql/table.h b/sql/table.h index d24e4e1e422..6291b250787 100644 --- a/sql/table.h +++ b/sql/table.h @@ -91,6 +91,7 @@ struct st_table { my_bool copy_blobs; /* copy_blobs when storing */ my_bool null_row; /* All columns are null */ my_bool maybe_null,outer_join; /* Used with OUTER JOIN */ + my_bool force_index; my_bool distinct,const_table,no_rows; my_bool key_read, bulk_insert; my_bool crypted; @@ -168,6 +169,7 @@ typedef struct st_table_list bool straight; /* optimize with prev table */ bool updating; /* for replicate-do/ignore table */ bool do_redirect; /* To get the struct in UNION's */ + bool force_index; /* Prefer index over table scan */ } TABLE_LIST; typedef struct st_changed_table_list diff --git a/strings/Makefile.am b/strings/Makefile.am index ac0b6d7f1e0..dea9effdfeb 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -22,19 +22,19 @@ pkglib_LIBRARIES = libmystrings.a # Exact one of ASSEMBLER_X if ASSEMBLER_x86 ASRCS = strings-x86.s longlong2str-x86.s -CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-latin1_de.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-win1250ch.c ctype-bin.c +CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-latin1_de.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-win1250ch.c ctype-bin.c my_vsnprintf.c xml.c else if ASSEMBLER_sparc32 # These file MUST all be on the same line!! Otherwise automake # generats a very broken makefile ASRCS = bmove_upp-sparc.s strappend-sparc.s strend-sparc.s strinstr-sparc.s strmake-sparc.s strmov-sparc.s strnmov-sparc.s strstr-sparc.s -CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-latin1_de.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-win1250ch.c ctype-bin.c +CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-latin1_de.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-win1250ch.c ctype-bin.c my_vsnprintf.c xml.c else #no assembler ASRCS = # These file MUST all be on the same line!! Otherwise automake # generats a very broken makefile -CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-latin1_de.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-win1250ch.c ctype-bin.c +CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-latin1_de.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-win1250ch.c ctype-bin.c my_vsnprintf.c xml.c endif endif @@ -44,7 +44,7 @@ noinst_PROGRAMS = conf_to_src EXTRA_DIST = ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-win1250ch.c \ ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \ ctype-tis620.c ctype-ujis.c ctype-latin1_de.c \ - strto.c strings-x86.s \ + xml.c strto.c strings-x86.s \ longlong2str.c longlong2str-x86.s \ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \ strfill.c strcend.c is_prefix.c strstr.c strinstr.c \ diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 408c7f8fe35..a475a36d049 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -6218,7 +6218,7 @@ my_mb_wc_big5(CHARSET_INFO *cs __attribute__((unused)), CHARSET_INFO my_charset_big5 = { 1, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY, /* state */ + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */ "big5", /* cs name */ "big5", /* name */ "", /* comment */ @@ -6250,14 +6250,15 @@ CHARSET_INFO my_charset_big5 = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 0d7729721ad..7d174d510e2 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -47,8 +47,8 @@ static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)), const uchar *s, uint slen, const uchar *t, uint tlen) { - int len = ( slen > tlen ) ? tlen : slen; - return memcmp(s,t,len); + int cmp= memcmp(s,t,min(slen,tlen)); + return cmp ? cmp : (int) (slen - tlen); } static void my_caseup_str_bin(CHARSET_INFO *cs __attribute__((unused)), @@ -254,7 +254,14 @@ static int my_wildcmp_bin(CHARSET_INFO *cs, return(str != str_end ? 1 : 0); } - +static int my_strnxfrm_bin(CHARSET_INFO *cs __attribute__((unused)), + uchar * dest, uint len, + const uchar *src, + uint srclen __attribute__((unused))) +{ + memcpy(dest,src,len= min(len,srclen)); + return len; +} static CHARSET_INFO my_charset_bin_st = { @@ -271,7 +278,7 @@ static CHARSET_INFO my_charset_bin_st = NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_binary, /* strnncoll */ - NULL, /* strxnfrm */ + my_strnxfrm_bin, /* strxnfrm */ my_like_range_simple, /* like_range */ my_wildcmp_bin, /* wildcmp */ 1, /* mbmaxlen */ @@ -291,13 +298,14 @@ static CHARSET_INFO my_charset_bin_st = my_hash_sort_bin, /* hash_sort */ 255, /* max_sort_char */ my_snprintf_8bit, /* snprintf */ - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, my_strntod_8bit, + my_scan_8bit }; diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c index bb0afe98032..6397d3d902e 100644 --- a/strings/ctype-czech.c +++ b/strings/ctype-czech.c @@ -596,7 +596,7 @@ static MY_UNI_IDX idx_uni_8859_2[]={ CHARSET_INFO my_charset_czech = { 2, /* number */ - MY_CS_COMPILED, /* state */ + MY_CS_COMPILED|MY_CS_STRNXFRM, /* state */ "latin2", /* cs name */ "czech", /* name */ "", /* comment */ @@ -628,13 +628,14 @@ CHARSET_INFO my_charset_czech = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; #endif diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index 814f43166c4..ee75673e1c5 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8648,7 +8648,7 @@ CHARSET_INFO my_charset_euc_kr = NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ 2, /* mbmaxlen */ @@ -8668,13 +8668,14 @@ CHARSET_INFO my_charset_euc_kr = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; #endif diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index d575e48a59a..0820d03b2d0 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5698,7 +5698,7 @@ CHARSET_INFO my_charset_gb2312 = NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ 2, /* mbmaxlen */ @@ -5718,13 +5718,14 @@ CHARSET_INFO my_charset_gb2312 = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; #endif diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 0094a93e5f8..3aff098cd14 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -9873,7 +9873,7 @@ my_mb_wc_gbk(CHARSET_INFO *cs __attribute__((unused)), CHARSET_INFO my_charset_gbk = { 28, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY, /* state */ + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */ "gbk", /* cs name */ "gbk", /* name */ "", /* comment */ @@ -9905,13 +9905,14 @@ CHARSET_INFO my_charset_gbk = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, my_strntod_8bit, + my_scan_8bit }; diff --git a/strings/ctype-latin1_de.c b/strings/ctype-latin1_de.c index 166e059ef42..6a5a9b78e8d 100644 --- a/strings/ctype-latin1_de.c +++ b/strings/ctype-latin1_de.c @@ -414,7 +414,7 @@ static my_bool my_like_range_latin1_de(CHARSET_INFO *cs __attribute__((unused)), CHARSET_INFO my_charset_latin1_de = { 31, /* number */ - MY_CS_COMPILED, /* state */ + MY_CS_COMPILED|MY_CS_STRNXFRM, /* state */ "latin1", /* cs name */ "latin1_de", /* name */ "", /* comment */ @@ -446,13 +446,14 @@ CHARSET_INFO my_charset_latin1_de = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; #endif diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 49801478504..99d03e187b1 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -17,7 +17,6 @@ #include #include "m_string.h" #include "m_ctype.h" -#include "my_sys.h" /* defines errno */ #include #include "stdarg.h" @@ -29,11 +28,13 @@ int my_strnxfrm_simple(CHARSET_INFO * cs, const uchar *src, uint srclen) { uchar *map= cs->sort_order; + const uchar *end; DBUG_ASSERT(len >= srclen); - for ( ; len > 0 ; len-- ) + len= min(len,srclen); + for ( end=src+len; src < end ; ) *dest++= map[*src++]; - return srclen; + return len; } int my_strnncoll_simple(CHARSET_INFO * cs, const uchar *s, uint slen, @@ -110,88 +111,40 @@ int my_mb_wc_8bit(CHARSET_INFO *cs,my_wc_t *wc, } int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, - unsigned char *s, - unsigned char *e __attribute__((unused))) + unsigned char *str, + unsigned char *end __attribute__((unused))) { MY_UNI_IDX *idx; - for(idx=cs->tab_from_uni; idx->tab ; idx++){ - if(idx->from<=wc && idx->to>=wc){ - s[0]=idx->tab[wc-idx->from]; - return (!s[0] && wc) ? MY_CS_ILUNI : 1; + for (idx=cs->tab_from_uni; idx->tab ; idx++) + { + if (idx->from <= wc && idx->to >= wc) + { + str[0]= idx->tab[wc - idx->from]; + return (!str[0] && wc) ? MY_CS_ILUNI : 1; } } return MY_CS_ILUNI; } -#ifdef NOT_USED -static int my_vsnprintf_8bit(char *to, size_t n, const char* fmt, va_list ap) -{ - char *start=to, *end=to+n-1; - for (; *fmt ; fmt++) - { - if (fmt[0] != '%') - { - if (to == end) /* End of buffer */ - break; - *to++= *fmt; /* Copy ordinary char */ - continue; - } - /* Skip if max size is used (to be compatible with printf) */ - fmt++; - while (my_isdigit(system_charset_info,*fmt) || *fmt == '.' || *fmt == '-') - fmt++; - if (*fmt == 'l') - fmt++; - if (*fmt == 's') /* String parameter */ - { - reg2 char *par = va_arg(ap, char *); - uint plen,left_len = (uint)(end-to); - if (!par) par = (char*)"(null)"; - plen = (uint) strlen(par); - if (left_len <= plen) - plen = left_len - 1; - to=strnmov(to,par,plen); - continue; - } - else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */ - { - register int iarg; - if ((uint) (end-to) < 16) - break; - iarg = va_arg(ap, int); - if (*fmt == 'd') - to=int10_to_str((long) iarg,to, -10); - else - to=int10_to_str((long) (uint) iarg,to,10); - continue; - } - /* We come here on '%%', unknown code or too long parameter */ - if (to == end) - break; - *to++='%'; /* % used as % or unknown code */ - } - DBUG_ASSERT(to <= end); - *to='\0'; /* End of errmessage */ - return (uint) (to - start); -} -#endif +/* + We can't use vsprintf here as it's not guaranteed to return + the length on all operating systems. + This function is also not called in a safe environment, so the + end buffer must be checked. +*/ int my_snprintf_8bit(CHARSET_INFO *cs __attribute__((unused)), char* to, uint n __attribute__((unused)), const char* fmt, ...) { va_list args; + int result; va_start(args,fmt); -#ifdef NOT_USED - return my_vsnprintf_8bit(to, n, fmt, args); -#endif - /* - FIXME: generally not safe, but it is OK for now - FIXME: as far as it's not called unsafely in the current code - */ - return vsprintf(to,fmt,args); /* FIXME */ + result= my_vsnprintf(to, n, fmt, args); + va_end(args); + return result; } @@ -249,7 +202,8 @@ void my_hash_sort_simple(CHARSET_INFO *cs, long my_strntol_8bit(CHARSET_INFO *cs, - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr, int *err) { int negative; register ulong cutoff; @@ -259,10 +213,13 @@ long my_strntol_8bit(CHARSET_INFO *cs, register unsigned char c; const char *save, *e; int overflow; - + + *err= 0; /* Initialize error indicator */ +#ifdef NOT_USED if (base < 0 || base == 1 || base > 36) base = 10; - +#endif + s = nptr; e = nptr+l; @@ -287,9 +244,12 @@ long my_strntol_8bit(CHARSET_INFO *cs, else negative = 0; +#ifdef NOT_USED if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x')) s += 2; +#endif +#ifdef NOT_USED if (base == 0) { if (*s == '0') @@ -305,6 +265,7 @@ long my_strntol_8bit(CHARSET_INFO *cs, else base = 10; } +#endif save = s; cutoff = ((ulong)~0L) / (unsigned long int) base; @@ -349,14 +310,14 @@ long my_strntol_8bit(CHARSET_INFO *cs, if (overflow) { - my_errno=(ERANGE); + err[0]= ERANGE; return negative ? LONG_MIN : LONG_MAX; } return (negative ? -((long) i) : (long) i); noconv: - my_errno=(EDOM); + err[0]= EDOM; if (endptr != NULL) *endptr = (char *) nptr; return 0L; @@ -364,7 +325,8 @@ noconv: ulong my_strntoul_8bit(CHARSET_INFO *cs, - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr, int *err) { int negative; register ulong cutoff; @@ -375,9 +337,12 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, const char *save, *e; int overflow; + *err= 0; /* Initialize error indicator */ +#ifdef NOT_USED if (base < 0 || base == 1 || base > 36) base = 10; - +#endif + s = nptr; e = nptr+l; @@ -401,9 +366,12 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, else negative = 0; +#ifdef NOT_USED if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x')) s += 2; +#endif +#ifdef NOT_USED if (base == 0) { if (*s == '0') @@ -419,6 +387,7 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, else base = 10; } +#endif save = s; cutoff = ((ulong)~0L) / (unsigned long int) base; @@ -455,14 +424,14 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, if (overflow) { - my_errno=(ERANGE); + err[0]= ERANGE; return ((ulong)~0L); } return (negative ? -((long) i) : (long) i); noconv: - my_errno=(EDOM); + err[0]= EDOM; if (endptr != NULL) *endptr = (char *) nptr; return 0L; @@ -470,7 +439,8 @@ noconv: longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr,int *err) { int negative; register ulonglong cutoff; @@ -481,8 +451,11 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), const char *save; int overflow; + *err= 0; /* Initialize error indicator */ +#ifdef NOT_USED if (base < 0 || base == 1 || base > 36) base = 10; +#endif s = nptr; e = nptr+l; @@ -507,9 +480,12 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), else negative = 0; +#ifdef NOT_USED if (base == 16 && s[0] == '0' && (s[1]=='X'|| s[1]=='x')) s += 2; +#endif +#ifdef NOT_USED if (base == 0) { if (*s == '0') @@ -525,6 +501,7 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), else base = 10; } +#endif save = s; @@ -570,14 +547,14 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), if (overflow) { - my_errno=(ERANGE); + err[0]= ERANGE; return negative ? LONGLONG_MIN : LONGLONG_MAX; } return (negative ? -((longlong) i) : (longlong) i); noconv: - my_errno=(EDOM); + err[0]= EDOM; if (endptr != NULL) *endptr = (char *) nptr; return 0L; @@ -585,7 +562,8 @@ noconv: ulonglong my_strntoull_8bit(CHARSET_INFO *cs, - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr, int *err) { int negative; register ulonglong cutoff; @@ -596,8 +574,11 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, const char *save; int overflow; + *err= 0; /* Initialize error indicator */ +#ifdef NOT_USED if (base < 0 || base == 1 || base > 36) base = 10; +#endif s = nptr; e = nptr+l; @@ -622,9 +603,12 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, else negative = 0; +#ifdef NOT_USED if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x')) s += 2; +#endif +#ifdef NOT_USED if (base == 0) { if (*s == '0') @@ -640,6 +624,7 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, else base = 10; } +#endif save = s; @@ -677,61 +662,89 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, if (overflow) { - my_errno=(ERANGE); + err[0]= ERANGE; return (~(ulonglong) 0); } return (negative ? -((longlong) i) : (longlong) i); noconv: - my_errno=(EDOM); + err[0]= EDOM; if (endptr != NULL) *endptr = (char *) nptr; return 0L; } -double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), - const char *s, uint l, char **e) +/* + Read double from string + + SYNOPSIS: + my_strntod_8bit() + cs Character set information + str String to convert to double + length Optional length for string. + end result pointer to end of converted string + err Error number if failed conversion + + NOTES: + If length is not INT_MAX32 or str[length] != 0 then the given str must + be writeable + If length == INT_MAX32 the str must be \0 terminated. + + It's implemented this way to save a buffer allocation and a memory copy. + + RETURN + Value of number in string +*/ + + +double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), + char *str, uint length, + char **end, int *err) { - char buf[256]; - double res; - if((l+1)>sizeof(buf)) + char end_char; + double result; + + errno= 0; /* Safety */ + if (length == INT_MAX32 || str[length] == 0) + result= strtod(str, end); + else { - if (e) - memcpy(*e,s,sizeof(s)); - return 0; + end_char= str[length]; + str[length]= 0; + result= strtod(str, end); + str[length]= end_char; /* Restore end char */ } - strncpy(buf,s,l); - buf[l]='\0'; - res=strtod(buf,e); - if (e) - memcpy(*e,*e-buf+s,sizeof(s)); - return res; + *err= errno; + return result; } /* This is a fast version optimized for the case of radix 10 / -10 + + Assume len >= 1 */ -int my_l10tostr_8bit(CHARSET_INFO *cs __attribute__((unused)), +int my_long10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), char *dst, uint len, int radix, long int val) { char buffer[66]; register char *p, *e; long int new_val; - int sl=0; - uint l; - + uint sign=0; + e = p = &buffer[sizeof(buffer)-1]; - *e='\0'; + *p= 0; if (radix < 0) { if (val < 0) { - sl = 1; - val = -val; + val= -val; + *dst++= '-'; + len--; + sign= 1; } } @@ -746,41 +759,38 @@ int my_l10tostr_8bit(CHARSET_INFO *cs __attribute__((unused)), val= new_val; } - if (sl) - { - *--p='-'; - } - - l=e-p; - l=(l>len)?len:l; - memcpy(dst,p,l); - return (int)l; + len= min(len, (uint) (e-p)); + memcpy(dst, p, len); + return (int) len+sign; } -int my_ll10tostr_8bit(CHARSET_INFO *cs __attribute__((unused)), + +int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), char *dst, uint len, int radix, longlong val) { char buffer[65]; register char *p, *e; long long_val; - int sl=0; - uint l; + uint sign= 0; if (radix < 0) { if (val < 0) { - sl=1; val = -val; + *dst++= '-'; + len--; + sign= 1; } } e = p = &buffer[sizeof(buffer)-1]; - *p='\0'; + *p= 0; if (val == 0) { - *--p='0'; + *--p= '0'; + len= 1; goto cnv; } @@ -800,16 +810,10 @@ int my_ll10tostr_8bit(CHARSET_INFO *cs __attribute__((unused)), long_val= quo; } + len= min(len, (uint) (e-p)); cnv: - if (sl) - { - *--p='-'; - } - - l=e-p; - l=(l>len)?len:l; - memcpy(dst,p,l); - return (int)(e-p); + memcpy(dst, p, len); + return len+sign; } @@ -974,3 +978,29 @@ my_bool my_like_range_simple(CHARSET_INFO *cs, *min_str++ = *max_str++ = ' '; // Because if key compression return 0; } + + +ulong my_scan_8bit(CHARSET_INFO *cs, const char *str, const char *end, int sq) +{ + const char *str0= str; + switch (sq) + { + case MY_SEQ_INTTAIL: + if (*str == '.') + { + for(str++ ; str != end && *str == '0' ; str++); + return str-str0; + } + return 0; + + case MY_SEQ_SPACES: + for (str++ ; str != end ; str++) + { + if (!my_isspace(cs,*str)) + break; + } + return str-str0; + default: + return 0; + } +} diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 3949be5e215..b19bcf1a45a 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4460,7 +4460,7 @@ my_mb_wc_sjis(CHARSET_INFO *cs __attribute__((unused)), CHARSET_INFO my_charset_sjis = { 13, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY, /* state */ + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */ "sjis", /* cs name */ "sjis", /* name */ "", /* comment */ @@ -4492,13 +4492,14 @@ CHARSET_INFO my_charset_sjis = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; #endif diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 7168026eea5..ac959105736 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -688,7 +688,7 @@ void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length) CHARSET_INFO my_charset_tis620 = { 18, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY, /* state */ + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */ "tis620", /* cs name */ "tis620", /* name */ "", /* comment */ @@ -720,13 +720,14 @@ CHARSET_INFO my_charset_tis620 = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index 0a0024594e4..12e177a89be 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -8442,7 +8442,7 @@ CHARSET_INFO my_charset_ujis = NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ NULL, /* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_mb, /* wildcmp */ 3, /* mbmaxlen */ @@ -8462,13 +8462,14 @@ CHARSET_INFO my_charset_ujis = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 42a70731ab5..435121c1056 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -21,9 +21,12 @@ #include #include "m_string.h" #include "m_ctype.h" -#include "my_sys.h" /* defines errno */ #include +#ifndef EILSEQ +#define EILSEQ ENOENT +#endif + #ifdef HAVE_CHARSET_utf8 #define HAVE_UNIDATA #endif @@ -1958,7 +1961,7 @@ static int my_mbcharlen_utf8(CHARSET_INFO *cs __attribute__((unused)) , uint c) CHARSET_INFO my_charset_utf8 = { 33, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY, /* state */ + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */ "utf8", /* cs name */ "utf8", /* name */ "", /* comment */ @@ -1990,13 +1993,14 @@ CHARSET_INFO my_charset_utf8 = my_hash_sort_utf8, /* hash_sort */ 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, my_strntod_8bit, + my_scan_8bit }; @@ -2446,7 +2450,8 @@ static int my_snprintf_ucs2(CHARSET_INFO *cs __attribute__((unused)) long my_strntol_ucs2(CHARSET_INFO *cs, - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr, int *err) { int negative=0; int overflow; @@ -2459,7 +2464,9 @@ long my_strntol_ucs2(CHARSET_INFO *cs, register const char *e=nptr+l; const char *save; - do { + *err= 0; + do + { if ((cnv=cs->mb_wc(cs,&wc,s,e))>0) { switch (wc) @@ -2475,16 +2482,18 @@ long my_strntol_ucs2(CHARSET_INFO *cs, { if (endptr !=NULL ) *endptr = (char*)s; - my_errno = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; + err[0] = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; return 0; } s+=cnv; } while (1); bs: - + +#if 0 if (base <= 0 || base == 1 || base > 36) base = 10; +#endif overflow = 0; res = 0; @@ -2518,7 +2527,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]=EILSEQ; return 0; } else @@ -2533,7 +2542,7 @@ bs: if (s == save) { - my_errno=EDOM; + err[0]=EDOM; return 0L; } @@ -2547,7 +2556,7 @@ bs: if (overflow) { - my_errno=(ERANGE); + err[0]=ERANGE; return negative ? LONG_MIN : LONG_MAX; } @@ -2556,7 +2565,8 @@ bs: ulong my_strntoul_ucs2(CHARSET_INFO *cs, - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr, int *err) { int negative=0; int overflow; @@ -2569,7 +2579,9 @@ ulong my_strntoul_ucs2(CHARSET_INFO *cs, register const char *e=nptr+l; const char *save; - do { + *err= 0; + do + { if ((cnv=cs->mb_wc(cs,&wc,s,e))>0) { switch (wc) @@ -2585,17 +2597,19 @@ ulong my_strntoul_ucs2(CHARSET_INFO *cs, { if (endptr !=NULL ) *endptr = (char*)s; - my_errno = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; + err[0] = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; return 0; } s+=cnv; } while (1); bs: - + +#if 0 if (base <= 0 || base == 1 || base > 36) base = 10; - +#endif + overflow = 0; res = 0; save = s; @@ -2628,7 +2642,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]=EILSEQ; return 0; } else @@ -2643,13 +2657,13 @@ bs: if (s == save) { - my_errno=EDOM; + err[0]=EDOM; return 0L; } if (overflow) { - my_errno=(ERANGE); + err[0]=(ERANGE); return ((ulong)~0L); } @@ -2660,7 +2674,8 @@ bs: longlong my_strntoll_ucs2(CHARSET_INFO *cs, - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr, int *err) { int negative=0; int overflow; @@ -2673,7 +2688,9 @@ longlong my_strntoll_ucs2(CHARSET_INFO *cs, register const char *e=nptr+l; const char *save; - do { + *err= 0; + do + { if ((cnv=cs->mb_wc(cs,&wc,s,e))>0) { switch (wc) @@ -2689,17 +2706,19 @@ longlong my_strntoll_ucs2(CHARSET_INFO *cs, { if (endptr !=NULL ) *endptr = (char*)s; - my_errno = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; + err[0] = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; return 0; } s+=cnv; } while (1); bs: - + +#if 0 if (base <= 0 || base == 1 || base > 36) base = 10; - +#endif + overflow = 0; res = 0; save = s; @@ -2732,7 +2751,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]=EILSEQ; return 0; } else @@ -2747,7 +2766,7 @@ bs: if (s == save) { - my_errno=EDOM; + err[0]=EDOM; return 0L; } @@ -2761,7 +2780,7 @@ bs: if (overflow) { - my_errno=(ERANGE); + err[0]=ERANGE; return negative ? LONGLONG_MIN : LONGLONG_MAX; } @@ -2772,7 +2791,8 @@ bs: ulonglong my_strntoull_ucs2(CHARSET_INFO *cs, - const char *nptr, uint l, char **endptr, int base) + const char *nptr, uint l, int base, + char **endptr, int *err) { int negative=0; int overflow; @@ -2785,7 +2805,9 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs, register const char *e=nptr+l; const char *save; - do { + *err= 0; + do + { if ((cnv=cs->mb_wc(cs,&wc,s,e))>0) { switch (wc) @@ -2801,7 +2823,7 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs, { if (endptr !=NULL ) *endptr = (char*)s; - my_errno = (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; + err[0]= (cnv==MY_CS_ILSEQ) ? EILSEQ : EDOM; return 0; } s+=cnv; @@ -2809,16 +2831,19 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs, bs: +#if 0 if (base <= 0 || base == 1 || base > 36) base = 10; - +#endif + overflow = 0; res = 0; save = s; cutoff = (~(ulonglong) 0) / (unsigned long int) base; cutlim = (uint) ((~(ulonglong) 0) % (unsigned long int) base); - do { + do + { if ((cnv=cs->mb_wc(cs,&wc,s,e))>0) { s+=cnv; @@ -2844,7 +2869,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]= EILSEQ; return 0; } else @@ -2859,13 +2884,13 @@ bs: if (s == save) { - my_errno=EDOM; + err[0]= EDOM; return 0L; } if (overflow) { - my_errno=(ERANGE); + err[0]= ERANGE; return (~(ulonglong) 0); } @@ -2874,37 +2899,35 @@ bs: double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), - const char *nptr, uint l, char **endptr) + char *nptr, uint length, + char **endptr, int *err) { char buf[256]; double res; register char *b=buf; register const char *s=nptr; - register const char *e=nptr+l; + register const char *end; my_wc_t wc; int cnv; - - if((l+1)>sizeof(buf)) - { - if (endptr) - *endptr=(char*)nptr; - my_errno=ERANGE; - return 0; - } - - while ((cnv=cs->mb_wc(cs,&wc,s,e))>0) + + *err= 0; + /* Cut too long strings */ + if (length >= sizeof(buf)) + length= sizeof(buf)-1; + end=nptr+length; + + while ((cnv=cs->mb_wc(cs,&wc,s,end)) > 0) { s+=cnv; - if (wc < 128) - { - *b++=wc; - } - else - break; + if (wc > (int) (uchar) 'e' || !wc) + break; /* Can't be part of double */ + *b++=wc; } - *b='\0'; + *b= 0; - res=strtod(buf,endptr); + errno= 0; + res=strtod(buf, endptr); + *err= errno; if (endptr) *endptr=(char*) (*endptr-buf+nptr); return res; @@ -3025,7 +3048,7 @@ cnv: CHARSET_INFO my_charset_ucs2 = { 35, /* number */ - MY_CS_COMPILED|MY_CS_PRIMARY, /* state */ + MY_CS_COMPILED|MY_CS_PRIMARY|MY_CS_STRNXFRM, /* state */ "ucs2", /* cs name */ "ucs2", /* name */ "", /* comment */ @@ -3063,7 +3086,8 @@ CHARSET_INFO my_charset_ucs2 = my_strntoul_ucs2, my_strntoll_ucs2, my_strntoull_ucs2, - my_strntod_ucs2 + my_strntod_ucs2, + my_scan_8bit }; diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index 358cede442c..86ddb82e1a2 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -622,7 +622,7 @@ static my_bool my_like_range_win1250ch(CHARSET_INFO *cs __attribute__((unused)), CHARSET_INFO my_charset_win1250ch = { 34, /* number */ - MY_CS_COMPILED, /* state */ + MY_CS_COMPILED|MY_CS_STRNXFRM, /* state */ "cp1250", /* cs name */ "cp1250_czech", /* name */ "", /* comment */ @@ -654,13 +654,14 @@ CHARSET_INFO my_charset_win1250ch = my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }; diff --git a/strings/ctype.c b/strings/ctype.c index 61fb57d9ac3..0873429f9ab 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -16,6 +16,7 @@ #include #include +#include #ifndef SCO #include #endif @@ -2822,7 +2823,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_8859_1, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -2842,13 +2843,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -2868,7 +2870,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_cp1251, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -2888,13 +2890,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -2913,7 +2916,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_cp1257, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -2933,13 +2936,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -2958,7 +2962,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_8859_2, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -2978,13 +2982,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3004,7 +3009,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_8859_1, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3024,13 +3029,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3049,7 +3055,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3069,13 +3075,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3094,7 +3101,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3114,13 +3121,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3139,7 +3147,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3159,13 +3167,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3185,7 +3194,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_8859_1, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3205,13 +3214,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3230,7 +3240,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3250,13 +3260,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3275,7 +3286,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3295,13 +3306,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3320,7 +3332,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3340,13 +3352,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3365,7 +3378,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_8859_2, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3385,13 +3398,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3410,7 +3424,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_koi8_r, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3430,13 +3444,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3455,7 +3470,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_koi8_u, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3475,13 +3490,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3501,7 +3517,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_8859_2, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3521,13 +3537,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3546,7 +3563,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_8859_9, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3566,13 +3583,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3592,7 +3610,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3612,13 +3630,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3638,7 +3657,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_us_ascii, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3658,13 +3677,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3683,7 +3703,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_cp1250, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3703,13 +3723,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3728,7 +3749,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_cp1251, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3748,13 +3769,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3773,7 +3795,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_armscii_8, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3793,13 +3815,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3818,7 +3841,7 @@ static CHARSET_INFO compiled_charsets[] = { idx_uni_cp1251, /* tab_from_uni */ 0, /* strxfrm_multiply */ my_strnncoll_simple,/* strnncoll */ - NULL, /* strnxfrm */ + my_strnxfrm_simple, /* strnxfrm */ my_like_range_simple,/* like_range */ my_wildcmp_8bit, /* wildcmp */ 1, /* mbmaxlen */ @@ -3838,13 +3861,14 @@ static CHARSET_INFO compiled_charsets[] = { my_hash_sort_simple, 0, my_snprintf_8bit, - my_l10tostr_8bit, - my_ll10tostr_8bit, + my_long10_to_str_8bit, + my_longlong10_to_str_8bit, my_strntol_8bit, my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3890,11 +3914,238 @@ static CHARSET_INFO compiled_charsets[] = { NULL, NULL, NULL, + NULL, NULL } }; +static char *mstr(char *str,const char *src,uint l1,uint l2) +{ + l1= l1str; s++) + { + if (!strncmp(attr,s->str,len)) + return s; + } + return NULL; +} + +typedef struct my_cs_file_info +{ + char csname[MY_CS_NAME_SIZE]; + char name[MY_CS_NAME_SIZE]; + uchar ctype[MY_CS_CTYPE_TABLE_SIZE]; + uchar to_lower[MY_CS_TO_LOWER_TABLE_SIZE]; + uchar to_upper[MY_CS_TO_UPPER_TABLE_SIZE]; + uchar sort_order[MY_CS_SORT_ORDER_TABLE_SIZE]; + uint16 tab_to_uni[MY_CS_TO_UNI_TABLE_SIZE]; + CHARSET_INFO cs; + int (*add_collation)(CHARSET_INFO *cs); +} MY_CHARSET_LOADER; + + + +static int fill_uchar(uchar *a,uint size,const char *str, uint len) +{ + int err=0; + uint i= 0; + const char *s, *b, *e=str+len; + + for (s=str ; s < e ; i++) + { + for ( ; (s < e) && strchr(" \t\r\n",s[0]); s++) ; + b=s; + for ( ; (s < e) && !strchr(" \t\r\n",s[0]); s++) ; + if (s == b || i > size) + break; + a[i]= my_strntoul(my_charset_latin1,b,s-b,16,NULL,&err); + } + return 0; +} + +static int fill_uint16(uint16 *a,uint size,const char *str, uint len) +{ + uint i= 0; + int err; + + const char *s, *b, *e=str+len; + for (s=str ; s < e ; i++) + { + for ( ; (s < e) && strchr(" \t\r\n",s[0]); s++) ; + b=s; + for ( ; (s < e) && !strchr(" \t\r\n",s[0]); s++) ; + if (s == b || i > size) + break; + a[i]= my_strntol(my_charset_latin1,b,s-b,16,NULL,&err); + } + return 0; +} + + +static int cs_enter(MY_XML_PARSER *st,const char *attr, uint len) +{ + struct my_cs_file_info *i= (struct my_cs_file_info *)st->user_data; + struct my_cs_file_section_st *s= cs_file_sec(attr,len); + + if ( s && (s->state == _CS_CHARSET)) + { + bzero(&i->cs,sizeof(i->cs)); + } + return MY_XML_OK; +} + + +static int cs_leave(MY_XML_PARSER *st,const char *attr, uint len) +{ + struct my_cs_file_info *i= (struct my_cs_file_info *)st->user_data; + struct my_cs_file_section_st *s= cs_file_sec(attr,len); + int state= s ? s->state : 0; + int rc; + + switch(state){ + case _CS_COLLATION: + rc= i->add_collation ? i->add_collation(&i->cs) : MY_XML_OK; + break; + default: + rc=MY_XML_OK; + } + return rc; +} + + +static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) +{ + struct my_cs_file_info *i= (struct my_cs_file_info *)st->user_data; + struct my_cs_file_section_st *s; + int state= (s=cs_file_sec(st->attr,strlen(st->attr))) ? s->state : 0; + int err; + +#ifndef DBUG_OFF + if(0){ + char str[1024]; + mstr(str,attr,len,sizeof(str)-1); + printf("VALUE %d %s='%s'\n",state,st->attr,str); + } +#endif + + switch (state) { + case _CS_ID: + i->cs.number= my_strntoul(my_charset_latin1,attr,len,10,(char**)NULL,&err); + break; + case _CS_COLNAME: + i->cs.name=mstr(i->name,attr,len,MY_CS_NAME_SIZE-1); + break; + case _CS_CSNAME: + i->cs.csname=mstr(i->csname,attr,len,MY_CS_NAME_SIZE-1); + break; + case _CS_FLAG: + if (!strncmp("primary",attr,len)) + i->cs.state|= MY_CS_PRIMARY; + break; + case _CS_UPPERMAP: + fill_uchar(i->to_upper,MY_CS_TO_UPPER_TABLE_SIZE,attr,len); + i->cs.to_upper=i->to_upper; + break; + case _CS_LOWERMAP: + fill_uchar(i->to_lower,MY_CS_TO_LOWER_TABLE_SIZE,attr,len); + i->cs.to_lower=i->to_lower; + break; + case _CS_UNIMAP: + fill_uint16(i->tab_to_uni,MY_CS_TO_UNI_TABLE_SIZE,attr,len); + i->cs.tab_to_uni=i->tab_to_uni; + break; + case _CS_COLLMAP: + fill_uchar(i->sort_order,MY_CS_SORT_ORDER_TABLE_SIZE,attr,len); + i->cs.sort_order=i->sort_order; + break; + case _CS_CTYPEMAP: + fill_uchar(i->ctype,MY_CS_CTYPE_TABLE_SIZE,attr,len); + i->cs.ctype=i->ctype; + break; + } + return MY_XML_OK; +} + + +my_bool my_parse_charset_xml(const char *buf, uint len, + int (*add_collation)(CHARSET_INFO *cs)) +{ + MY_XML_PARSER p; + struct my_cs_file_info i; + my_bool rc; + + my_xml_parser_create(&p); + my_xml_set_enter_handler(&p,cs_enter); + my_xml_set_value_handler(&p,cs_value); + my_xml_set_leave_handler(&p,cs_leave); + i.add_collation= add_collation; + my_xml_set_user_data(&p,(void*)&i); + rc= (my_xml_parse(&p,buf,len) == MY_XML_OK) ? FALSE : TRUE; + my_xml_parser_free(&p); + return rc; +} + + CHARSET_INFO *my_charset_latin1 = &compiled_charsets[0]; CHARSET_INFO *all_charsets[256]; CHARSET_INFO *default_charset_info = &compiled_charsets[0]; diff --git a/mysys/my_vsnprintf.c b/strings/my_vsnprintf.c similarity index 74% rename from mysys/my_vsnprintf.c rename to strings/my_vsnprintf.c index f6c91c0c329..a67523af7bc 100644 --- a/mysys/my_vsnprintf.c +++ b/strings/my_vsnprintf.c @@ -14,13 +14,25 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "mysys_priv.h" -#include "mysys_err.h" +#include #include #include #include #include +/* + Limited snprintf() implementations + + IMPLEMENTION: + Supports following formats: + %#d + %#u + %#.#s Note #.# is skiped + + RETURN + length of result string +*/ + int my_snprintf(char* to, size_t n, const char* fmt, ...) { va_list args; @@ -31,9 +43,12 @@ int my_snprintf(char* to, size_t n, const char* fmt, ...) return result; } + int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap) { char *start=to, *end=to+n-1; + uint length, num_state, pre_zero; + for (; *fmt ; fmt++) { if (fmt[0] != '%') @@ -43,10 +58,27 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap) *to++= *fmt; /* Copy ordinary char */ continue; } - /* Skip if max size is used (to be compatible with printf) */ - fmt++; - while (my_isdigit(system_charset_info,*fmt) || *fmt == '.' || *fmt == '-') + fmt++; /* skip '%' */ + /* Read max fill size (only used with %d and %u) */ + if (*fmt == '-') fmt++; + length= num_state= pre_zero= 0; + for (;; fmt++) + { + if (my_isdigit(system_charset_info,*fmt)) + { + if (!num_state) + { + length=length*10+ (uint) (*fmt-'0'); + if (!length) + pre_zero= 1; /* first digit was 0 */ + } + continue; + } + if (*fmt != '.' || num_state) + break; + num_state= 1; + } if (*fmt == 'l') fmt++; if (*fmt == 's') /* String parameter */ @@ -63,13 +95,26 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap) else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */ { register int iarg; - if ((uint) (end-to) < 16) + char *to_start= to; + if ((uint) (end-to) < max(16,length)) break; iarg = va_arg(ap, int); if (*fmt == 'd') to=int10_to_str((long) iarg,to, -10); else to=int10_to_str((long) (uint) iarg,to,10); + /* If %#d syntax was used, we have to pre-zero/pre-space the string */ + if (length) + { + uint res_length= (uint) (to - to_start); + if (res_length < length) + { + uint diff= (length- res_length); + bmove_upp(to+diff, to, res_length); + bfill(to-res_length, diff, pre_zero ? '0' : ' '); + to+= diff; + } + } continue; } /* We come here on '%%', unknown code or too long parameter */ diff --git a/mysys/xml.c b/strings/xml.c similarity index 100% rename from mysys/xml.c rename to strings/xml.c diff --git a/tests/client_test.c b/tests/client_test.c index d5e13dd3b43..6f7473cf4b5 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -2,7 +2,7 @@ client_test.c - description ------------------------- begin : Sun Feb 3 2002 - copyright : (C) MySQL AB 1995-2002, www.mysql.com + copyright : (C) MySQL AB 1995-2003, www.mysql.com author : venu ( venu@mysql.com ) ***************************************************************************/ @@ -83,7 +83,7 @@ static void print_error(const char *msg) fprintf(stderr,"\n [MySQL-%s]",mysql->server_version); else fprintf(stderr,"\n [MySQL]"); - fprintf(stderr," %s\n",mysql_error(mysql)); + fprintf(stderr,"[%d] %s\n",mysql_errno(mysql),mysql_error(mysql)); } else if(msg) fprintf(stderr, " [MySQL] %s\n", msg); } @@ -97,7 +97,8 @@ static void print_st_error(MYSQL_STMT *stmt, const char *msg) else fprintf(stderr,"\n [MySQL]"); - fprintf(stderr," %s\n",mysql_stmt_error(stmt)); + fprintf(stderr,"[%d] %s\n",mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); } else if(msg) fprintf(stderr, " [MySQL] %s\n", msg); } @@ -106,18 +107,8 @@ static void client_disconnect(); #define myerror(msg) print_error(msg) #define mysterror(stmt, msg) print_st_error(stmt, msg) -#define myassert(exp) \ - if(!exp) {\ - client_disconnect(); \ - fprintf(stderr,"\n"); \ - assert(exp); \ -} -#define myassert_r(exp) \ - if(exp) {\ - client_disconnect(); \ - fprintf(stderr,"\n"); \ - assert(!(exp)); \ -} +#define myassert(exp) assert(exp) +#define myassert_r(exp) assert(!(exp)) #define myquery(r) \ { \ @@ -239,6 +230,9 @@ static void client_query() rc = mysql_query(mysql,"INSERT INTO myclient_test(name) VALUES('deleted')"); myquery(rc); + rc = mysql_query(mysql,"INSERT INTO myclient_test(name) VALUES('deleted')"); + myquery(rc); + rc = mysql_query(mysql,"UPDATE myclient_test SET name='updated' WHERE name='deleted'"); myquery(rc); @@ -343,10 +337,11 @@ int my_process_result_set(MYSQL_RES *result) my_print_dashes(result); if (mysql_errno(mysql) != 0) - fprintf(stderr, "\n mysql_fetch_row() failed\n"); + fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); else - fprintf(stdout,"\n %d rows returned", row_count); - return(row_count); + fprintf(stdout,"\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + return row_count; } /******************************************************** @@ -369,7 +364,7 @@ uint my_process_stmt_result(MYSQL_STMT *stmt) return 0; } - field_count= stmt->field_count; + field_count= mysql_num_fields(result); for(i=0; i < field_count; i++) { buffer[i].buffer_type= MYSQL_TYPE_STRING; @@ -388,12 +383,15 @@ uint my_process_stmt_result(MYSQL_STMT *stmt) { fputc('\t',stdout); fputc('|',stdout); - + + mysql_field_seek(result,0); for (i=0; i < field_count; i++) { field = mysql_fetch_field(result); if(length[i] == MYSQL_NULL_DATA) fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (length[i] == 0) + data[i][0]='\0'; /* unmodified buffer */ else if (IS_NUM(field->type)) fprintf(stdout, " %*s |", (int) field->max_length, data[i]); else @@ -404,9 +402,30 @@ uint my_process_stmt_result(MYSQL_STMT *stmt) row_count++; } my_print_dashes(result); - fprintf(stdout,"\n %d rows returned", row_count); + fprintf(stdout,"\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); mysql_free_result(result); + return row_count; +} +/******************************************************** +* process the stmt result set * +*********************************************************/ +uint my_stmt_result(const char *query, unsigned long length) +{ + MYSQL_STMT *stmt; + uint row_count; + int rc; + + stmt= mysql_prepare(mysql,query,length); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt,rc); + + row_count= my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + return row_count; } @@ -1175,24 +1194,26 @@ static void test_fetch_null() rc = mysql_commit(mysql); myquery(rc); - rc = mysql_query(mysql,"INSERT INTO test_fetch_null(col11) VALUES(1000)"); + rc = mysql_query(mysql,"INSERT INTO test_fetch_null(col11) VALUES(1000),(88),(389789)"); myquery(rc); rc = mysql_commit(mysql); myquery(rc); /* fetch */ - for (i=0; i < 10; i++) + for (i=0; i <= 10; i++) { bind[i].buffer_type=FIELD_TYPE_LONG; length[i]=99; bind[i].length= (long *)&length[i]; } - bind[i].buffer_type=FIELD_TYPE_LONG; - bind[i].buffer=(gptr)&nData; + bind[i-1].buffer=(gptr)&nData; strcpy((char *)query , "SELECT * FROM test_fetch_null"); - stmt = mysql_prepare(mysql, query, strlen(query)); + + myassert(3 == my_stmt_result(query,50)); + + stmt = mysql_prepare(mysql, query, 50); mystmt_init(stmt); rc = mysql_bind_result(stmt,bind); @@ -1201,20 +1222,21 @@ static void test_fetch_null() rc = mysql_execute(stmt); mystmt(stmt, rc); - rc = mysql_fetch(stmt); - mystmt(stmt,rc); - - for (i=0; i < 10; i++) + rc= 0; + while (mysql_fetch(stmt) != MYSQL_NO_DATA) { - fprintf(stdout, "\n data[%d]: %s", i, length[i] == MYSQL_NULL_DATA ? "NULL" : "NOT NULL"); - myassert(length[i] == MYSQL_NULL_DATA); + rc++; + for (i=0; i < 10; i++) + { + fprintf(stdout, "\n data[%d] : %s", i, + length[i] == MYSQL_NULL_DATA ? "NULL" : "NOT NULL"); + myassert(length[i] == MYSQL_NULL_DATA); + } + fprintf(stdout, "\n data[%d]: %d", i, nData); + myassert(nData == 1000 || nData == 88 || nData == 389789); + myassert(length[i] == 4); } - fprintf(stdout, "\n data[%d]: %d", i, nData); - myassert(nData == 1000); - - rc = mysql_fetch(stmt); - myassert(rc == MYSQL_NO_DATA); - + myassert(rc == 3); mysql_stmt_close(stmt); } @@ -1571,6 +1593,7 @@ static void test_long_data() MYSQL_STMT *stmt; int rc, int_data; char *data=NullS; + long length; MYSQL_RES *result; MYSQL_BIND bind[3]; @@ -1606,10 +1629,11 @@ static void test_long_data() bind[0].buffer=(char *)&int_data; bind[0].buffer_type=FIELD_TYPE_LONG; - bind[1].is_long_data=1; /* specify long data suppy during run-time */ /* Non string or binary type, error */ bind[1].buffer_type=FIELD_TYPE_LONG; + bind[1].length=&length; + length= MYSQL_LONG_DATA; /* specify long data suppy during run-time */ rc = mysql_bind_param(stmt,bind); fprintf(stdout," mysql_bind_param() returned: %d\n",rc); mystmt_r(stmt, rc); @@ -1679,7 +1703,7 @@ static void test_long_data_str() MYSQL_STMT *stmt; int rc, i; char data[255]; - long length; + long length, length1; MYSQL_RES *result; MYSQL_BIND bind[2]; @@ -1712,8 +1736,9 @@ static void test_long_data_str() bind[0].buffer_type = FIELD_TYPE_LONG; bind[1].buffer=data; /* string data */ - bind[1].is_long_data=1; /* specify long data suppy during run-time */ bind[1].buffer_type=FIELD_TYPE_STRING; + bind[1].length= &length1; + length1= MYSQL_LONG_DATA; rc = mysql_bind_param(stmt,bind); mystmt(stmt, rc); @@ -1778,9 +1803,9 @@ static void test_long_data_str() static void test_long_data_str1() { MYSQL_STMT *stmt; - int rc; + int rc, i; char data[255]; - int length, i; + long length, length1; MYSQL_RES *result; MYSQL_BIND bind[2]; @@ -1810,8 +1835,9 @@ static void test_long_data_str1() verify_param_count(stmt,2); bind[0].buffer=data; /* string data */ - bind[0].is_long_data=1; /* specify long data suppy during run-time */ + bind[0].length= &length1; bind[0].buffer_type=FIELD_TYPE_STRING; + length1= MYSQL_LONG_DATA; bind[1] = bind[0]; bind[1].buffer_type=FIELD_TYPE_BLOB; @@ -1874,7 +1900,7 @@ static void test_long_data_str1() myassert(1 == my_process_result_set(result)); mysql_free_result(result); - sprintf(data,"%d",i*length); + sprintf(data,"%ld",(long)i*length); verify_col_data("test_long_data_str","length(longstr)",data); sprintf(data,"%d",i*2); @@ -1890,7 +1916,7 @@ static void test_long_data_bin() MYSQL_STMT *stmt; int rc; char data[255]; - int length; + long length, length1; MYSQL_RES *result; MYSQL_BIND bind[2]; @@ -1923,8 +1949,9 @@ static void test_long_data_bin() bind[0].buffer_type = FIELD_TYPE_LONG; bind[1].buffer=data; /* string data */ - bind[1].is_long_data=1; /* specify long data suppy during run-time */ bind[1].buffer_type=FIELD_TYPE_LONG_BLOB; + bind[1].length= &length1; + length1= MYSQL_LONG_DATA; rc = mysql_bind_param(stmt,bind); mystmt(stmt, rc); @@ -2603,6 +2630,8 @@ static void test_fetch_date() bind[6].buffer=(gptr)&ts_6; bind[6].length=(long *)&ts6_length; + myassert(1 == my_stmt_result("SELECT * FROM test_bind_result",50)); + stmt = mysql_prepare(mysql, "SELECT * FROM test_bind_result", 50); mystmt_init(stmt); @@ -2611,7 +2640,7 @@ static void test_fetch_date() rc = mysql_execute(stmt); mystmt(stmt, rc); - + ts_4[0]='\0'; rc = mysql_fetch(stmt); mystmt(stmt,rc); @@ -2628,7 +2657,7 @@ static void test_fetch_date() myassert(d_length == 10); myassert(strcmp(time,"12:49:00")==0); - myassert(d_length == 8); + myassert(t_length == 8); myassert(strcmp(ts,"2002-01-02 17:46:59")==0); myassert(ts_length == 19); @@ -2651,6 +2680,942 @@ static void test_fetch_date() mysql_stmt_close(stmt); } +/******************************************************** +* to test fetching of str to all types * +*********************************************************/ +static void test_fetch_str() +{ + MYSQL_STMT *stmt; + int rc, i, round, bit; + long data[10], length[10]; + float f_data; + double d_data; + char s_data[10]; + MYSQL_BIND bind[7]; + + myheader("test_fetch_str"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_str"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_str(c1 char(10),\ + c2 char(10),\ + c3 char(20),\ + c4 char(20),\ + c5 char(30),\ + c6 char(40),\ + c7 char(20))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_bind_str VALUES(?,?,?,?,?,?,?)",100); + myquery(rc); + + verify_param_count(stmt, 7); + + round= 0; + for (i=0; i < 7; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)&data[i]; + data[i]= round+i+1; + round= (round +10)*10; + } + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + myassert(1 == my_stmt_result("SELECT * FROM test_bind_str",50)); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_bind_str",50); + myquery(rc); + + for (i=0; i < 7; i++) + { + bind[i].buffer= (void *)&data[i]; + bind[i].length= (long *)&length[i]; + } + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&s_data; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n tiny : %ld(%ld)", data[0], length[0]); + fprintf(stdout, "\n short : %ld(%ld)", data[1], length[1]); + fprintf(stdout, "\n int : %ld(%ld)", data[2], length[2]); + fprintf(stdout, "\n longlong : %ld(%ld)", data[3], length[3]); + fprintf(stdout, "\n float : %f(%ld)", f_data, length[4]); + fprintf(stdout, "\n double : %g(%ld)", d_data, length[5]); + fprintf(stdout, "\n char : %s(%ld)", s_data, length[6]); + + round= 0; + bit= 1; + + for (i=0; i < 4; i++) + { + myassert(data[i] == round+i+1); + myassert(length[i] == bit); + round= (round+10)*10; + bit<<= 1; + } + + /* FLOAT */ + myassert((int)f_data == round+1+i); + myassert(length[4] == 4); + + /* DOUBLE */ + round= (round+10)*10; + myassert((int)d_data == round+2+i); + myassert(length[5] == 8); + + /* CHAR */ + round= (round+10)*10; + { + char buff[20]; + int len= sprintf(buff,"%d", round+3+i); + myassert(strcmp(s_data,buff)==0); + myassert(length[6] == len); + } + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test fetching of long to all types * +*********************************************************/ +static void test_fetch_long() +{ + MYSQL_STMT *stmt; + int rc, i, round, bit; + long data[10], length[10]; + float f_data; + double d_data; + char s_data[10]; + MYSQL_BIND bind[7]; + + myheader("test_fetch_long"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_long"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_long(c1 int unsigned,\ + c2 int unsigned,\ + c3 int,\ + c4 int,\ + c5 int,\ + c6 int unsigned,\ + c7 int)"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_bind_long VALUES(?,?,?,?,?,?,?)",100); + myquery(rc); + + verify_param_count(stmt, 7); + + round= 0; + for (i=0; i < 7; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)&data[i]; + data[i]= round+i+1; + round= (round +10)*10; + } + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + myassert(1 == my_stmt_result("SELECT * FROM test_bind_long",50)); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_bind_long",50); + myquery(rc); + + for (i=0; i < 7; i++) + { + bind[i].buffer= (void *)&data[i]; + bind[i].length= (long *)&length[i]; + } + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&s_data; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n tiny : %ld(%ld)", data[0], length[0]); + fprintf(stdout, "\n short : %ld(%ld)", data[1], length[1]); + fprintf(stdout, "\n int : %ld(%ld)", data[2], length[2]); + fprintf(stdout, "\n longlong : %ld(%ld)", data[3], length[3]); + fprintf(stdout, "\n float : %f(%ld)", f_data, length[4]); + fprintf(stdout, "\n double : %g(%ld)", d_data, length[5]); + fprintf(stdout, "\n char : %s(%ld)", s_data, length[6]); + + round= 0; + bit= 1; + + for (i=0; i < 4; i++) + { + myassert(data[i] == round+i+1); + myassert(length[i] == bit); + round= (round+10)*10; + bit<<= 1; + } + + /* FLOAT */ + myassert((int)f_data == round+1+i); + myassert(length[4] == 4); + + /* DOUBLE */ + round= (round+10)*10; + myassert((int)d_data == round+2+i); + myassert(length[5] == 8); + + /* CHAR */ + round= (round+10)*10; + { + char buff[20]; + int len= sprintf(buff,"%d", round+3+i); + myassert(strcmp(s_data,buff)==0); + myassert(length[6] == len); + } + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test fetching of short to all types * +*********************************************************/ +static void test_fetch_short() +{ + MYSQL_STMT *stmt; + int rc, i, round, bit; + long data[10], length[10]; + float f_data; + double d_data; + char s_data[10]; + MYSQL_BIND bind[7]; + + myheader("test_fetch_short"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_long"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_long(c1 smallint unsigned,\ + c2 smallint,\ + c3 smallint unsigned,\ + c4 smallint,\ + c5 smallint,\ + c6 smallint,\ + c7 smallint unsigned)"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_bind_long VALUES(?,?,?,?,?,?,?)",100); + myquery(rc); + + verify_param_count(stmt, 7); + + round= 0; + for (i=0; i < 7; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)&data[i]; + data[i]= round+i+1; + round= (round +10)*2; + } + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + myassert(1 == my_stmt_result("SELECT * FROM test_bind_long",50)); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_bind_long",50); + myquery(rc); + + for (i=0; i < 7; i++) + { + bind[i].buffer= (void *)&data[i]; + bind[i].length= (long *)&length[i]; + } + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&s_data; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n tiny : %ld(%ld)", data[0], length[0]); + fprintf(stdout, "\n short : %ld(%ld)", data[1], length[1]); + fprintf(stdout, "\n int : %ld(%ld)", data[2], length[2]); + fprintf(stdout, "\n longlong : %ld(%ld)", data[3], length[3]); + fprintf(stdout, "\n float : %f(%ld)", f_data, length[4]); + fprintf(stdout, "\n double : %g(%ld)", d_data, length[5]); + fprintf(stdout, "\n char : %s(%ld)", s_data, length[6]); + + round= 0; + bit= 1; + + for (i=0; i < 4; i++) + { + myassert(data[i] == round+i+1); + myassert(length[i] == bit); + round= (round+10)*2; + bit<<= 1; + } + + /* FLOAT */ + myassert((int)f_data == round+1+i); + myassert(length[4] == 4); + + /* DOUBLE */ + round= (round+10)*2; + myassert((int)d_data == round+2+i); + myassert(length[5] == 8); + + /* CHAR */ + round= (round+10)*2; + { + char buff[20]; + int len= sprintf(buff,"%d", round+3+i); + myassert(strcmp(s_data,buff)==0); + myassert(length[6] == len); + } + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test fetching of tiny to all types * +*********************************************************/ +static void test_fetch_tiny() +{ + MYSQL_STMT *stmt; + int rc, i, bit; + long data[10], length[10]; + float f_data; + double d_data; + char s_data[10]; + MYSQL_BIND bind[7]; + + myheader("test_fetch_tiny"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_long"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_long(c1 tinyint unsigned,\ + c2 tinyint,\ + c3 tinyint unsigned,\ + c4 tinyint,\ + c5 tinyint,\ + c6 tinyint,\ + c7 tinyint unsigned)"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_bind_long VALUES(?,?,?,?,?,?,?)",100); + myquery(rc); + + verify_param_count(stmt, 7); + + rc= 10; + for (i=0; i < 7; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)&data[i]; + data[i]= rc+i; + rc+= 10; + } + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + myassert(1 == my_stmt_result("SELECT * FROM test_bind_long",50)); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_bind_long",50); + myquery(rc); + + for (i=0; i < 7; i++) + { + bind[i].buffer= (void *)&data[i]; + bind[i].length= (long *)&length[i]; + } + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&s_data; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n tiny : %ld(%ld)", data[0], length[0]); + fprintf(stdout, "\n short : %ld(%ld)", data[1], length[1]); + fprintf(stdout, "\n int : %ld(%ld)", data[2], length[2]); + fprintf(stdout, "\n longlong : %ld(%ld)", data[3], length[3]); + fprintf(stdout, "\n float : %f(%ld)", f_data, length[4]); + fprintf(stdout, "\n double : %g(%ld)", d_data, length[5]); + fprintf(stdout, "\n char : %s(%ld)", s_data, length[6]); + + bit= 1; + rc= 10; + for (i=0; i < 4; i++) + { + myassert(data[i] == rc+i); + myassert(length[i] == bit); + bit<<= 1; + rc+= 10; + } + + /* FLOAT */ + rc+= i; + myassert((int)f_data == rc); + myassert(length[4] == 4); + + /* DOUBLE */ + rc+= 11; + myassert((int)d_data == rc); + myassert(length[5] == 8); + + /* CHAR */ + rc+= 11; + { + char buff[20]; + int len= sprintf(buff,"%d", rc); + myassert(strcmp(s_data,buff)==0); + myassert(length[6] == len); + } + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test fetching of longlong to all types * +*********************************************************/ +static void test_fetch_bigint() +{ + MYSQL_STMT *stmt; + int rc, i, round, bit; + long data[10], length[10]; + float f_data; + double d_data; + char s_data[10]; + MYSQL_BIND bind[7]; + + myheader("test_fetch_bigint"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_long"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_long(c1 bigint,\ + c2 bigint,\ + c3 bigint unsigned,\ + c4 bigint unsigned,\ + c5 bigint unsigned,\ + c6 bigint unsigned,\ + c7 bigint unsigned)"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_bind_long VALUES(?,?,?,?,?,?,?)",100); + myquery(rc); + + verify_param_count(stmt, 7); + + round= 0; + for (i=0; i < 7; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)&data[i]; + data[i]= round+i+1; + round= (round +10)*10; + } + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + myassert(1 == my_stmt_result("SELECT * FROM test_bind_long",50)); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_bind_long",50); + myquery(rc); + + for (i=0; i < 7; i++) + { + bind[i].buffer= (void *)&data[i]; + bind[i].length= (long *)&length[i]; + } + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&s_data; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n tiny : %ld(%ld)", data[0], length[0]); + fprintf(stdout, "\n short : %ld(%ld)", data[1], length[1]); + fprintf(stdout, "\n int : %ld(%ld)", data[2], length[2]); + fprintf(stdout, "\n longlong : %ld(%ld)", data[3], length[3]); + fprintf(stdout, "\n float : %f(%ld)", f_data, length[4]); + fprintf(stdout, "\n double : %g(%ld)", d_data, length[5]); + fprintf(stdout, "\n char : %s(%ld)", s_data, length[6]); + + round= 0; + bit= 1; + + for (i=0; i < 4; i++) + { + myassert(data[i] == round+i+1); + myassert(length[i] == bit); + round= (round+10)*10; + bit<<= 1; + } + + /* FLOAT */ + myassert((int)f_data == round+1+i); + myassert(length[4] == 4); + + /* DOUBLE */ + round= (round+10)*10; + myassert((int)d_data == round+2+i); + myassert(length[5] == 8); + + /* CHAR */ + round= (round+10)*10; + { + char buff[20]; + int len= sprintf(buff,"%d", round+3+i); + myassert(strcmp(s_data,buff)==0); + myassert(length[6] == len); + } + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test fetching of float to all types * +*********************************************************/ +static void test_fetch_float() +{ + MYSQL_STMT *stmt; + int rc, i, round, bit; + long data[10], length[10]; + float f_data; + double d_data; + char s_data[10]; + MYSQL_BIND bind[7]; + + myheader("test_fetch_float"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_long"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_long(c1 float(3),\ + c2 float,\ + c3 float unsigned,\ + c4 float,\ + c5 float,\ + c6 float,\ + c7 float(10) unsigned)"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_bind_long VALUES(?,?,?,?,?,?,?)",100); + myquery(rc); + + verify_param_count(stmt, 7); + + round= 0; + for (i=0; i < 7; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)&data[i]; + data[i]= round+i+1; + round= (round +10)*2; + } + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + myassert(1 == my_stmt_result("SELECT * FROM test_bind_long",50)); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_bind_long",50); + myquery(rc); + + for (i=0; i < 7; i++) + { + bind[i].buffer= (void *)&data[i]; + bind[i].length= (long *)&length[i]; + } + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + + bind[4].buffer_type= MYSQL_TYPE_FLOAT; + bind[4].buffer= (void *)&f_data; + + bind[5].buffer_type= MYSQL_TYPE_DOUBLE; + bind[5].buffer= (void *)&d_data; + + bind[6].buffer_type= MYSQL_TYPE_STRING; + bind[6].buffer= (void *)&s_data; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n tiny : %ld(%ld)", data[0], length[0]); + fprintf(stdout, "\n short : %ld(%ld)", data[1], length[1]); + fprintf(stdout, "\n int : %ld(%ld)", data[2], length[2]); + fprintf(stdout, "\n longlong : %ld(%ld)", data[3], length[3]); + fprintf(stdout, "\n float : %f(%ld)", f_data, length[4]); + fprintf(stdout, "\n double : %g(%ld)", d_data, length[5]); + fprintf(stdout, "\n char : %s(%ld)", s_data, length[6]); + + round= 0; + bit= 1; + + for (i=0; i < 4; i++) + { + myassert(data[i] == round+i+1); + myassert(length[i] == bit); + round= (round+10)*2; + bit<<= 1; + } + + /* FLOAT */ + myassert((int)f_data == round+1+i); + myassert(length[4] == 4); + + /* DOUBLE */ + round= (round+10)*2; + myassert((int)d_data == round+2+i); + myassert(length[5] == 8); + + /* CHAR */ + round= (round+10)*2; + { + char buff[20]; + int len= sprintf(buff,"%d", round+3+i); + myassert(strcmp(s_data,buff)==0); + myassert(length[6] == len); + } + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test fetching of double to all types * +*********************************************************/ +static void test_fetch_double() +{ + MYSQL_STMT *stmt; + int rc, i, round, bit; + long data[10], length[10]; + float f_data; + double d_data; + char s_data[10]; + MYSQL_BIND bind[7]; + + myheader("test_fetch_double"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_long"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_long(c1 double(5,2),\ + c2 double unsigned,\ + c3 double unsigned,\ + c4 double unsigned,\ + c5 double unsigned,\ + c6 double unsigned,\ + c7 double unsigned)"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"INSERT INTO test_bind_long VALUES(?,?,?,?,?,?,?)",100); + myquery(rc); + + verify_param_count(stmt, 7); + + round= 0; + for (i=0; i < 7; i++) + { + bind[i].buffer_type= MYSQL_TYPE_LONG; + bind[i].buffer= (void *)&data[i]; + data[i]= round+i+1; + round= (round +10)*10; + } + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_commit(mysql); + myquery(rc); + + mysql_stmt_close(stmt); + + myassert(1 == my_stmt_result("SELECT * FROM test_bind_long",50)); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_bind_long",50); + myquery(rc); + + for (i=0; i < 7; i++) + { + bind[i].buffer= (void *)&data[i]; + bind[i].length= (long *)&length[i]; + } + bind[0].buffer_type= MYSQL_TYPE_TINY; + bind[1].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer_type= MYSQL_TYPE_LONG; + bind[3].buffer_type= MYSQL_TYPE_LONGLONG; + + bind[4].buffer_type= MYSQL_TYPE_STRING; + bind[4].buffer= (void *)&s_data; + + bind[5].buffer_type= MYSQL_TYPE_FLOAT; + bind[5].buffer= (void *)&f_data; + + bind[6].buffer_type= MYSQL_TYPE_DOUBLE; + bind[6].buffer= (void *)&d_data; + + rc = mysql_bind_result(stmt, bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n tiny : %ld(%ld)", data[0], length[0]); + fprintf(stdout, "\n short : %ld(%ld)", data[1], length[1]); + fprintf(stdout, "\n int : %ld(%ld)", data[2], length[2]); + fprintf(stdout, "\n longlong : %ld(%ld)", data[3], length[3]); + fprintf(stdout, "\n float : %f(%ld)", f_data, length[5]); + fprintf(stdout, "\n double : %g(%ld)", d_data, length[6]); + fprintf(stdout, "\n char : %s(%ld)", s_data, length[4]); + + round= 0; + bit= 1; + + for (i=0; i < 4; i++) + { + myassert(data[i] == round+i+1); + myassert(length[i] == bit); + round= (round+10)*10; + bit<<= 1; + } + /* CHAR */ + { + char buff[20]; + int len= sprintf(buff,"%d", round+1+i); + myassert(strcmp(s_data,buff)==0); + myassert(length[4] == len); + } + + /* FLOAT */ + round= (round+10)*10; + myassert((int)f_data == round+2+i); + myassert(length[5] == 4); + + /* DOUBLE */ + round= (round+10)*10; + myassert((int)d_data == round+3+i); + myassert(length[6] == 8); + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} /******************************************************** * to test simple prepare with all possible types * @@ -3479,6 +4444,161 @@ static void test_func_fields() mysql_free_result(result); } +/* Multiple stmts .. */ +static void test_multi_stmt() +{ +} + +/******************************************************** +* to test simple sample - manual * +*********************************************************/ +static void test_manual_sample() +{ + unsigned int param_count; + MYSQL_BIND bind[3]; + MYSQL_STMT *stmt; + short small_data; + int int_data; + char str_data[50], query[255]; + long length; + ulonglong affected_rows; + + myheader("test_manual_sample"); + + /* + Sample which is incorporated directly in the manual under Prepared + statements section (Example from mysql_execute() + */ + + mysql_autocommit(mysql, 1); + if (mysql_query(mysql,"DROP TABLE IF EXISTS test_table")) + { + fprintf(stderr, "\n drop table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + } + if (mysql_query(mysql,"CREATE TABLE test_table(col1 int, col2 varchar(50), \ + col3 smallint,\ + col4 timestamp(14))")) + { + fprintf(stderr, "\n create table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + } + + /* Prepare a insert query with 3 parameters */ + strcpy(query, "INSERT INTO test_table(col1,col2,col3) values(?,?,?)"); + if(!(stmt = mysql_prepare(mysql,query,strlen(query)))) + { + fprintf(stderr, "\n prepare, insert failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + } + fprintf(stdout, "\n prepare, insert successful"); + + /* Get the parameter count from the statement */ + param_count= mysql_param_count(stmt); + + fprintf(stdout, "\n total parameters in insert: %d", param_count); + if (param_count != 3) /* validate parameter count */ + { + fprintf(stderr, "\n invalid parameter count returned by MySQL"); + exit(0); + } + + /* Bind the data for the parameters */ + + /* INTEGER PART */ + memset(bind,0,sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void *)&int_data; + + /* STRING PART */ + bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; + bind[1].buffer= (void *)str_data; + bind[1].buffer_length= sizeof(str_data); + + /* SMALLINT PART */ + bind[2].buffer_type= MYSQL_TYPE_SHORT; + bind[2].buffer= (void *)&small_data; + bind[2].length= (long *)&length; + + /* Bind the buffers */ + if (mysql_bind_param(stmt, bind)) + { + fprintf(stderr, "\n param bind failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + } + + /* Specify the data */ + int_data= 10; /* integer */ + strcpy(str_data,"MySQL"); /* string */ + /* INSERT SMALLINT data as NULL */ + length= MYSQL_NULL_DATA; + + /* Execute the insert statement - 1*/ + if (mysql_execute(stmt)) + { + fprintf(stderr, "\n execute 1 failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + } + + /* Get the total rows affected */ + affected_rows= mysql_stmt_affected_rows(stmt); + + fprintf(stdout, "\n total affected rows: %lld", affected_rows); + if (affected_rows != 1) /* validate affected rows */ + { + fprintf(stderr, "\n invalid affected rows by MySQL"); + exit(0); + } + + /* Re-execute the insert, by changing the values */ + int_data= 1000; + strcpy(str_data,"The most popular open source database"); + small_data= 1000; /* smallint */ + length= 0; + + /* Execute the insert statement - 2*/ + if (mysql_execute(stmt)) + { + fprintf(stderr, "\n execute 2 failed"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + } + + /* Get the total rows affected */ + affected_rows= mysql_stmt_affected_rows(stmt); + + fprintf(stdout, "\n total affected rows: %lld", affected_rows); + if (affected_rows != 1) /* validate affected rows */ + { + fprintf(stderr, "\n invalid affected rows by MySQL"); + exit(0); + } + + /* Close the statement */ + if (mysql_stmt_close(stmt)) + { + fprintf(stderr, "\n failed while closing the statement"); + fprintf(stderr, "\n %s", mysql_stmt_error(stmt)); + exit(0); + } + myassert(2 == my_stmt_result("SELECT * FROM test_table",50)); + + /* DROP THE TABLE */ + if (mysql_query(mysql,"DROP TABLE test_table")) + { + fprintf(stderr, "\n drop table failed"); + fprintf(stderr, "\n %s", mysql_error(mysql)); + exit(0); + } + fprintf(stdout, "Success !!!"); +} + + static struct my_option myctest_long_options[] = { {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, @@ -3586,20 +4706,26 @@ int main(int argc, char **argv) MY_INIT(argv[0]); get_options(argc,argv); - client_connect(); /* connect to server */ - test_select_prepare(); - test_prepare(); - test_prepare_simple(); + client_connect(); /* connect to server */ + client_query(); /* simple client query test */ + test_manual_sample(); /* sample in the manual */ test_bind_result(); /* result bind test */ test_fetch_null(); /* to fetch null data */ - test_fetch_date(); + test_fetch_date(); /* to fetch date,time and timestamp */ + test_fetch_str(); /* to fetch string to all types */ + test_fetch_long(); /* to fetch long to all types */ + test_fetch_short(); /* to fetch short to all types */ + test_fetch_tiny(); /* to fetch tiny to all types */ + test_fetch_bigint(); /* to fetch bigint to all types */ + test_fetch_float(); /* to fetch float to all types */ + test_fetch_double(); /* to fetch double to all types */ test_bind_result_ext(); /* result bind test - extension */ test_bind_result_ext1(); /* result bind test - extension */ test_select_direct(); /* direct select - protocol_simple debug */ test_select_prepare(); /* prepare select - protocol_prep debug */ - test_select_direct(); /* direct select - protocol_simple debug */ - test_select(); - test_select_version(); + test_select_direct(); /* direct select - protocol_simple debug */ + test_select(); /* simple select test */ + test_select_version(); /* select with variables */ test_set_variable(); /* set variable prepare */ #if NOT_USED test_select_meta(); /* select param meta information */ @@ -3607,19 +4733,14 @@ int main(int argc, char **argv) test_insert_meta(); /* insert param meta information */ #endif test_simple_update(); /* simple update test */ - test_func_fields(); - test_long_data(); - test_insert(); - test_set_variable(); - test_tran_innodb(); - test_select_version(); - test_select_simple(); - test_debug_example(); - test_select(); - test_select_show(); + test_func_fields(); /* test for new 4.1 MYSQL_FIELD members */ + test_long_data(); /* test for sending text data in chunks */ + test_insert(); /* simple insert test - prepare */ + test_set_variable(); /* prepare with set variables */ + test_tran_innodb(); /* test for mysql_commit(), rollback() and autocommit() */ + test_select_show(); /* prepare - show test */ test_null(); /* test null data handling */ - test_simple_update(); - test_prepare_resultset(); + test_simple_update(); /* simple prepare - update */ test_prepare_noparam();/* prepare without parameters */ test_select(); /* simple prepare-select */ test_insert(); /* prepare with insert */ @@ -3643,7 +4764,7 @@ int main(int argc, char **argv) test_prepare_ext(); /* test prepare with all types conversion -- TODO */ test_prepare_syntax();/* syntax check for prepares */ test_prepare_field_result(); /* prepare meta info */ - test_prepare_resultset(); + test_prepare_resultset(); /* prepare meta info test */ test_field_names(); /* test for field names */ test_field_flags(); /* test to help .NET provider team */ test_long_data_str(); /* long data handling */ @@ -3656,6 +4777,7 @@ int main(int argc, char **argv) test_func_fields(); /* FUNCTION field info */ /*test_stmt_close(); */ /* mysql_stmt_close() test -- hangs */ test_prepare_field_result(); /* prepare meta info */ + test_multi_stmt(); /* multi stmt test */ client_disconnect(); /* disconnect from server */ fprintf(stdout,"\n\nSUCCESS !!!\n");