From 7d33418bcdc3604f45f7a29774f96cdf568c000c Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Sun, 5 Jan 2003 21:58:06 +0200 Subject: [PATCH 01/48] btr0pcur.c: Fix bug: an index cursor can theoretically be restored in a wrong place log0log.c: Fix bug: if combined log file size is >= 2 GB in a 32-bit computer InnoDB can write log to a wrong position --- innobase/btr/btr0pcur.c | 5 +++++ innobase/log/log0log.c | 32 +++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/innobase/btr/btr0pcur.c b/innobase/btr/btr0pcur.c index b2115dfdd6c..7b817d8263d 100644 --- a/innobase/btr/btr0pcur.c +++ b/innobase/btr/btr0pcur.c @@ -292,6 +292,11 @@ btr_pcur_restore_position( mem_heap_free(heap); + /* We have to store position information, modify clock value, etc. + because the cursor may now be on a different page */ + + btr_pcur_store_position(cursor, mtr); + return(FALSE); } diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index f9b785ccbd5..539cde337bd 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -437,25 +437,29 @@ log_group_calc_lsn_offset( dulint lsn, /* in: lsn, must be within 4 GB of group->lsn */ log_group_t* group) /* in: log group */ { - dulint gr_lsn; - ulint gr_lsn_size_offset; - ulint difference; - ulint group_size; - ulint offset; + dulint gr_lsn; + ib_longlong gr_lsn_size_offset; + ib_longlong difference; + ib_longlong group_size; + ib_longlong offset; ut_ad(mutex_own(&(log_sys->mutex))); + /* If total log file size is > 2 GB we can easily get overflows + with 32-bit integers. Use 64-bit integers instead. */ + gr_lsn = group->lsn; - gr_lsn_size_offset = log_group_calc_size_offset(group->lsn_offset, - group); - group_size = log_group_get_capacity(group); + gr_lsn_size_offset = (ib_longlong) + log_group_calc_size_offset(group->lsn_offset, group); + + group_size = (ib_longlong) log_group_get_capacity(group); if (ut_dulint_cmp(lsn, gr_lsn) >= 0) { - difference = ut_dulint_minus(lsn, gr_lsn); + difference = (ib_longlong) ut_dulint_minus(lsn, gr_lsn); } else { - difference = ut_dulint_minus(gr_lsn, lsn); + difference = (ib_longlong) ut_dulint_minus(gr_lsn, lsn); difference = difference % group_size; @@ -464,7 +468,13 @@ log_group_calc_lsn_offset( offset = (gr_lsn_size_offset + difference) % group_size; - return(log_group_calc_real_offset(offset, group)); + ut_a(offset <= 0xFFFFFFFF); + + /* printf("Offset is %lu gr_lsn_offset is %lu difference is %lu\n", + (ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference); + */ + + return(log_group_calc_real_offset((ulint)offset, group)); } /*********************************************************************** From ee59eb241854e05d522236f6ae89cff54b82012f Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Tue, 7 Jan 2003 16:53:10 +0200 Subject: [PATCH 02/48] Portability fixes Fixed test suite for HPUX 10.20 and MacOSX --- Build-tools/Do-compile | 27 +++++--- client/mysqladmin.c | 62 +++++++++++------ client/mysqltest.c | 8 +-- mysql-test/mysql-test-run.sh | 33 ++++++--- sql-bench/bench-init.pl.sh | 5 +- sql-bench/crash-me.sh | 126 +++++++++++++++++++--------------- sql-bench/test-alter-table.sh | 43 ++++++++++-- sql-bench/test-insert.sh | 7 +- sql/mysql_priv.h | 1 - sql/mysqld.cc | 43 +++++++----- sql/net_pkg.cc | 5 +- sql/slave.cc | 2 + 12 files changed, 233 insertions(+), 129 deletions(-) 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 < -#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 @@ -70,8 +70,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); /* @@ -481,7 +481,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; } @@ -1110,34 +1111,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/mysqltest.c b/client/mysqltest.c index 20d277ca969..fe99dda1ac3 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 @@ -1797,10 +1797,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, @@ -1893,7 +1891,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; @@ -1971,7 +1971,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/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 5c80e7d538a..408c76d8602 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! @@ -343,9 +344,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) @@ -419,6 +420,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" @@ -435,6 +437,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" @@ -749,9 +752,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 @@ -873,8 +876,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 @@ -982,9 +985,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 } @@ -1085,8 +1091,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` @@ -1123,13 +1127,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 @@ -1159,7 +1167,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/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 085d7cce7f3..38014f7cddf 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/mysql_priv.h b/sql/mysql_priv.h index 3cf6bb2c1a5..2a8b263bf28 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -772,7 +772,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 61ae07c01e7..e7190f575db 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -470,6 +470,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 @@ -742,13 +743,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 @@ -827,7 +828,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); @@ -842,7 +843,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 */ @@ -887,12 +888,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 */ @@ -902,6 +903,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 */ @@ -1481,7 +1486,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 @@ -1550,8 +1555,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 @@ -1639,12 +1647,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: diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc index afedba6a259..30cad3a4177 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -134,7 +134,10 @@ net_printf(NET *net, uint errcode, ...) { if (thd && 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/slave.cc b/sql/slave.cc index d254221e726..455b574b355 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -376,6 +376,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, @@ -386,6 +387,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, From 4af985f4e3ae37367541571fd5acf1abee7b4ce2 Mon Sep 17 00:00:00 2001 From: "jani@hynda.(none)" <> Date: Tue, 7 Jan 2003 19:04:41 +0200 Subject: [PATCH 03/48] Added new program, mysql_waitpid. --- extra/Makefile.am | 2 +- extra/mysql_waitpid.c | 86 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 extra/mysql_waitpid.c diff --git a/extra/Makefile.am b/extra/Makefile.am index 2d7dc95f616..8e4491969b5 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -18,7 +18,7 @@ INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include -I.. 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..6e307209fda --- /dev/null +++ b/extra/mysql_waitpid.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include + +static const char *VER= "1.0"; +static char *progname; +static int verbose= 0; + +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.", 0, 0, 0, + GET_NO_ARG, 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); +} From d1396cc0479984179d633a8b0cb101821f7efd40 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Tue, 7 Jan 2003 21:20:43 +0200 Subject: [PATCH 04/48] mem0pool.c: Remove the warning message that mem allocation spills from the additional mem pool to the OS; this does not hit performance with modern malloc libraries --- innobase/mem/mem0pool.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 1c32a4d02a6..382e505b63f 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -259,19 +259,6 @@ mem_pool_fill_free_list( /* We come here when we have run out of space in the memory pool: */ - if (mem_out_of_mem_err_msg_count % 1000000000 == 0) { - /* We do not print the message every time: */ - - ut_print_timestamp(stderr); - - fprintf(stderr, - " InnoDB: Out of memory in additional memory pool.\n" - "InnoDB: InnoDB will start allocating memory from the OS.\n" - "InnoDB: You may get better performance if you configure a bigger\n" - "InnoDB: value in the MySQL my.cnf file for\n" - "InnoDB: innodb_additional_mem_pool_size.\n"); - } - mem_out_of_mem_err_msg_count++; return(FALSE); From aa51a872830a440b258f34e752a7a0253db8e60c Mon Sep 17 00:00:00 2001 From: "miguel@hegel.br" <> Date: Tue, 7 Jan 2003 23:46:30 -0200 Subject: [PATCH 05/48] Fix embedded server crash --- sql/sql_show.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a11abf75506..50ee78c1ebc 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1217,6 +1217,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_RPL_STATUS: net_store_data(&packet2, rpl_status_type[(int)rpl_status]); break; +#ifndef EMBEDDED_LIBRARY case SHOW_SLAVE_RUNNING: { LOCK_ACTIVE_MI; @@ -1226,6 +1227,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, UNLOCK_ACTIVE_MI; break; } +#endif case SHOW_OPENTABLES: net_store_data(&packet2,(uint32) cached_tables()); break; From bcacfe28a3f71326566f715cda97507ad387971a Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Tue, 7 Jan 2003 18:53:46 -0800 Subject: [PATCH 06/48] Protocol conversion tests --- tests/client_test.c | 1060 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1015 insertions(+), 45 deletions(-) diff --git a/tests/client_test.c b/tests/client_test.c index d5e13dd3b43..b31268376ef 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -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; } /******************************************************** @@ -388,7 +383,8 @@ 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); @@ -404,9 +400,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 +1192,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 +1220,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); } @@ -2603,6 +2623,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 +2633,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 +2650,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 +2673,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 +4437,12 @@ static void test_func_fields() mysql_free_result(result); } +/* Multiple stmts .. */ +static void test_multi_stmt() +{ +} + + static struct my_option myctest_long_options[] = { {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, @@ -3586,13 +4550,18 @@ 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_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 */ @@ -3618,7 +4587,7 @@ int main(int argc, char **argv) test_select(); test_select_show(); test_null(); /* test null data handling */ - test_simple_update(); + test_simple_update(); /* simple prepare - update */ test_prepare_resultset(); test_prepare_noparam();/* prepare without parameters */ test_select(); /* simple prepare-select */ @@ -3643,7 +4612,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 +4625,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"); From c22219563a441fb3f5131619befa768b55529283 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Tue, 7 Jan 2003 18:57:39 -0800 Subject: [PATCH 07/48] Code cleaup to fix the conversion routines - binary protocol --- include/mysql.h | 4 +-- libmysql/libmysql.c | 80 ++++++++++++++++++--------------------------- 2 files changed, 34 insertions(+), 50 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index e43136f8f69..d9da2bde73c 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 */ @@ -511,6 +510,7 @@ MYSQL_RES *STDCALL mysql_prepare_result(MYSQL_STMT *stmt); #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/libmysql/libmysql.c b/libmysql/libmysql.c index 5cae0a3813d..4425d41f85f 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4097,8 +4097,7 @@ 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 || - *param->length == MYSQL_NULL_DATA) + if (param->is_null || *param->length == MYSQL_NULL_DATA) store_param_null(net, param); else { @@ -4190,7 +4189,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->is_long_data || *param->length == MYSQL_LONG_DATA) { if (!param->long_ended) DBUG_RETURN(MYSQL_NEED_DATA); @@ -4281,7 +4280,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->is_null= 1; break; case MYSQL_TYPE_TINY: param->bind_length= 1; @@ -4412,41 +4411,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 +4470,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 +4509,64 @@ 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; - *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,NULL,10); + *buffer= data; break; + } case MYSQL_TYPE_SHORT: { - short data= (short)sint2korr(value); + short data= (short)my_strntol(system_charset_info,value,length,NULL,10); int2store(buffer, data); break; } case MYSQL_TYPE_LONG: { - int32 data= (int32)sint4korr(value); + int32 data= (int32)my_strntol(system_charset_info,value,length,NULL,10); int4store(buffer, data); break; } case MYSQL_TYPE_LONGLONG: { - longlong data= sint8korr(value); + longlong data= my_strntoll(system_charset_info,value,length,NULL,10); int8store(buffer, data); break; } case MYSQL_TYPE_FLOAT: { - float data; - float4get(data, value); + float data = (float)my_strntod(system_charset_info,value,length,NULL); float4store(buffer, data); break; } case MYSQL_TYPE_DOUBLE: { - double data; - float8get(data, value); + double data= my_strntod(system_charset_info,value,length,NULL); 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; @@ -4813,27 +4803,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 +4826,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 +4835,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); From 79dd162ed111b2329f41a870983c5474f9921b21 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Tue, 7 Jan 2003 18:59:08 -0800 Subject: [PATCH 08/48] Simple misc cases - warnings --- mysql-test/r/create.result | 2 +- mysql-test/r/warnings.result | 17 +++++++++++++++++ mysql-test/t/create.test | 2 +- mysql-test/t/warnings.test | 7 +++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index a32d32a4ab7..ea553b5ac58 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; 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/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; From 89ef355b9e8844d6da47da788adcf2249ee8fa77 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Wed, 8 Jan 2003 11:24:39 +0200 Subject: [PATCH 09/48] Fix for bug in LOAD DATA INFILE and replication Fix for SHOW VARIABLES in embedded server --- Docs/internals.texi | 73 ++++++++++++++++++++++++++++++++++++++++++++- configure.in | 2 +- sql/log_event.cc | 56 ++++++++++++++++++++++++++++++---- sql/log_event.h | 5 ++-- sql/slave.cc | 6 ---- sql/sql_show.cc | 2 ++ 6 files changed, 129 insertions(+), 15 deletions(-) diff --git a/Docs/internals.texi b/Docs/internals.texi index 6719bd4a6fa..a94158f84f8 100644 --- a/Docs/internals.texi +++ b/Docs/internals.texi @@ -96,13 +96,84 @@ cached for each user/database combination. Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in a @code{HEAP} table. (This is a very quick in-memory table with hash index.) -@item Join Row Cache +@item Join buffer Cache For every full join in a @code{SELECT} statement (a full join here means there were no keys that one could use to find the next table in a list), the found rows are cached in a join cache. One @code{SELECT} query can use many join caches in the worst case. @end table +@node join_buffer_size, flush tables, caching, Top +@subchapter How MySQL uses the join_buffer cache + +Basic information about @code{join_buffer_size}: + +@itemize @bullet +@item +It's only used in the case when join type is of type @code{ALL} or +@code{index}; In other words: no possible keys can be used. +@item +A join buffer is never allocated for the first not-const table, +even it it would be of type @code{ALL}/@code{index}. +@item +The buffer is allocated when we need to do a each full join between two +tables and freed after the query is done. +@item +Accepted row combinations of tables before the @code{ALL}/@code{index} +able is stored in the cache and is used to compare against each read +row in the @code{ALL} table. +@item +We only store the used fields in the join_buffer cache, not the +whole rows. +@end itemize + +Assume you have the following join: + +@example +Table name Type +t1 range +t2 ref +t3 @code{ALL} +@end example + +The join is then done as follows: + +@example +- While rows in t1 matching range + - Read through all rows in t2 according to reference key + - Store used fields form t1,t2 in cache + - If cache is full + - Read through all rows in t3 + - Compare t3 row against all t1,t2 combination in cache + - If rows satisfying join condition, send it to client + - Empty cache + +- Read through all rows in t3 + - Compare t3 row against all stored t1,t2 combinations in cache + - If rows satisfying join condition, send it to client +@end example + +The above means that table t3 is scanned + +@example +(size-of-stored-row(t1,t2) * accepted-row-cominations(t1,t2))/ +join_buffer_size+1 +@end example +times. + +Some conclusions: + +@itemize @bullet +@item +The larger the join_buff_size, the fewer scans of t3. +If @code{join_buff_size} is already large enough to hold all previous row +combinations then there is no speed to gain by making it bigger. +@item +If there is several tables of @code{ALL}/@code{index} then the we +allocate one @code{join_buffer_size buffer} for each of them and use the +same algorithm described above to handle it. (In other words, we store +the same row combination several times into different buffers) +@end itemize @node flush tables, filesort, caching, Top @chapter How MySQL Handles @code{FLUSH TABLES} diff --git a/configure.in b/configure.in index 0375cc61235..06dc6e03fb6 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.8-gamma) +AM_INIT_AUTOMAKE(mysql, 4.0.9-gamma) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 diff --git a/sql/log_event.cc b/sql/log_event.cc index d451a5bc46c..3c2c2fd27b1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -206,7 +206,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()); @@ -1773,8 +1785,34 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) return Log_event::exec_event(rli); } +/* + Does the data loading job when executing a LOAD DATA on the slave -int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) + 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); @@ -1836,8 +1874,12 @@ 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; @@ -1877,7 +1919,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) ); } @@ -2132,7 +2174,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 69a70d535ec..5b9f30b3afd 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -417,9 +417,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 diff --git a/sql/slave.cc b/sql/slave.cc index 455b574b355..b8689a28a54 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2343,12 +2343,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_show.cc b/sql/sql_show.cc index a11abf75506..04d3f13a8d0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1217,6 +1217,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_RPL_STATUS: net_store_data(&packet2, rpl_status_type[(int)rpl_status]); break; +#ifndef EMBEDDED_LIBRARY case SHOW_SLAVE_RUNNING: { LOCK_ACTIVE_MI; @@ -1226,6 +1227,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, UNLOCK_ACTIVE_MI; break; } +#endif case SHOW_OPENTABLES: net_store_data(&packet2,(uint32) cached_tables()); break; From 6cd2eaee1fd9e69750939217db9db04a6d998a90 Mon Sep 17 00:00:00 2001 From: "jani@hynda.(none)" <> Date: Wed, 8 Jan 2003 15:43:56 +0200 Subject: [PATCH 10/48] Fixed a couple of bugs. --- extra/mysql_waitpid.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extra/mysql_waitpid.c b/extra/mysql_waitpid.c index 6e307209fda..14d3f893c60 100644 --- a/extra/mysql_waitpid.c +++ b/extra/mysql_waitpid.c @@ -5,9 +5,9 @@ #include #include -static const char *VER= "1.0"; +static const char *VER= "1.1"; static char *progname; -static int verbose= 0; +static my_bool verbose; void usage(void); @@ -18,8 +18,8 @@ static struct my_option my_long_options[] = {"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.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + "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} @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) if (!argv[0] || !argv[1] || (pid= atoi(argv[0])) <= 0 || (t= atoi(argv[1])) <= 0) usage(); - for (; t >= 0; t--) + for (; t > 0; t--) { if (kill((pid_t) pid, sig)) { From e98e8106642fb6998922819d6542a24c8c088d6a Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Wed, 8 Jan 2003 19:40:35 +0100 Subject: [PATCH 11/48] ft_nlq_search.c: no _mi_search_next() bug fixed --- myisam/ft_nlq_search.c | 1 + 1 file changed, 1 insertion(+) diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 8c5d504b8d5..95ff700f815 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) { From 3c08da957e58937ead92a7609e67d2234fe76676 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Thu, 9 Jan 2003 02:19:14 +0200 Subject: [PATCH 12/48] Don't count NULL values in cardinalty for MyISAM tables. Free row buffer cache after each query for MyISAM tables. Added table join option FORCE INDEX Fixed core dump bug when connecting with hostname that could not be resolved. --- include/my_base.h | 1 + myisam/mi_check.c | 3 ++- myisam/mi_extra.c | 5 ++++ myisam/mi_open.c | 14 +++++++--- myisam/mi_search.c | 47 +++++++++++++++++++++++++------- myisam/myisamdef.h | 4 +-- mysql-test/r/myisam.result | 44 +++++++++++++++++++++++++++++- mysql-test/t/myisam.test | 26 +++++++++++++++++- sql/lex.h | 1 + sql/mysql_priv.h | 6 ++++- sql/opt_range.cc | 4 ++- sql/sql_base.cc | 6 +++-- sql/sql_lex.h | 2 +- sql/sql_parse.cc | 36 +++++++++++++++++++------ sql/sql_select.cc | 3 ++- sql/sql_yacc.yy | 55 ++++++++++++++++++++++++-------------- sql/table.h | 2 ++ 17 files changed, 207 insertions(+), 52 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index bcb8c8d6a2f..feb5259ef08 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -263,6 +263,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/myisam/mi_check.c b/myisam/mi_check.c index 540f3c92ad3..b65e963bcb7 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; - _mi_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,SEARCH_FIND, + _mi_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 aeacf81d90a..0da5ebabf40 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -559,28 +559,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 d57fd1bb5b2..41d53e76241 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 _mi_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 _mi_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; @@ -695,13 +697,29 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, } - /* - ** 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 - */ +/* + Compare two keys + + SYNOPSIS + _mi_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)) @@ -738,6 +756,15 @@ int _mi_key_cmp(register MI_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 */ } diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 07744e11e5f..601a9a40aea 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -358,7 +358,7 @@ struct st_myisam_info { #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 */ @@ -529,7 +529,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/r/myisam.result b/mysql-test/r/myisam.result index 4a0eb47efb7..3a3558eedcb 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) @@ -318,3 +318,45 @@ 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; +table type possible_keys key key_len ref rows Extra +t1 ALL a NULL NULL NULL 5 +t2 ALL a NULL NULL NULL 2 Using where +explain select * from t1,t2 force index(a) where t1.a=t2.a; +table type possible_keys key key_len ref rows Extra +t2 ALL a NULL NULL NULL 2 +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; +table type possible_keys key key_len ref rows Extra +t2 ALL a NULL NULL NULL 2 +t1 ref a a 4 t2.a 3 +explain select * from t1,t2 where t1.b=t2.b; +table type possible_keys key key_len ref rows Extra +t2 ALL b NULL NULL NULL 2 +t1 ref b b 5 t2.b 1 Using where +explain select * from t1,t2 force index(c) where t1.a=t2.a; +table type possible_keys key key_len ref rows Extra +t1 ALL a NULL NULL NULL 5 +t2 ALL NULL NULL NULL NULL 2 Using where +explain select * from t1 where a=0 or a=2; +table type possible_keys key key_len ref rows Extra +t1 ALL a NULL NULL NULL 5 Using where +explain select * from t1 force index (a) where a=0 or a=2; +table type possible_keys key key_len ref rows Extra +t1 range a a 4 NULL 4 Using where +drop table t1,t2; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 1265d809149..c96a21e73dd 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -2,7 +2,13 @@ # Test bugs in the MyISAM code # -drop table if exists t1; +# Initialise +drop table if exists t1,t2; + +# +# Test problem with CHECK TABLE; +# + CREATE TABLE t1 ( STRING_DATA char(255) default NULL, KEY STRING_DATA (STRING_DATA) @@ -326,3 +332,21 @@ 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; +drop table t1,t2; diff --git a/sql/lex.h b/sql/lex.h index 826b9b4a9ef..82ed322af83 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -151,6 +151,7 @@ static SYMBOL symbols[] = { { "FLOAT8", SYM(DOUBLE_SYM),0,0}, { "FLUSH", SYM(FLUSH_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/mysql_priv.h b/sql/mysql_priv.h index 2a8b263bf28..75bf4e97634 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -226,6 +226,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 @@ -509,7 +513,7 @@ bool add_field_to_list(char *field_name, enum enum_field_types type, void store_position_for_column(const char *name); bool add_to_list(SQL_LIST &list,Item *group,bool asc=0); TABLE_LIST *add_table_to_list(Table_ident *table,LEX_STRING *alias, - bool updating, + ulong table_option, thr_lock_type flags=TL_UNLOCK, List *use_index=0, List *ignore_index=0); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index a18c0178b5d..c607e71c01b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -605,12 +605,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) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7b7c8c01aab..54c3e40244a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -752,7 +752,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; @@ -910,7 +910,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; @@ -981,6 +981,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; @@ -1888,6 +1889,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_lex.h b/sql/sql_lex.h index 54e72fafdd5..a905871e629 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -110,7 +110,7 @@ typedef struct st_select_lex char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */ Item *where,*having; ha_rows select_limit,offset_limit; - ulong options; + ulong options, table_join_options; List expr_list; List when_list; SQL_LIST order_list,table_list,group_list; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a0336d0b50b..5bf3a1c0bcd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -498,7 +498,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); } @@ -3158,12 +3159,30 @@ bool add_to_list(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 *add_table_to_list(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 - ) + List *ignore_index) { register TABLE_LIST *ptr; THD *thd=current_thd; @@ -3211,8 +3230,9 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, } 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); if (use_index) ptr->use_index=(List *) thd->memdup((gptr) use_index, sizeof(*use_index)); @@ -3221,7 +3241,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, sizeof(*ignore_index)); /* check that used name is unique */ - if (flags != TL_IGNORE) + if (lock_type != TL_IGNORE) { for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ; tables ; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 28aa21e94ce..237197ba6be 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2057,7 +2057,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) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e26e57b8bbd..0e93f048406 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 @@ -198,6 +198,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 @@ -735,7 +736,8 @@ create: lex->sql_command= SQLCOM_CREATE_TABLE; if (!add_table_to_list($5, ($2 & HA_LEX_CREATE_TMP_TABLE ? - &tmp_table_alias : (LEX_STRING*) 0),1)) + &tmp_table_alias : (LEX_STRING*) 0), + TL_OPTION_UPDATING)) YYABORT; lex->create_list.empty(); lex->key_list.empty(); @@ -751,7 +753,7 @@ create: { LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_INDEX; - if (!add_table_to_list($6,NULL,1)) + if (!add_table_to_list($6, NULL, TL_OPTION_UPDATING)) YYABORT; lex->create_list.empty(); lex->key_list.empty(); @@ -1171,7 +1173,7 @@ alter: LEX *lex=Lex; lex->sql_command = SQLCOM_ALTER_TABLE; lex->name=0; - if (!add_table_to_list($4, NULL,1)) + if (!add_table_to_list($4, NULL, TL_OPTION_UPDATING)) YYABORT; lex->drop_primary=0; lex->create_list.empty(); @@ -1442,8 +1444,9 @@ table_to_table_list: table_to_table: table_ident TO_SYM table_ident - { if (!add_table_to_list($1,NULL,1,TL_IGNORE) || - !add_table_to_list($3,NULL,1,TL_IGNORE)) + { + if (!add_table_to_list($1, NULL, TL_OPTION_UPDATING, TL_IGNORE) || + !add_table_to_list($3, NULL, TL_OPTION_UPDATING, TL_IGNORE)) YYABORT; }; @@ -2127,11 +2130,13 @@ join_table: { SELECT_LEX *sel=Select; sel->use_index_ptr=sel->ignore_index_ptr=0; + sel->table_join_options= 0; } table_ident opt_table_alias opt_key_definition { SELECT_LEX *sel=Select; - if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, sel->use_index_ptr, + if (!($$=add_table_to_list($2, $3, sel->table_join_options, + TL_UNLOCK, sel->use_index_ptr, sel->ignore_index_ptr))) YYABORT; } @@ -2150,12 +2155,20 @@ opt_key_definition: sel->use_index= *$2; sel->use_index_ptr= &sel->use_index; } + | FORCE_SYM key_usage_list + { + SELECT_LEX *sel=Select; + 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; sel->ignore_index= *$2; sel->ignore_index_ptr= &sel->ignore_index; - }; + } + ; key_usage_list: key_or_index { Select->interval_list.empty(); } '(' key_usage_list2 ')' @@ -2443,7 +2456,7 @@ drop: lex->drop_list.empty(); lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, $3.str)); - if (!add_table_to_list($5,NULL, 1)) + if (!add_table_to_list($5, NULL, TL_OPTION_UPDATING)) YYABORT; } | DROP DATABASE if_exists ident @@ -2467,7 +2480,7 @@ table_list: table_name: table_ident - { if (!add_table_to_list($1,NULL,1)) YYABORT; }; + { if (!add_table_to_list($1,NULL,TL_OPTION_UPDATING)) YYABORT; }; if_exists: /* empty */ { $$= 0; } @@ -2678,7 +2691,8 @@ delete: single_multi: FROM table_ident { - if (!add_table_to_list($2, NULL, 1, Lex->lock_option)) + if (!add_table_to_list($2, NULL, TL_OPTION_UPDATING, + Lex->lock_option)) YYABORT; } where_clause opt_order_clause @@ -2699,13 +2713,14 @@ table_wild_list: table_wild_one: ident opt_wild { - if (!add_table_to_list(new Table_ident($1), NULL, 1, - Lex->lock_option)) + if (!add_table_to_list(new Table_ident($1), NULL, + TL_OPTION_UPDATING, Lex->lock_option)) YYABORT; } | ident '.' ident opt_wild { - if (!add_table_to_list(new Table_ident($1,$3,0), NULL, 1, + if (!add_table_to_list(new Table_ident($1,$3,0), NULL, + TL_OPTION_UPDATING, Lex->lock_option)) YYABORT; } @@ -2774,7 +2789,7 @@ show_param: Lex->sql_command= SQLCOM_SHOW_FIELDS; if ($5) $4->change_db($5); - if (!add_table_to_list($4,NULL,0)) + if (!add_table_to_list($4, NULL, 0)) YYABORT; } | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ @@ -2807,7 +2822,7 @@ show_param: Lex->sql_command= SQLCOM_SHOW_KEYS; if ($4) $3->change_db($4); - if (!add_table_to_list($3,NULL,0)) + if (!add_table_to_list($3, NULL, 0)) YYABORT; } | STATUS_SYM wild @@ -2834,7 +2849,7 @@ show_param: | CREATE TABLE_SYM table_ident { Lex->sql_command = SQLCOM_SHOW_CREATE; - if(!add_table_to_list($3, NULL,0)) + if(!add_table_to_list($3, NULL, 0)) YYABORT; } | MASTER_SYM STATUS_SYM @@ -2879,7 +2894,7 @@ describe: lex->wild=0; lex->verbose=0; lex->sql_command=SQLCOM_SHOW_FIELDS; - if (!add_table_to_list($2, NULL,0)) + if (!add_table_to_list($2, NULL, 0)) YYABORT; } opt_describe_column {} @@ -2999,14 +3014,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 (!add_table_to_list($11,NULL,1)) + if (!add_table_to_list($11, NULL, TL_OPTION_UPDATING)) YYABORT; } | LOAD TABLE_SYM table_ident FROM MASTER_SYM { Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE; - if (!add_table_to_list($3,NULL,1)) + if (!add_table_to_list($3, NULL, TL_OPTION_UPDATING)) YYABORT; } diff --git a/sql/table.h b/sql/table.h index 3a08cd11a2a..c3f469115b5 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; @@ -157,6 +158,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; From a10178493005b3fa69163ef39c6a58fe9ff6658b Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Thu, 9 Jan 2003 03:12:17 +0200 Subject: [PATCH 13/48] Add TYPE as an alias for specifying key type --- sql/sql_yacc.yy | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bcee15c13cf..77325bad3a0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1356,6 +1356,7 @@ opt_unique_or_fulltext: key_alg: /* empty */ { $$= HA_KEY_ALG_UNDEF; } | USING opt_btree_or_rtree { $$= $2; }; + | TYPE opt_btree_or_rtree { $$= $2; }; opt_btree_or_rtree: BTREE_SYM { $$= HA_KEY_ALG_BTREE; } From bf683af4cea9a9efc3e524d5aabde4886e93540f Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Thu, 9 Jan 2003 22:42:31 +0200 Subject: [PATCH 14/48] Post merge fix Allow empty key list in USE|IGNORE|FORCE INDEX() --- mysql-test/r/myisam.result | 44 ++++++++++--------- mysql-test/t/myisam.test | 2 + mysys/my_handler.c | 87 ++++++++++++++++++++++---------------- sql/sql_lex.cc | 8 +++- sql/sql_lex.h | 4 +- sql/sql_parse.cc | 28 ++++++++++-- sql/sql_yacc.yy | 23 +++++++--- 7 files changed, 129 insertions(+), 67 deletions(-) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 3d4b1dbd46d..23610be36c4 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -332,29 +332,35 @@ 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; -table type possible_keys key key_len ref rows Extra -t1 ALL a NULL NULL NULL 5 -t2 ALL a NULL NULL NULL 2 Using where +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; -table type possible_keys key key_len ref rows Extra -t2 ALL a NULL NULL NULL 2 -t1 ALL a NULL NULL NULL 5 Using where +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; -table type possible_keys key key_len ref rows Extra -t2 ALL a NULL NULL NULL 2 -t1 ref a a 4 t2.a 3 +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; -table type possible_keys key key_len ref rows Extra -t2 ALL b NULL NULL NULL 2 -t1 ref b b 5 t2.b 1 Using where +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; -table type possible_keys key key_len ref rows Extra -t1 ALL a NULL NULL NULL 5 -t2 ALL NULL NULL NULL NULL 2 Using where +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; -table type possible_keys key key_len ref rows Extra -t1 ALL a NULL NULL NULL 5 Using where +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; -table type possible_keys key key_len ref rows Extra -t1 range a a 4 NULL 4 Using where +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/t/myisam.test b/mysql-test/t/myisam.test index 7b541d98cef..ed08b1cbacb 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -349,4 +349,6 @@ 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/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/sql/sql_lex.cc b/sql/sql_lex.cc index c7595c7ec5c..d22d5b8e0af 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1171,13 +1171,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 @@ -1334,6 +1335,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 b32e4489b01..4b6ac927f07 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -243,7 +243,7 @@ public: virtual List* get_item_list(); virtual List* get_use_index(); virtual List* get_ignore_index(); - virtual ulong table_join_options(); + virtual ulong get_table_join_options(); virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_options, @@ -375,7 +375,7 @@ public: List* get_item_list(); List* get_use_index(); List* get_ignore_index(); - ulong table_join_options(); + ulong get_table_join_options(); TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_options, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ce8bd41d3a6..81fb5a6d12c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3598,11 +3598,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) { @@ -3659,8 +3678,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, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 106fa61e535..79cadff3cc1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1359,7 +1359,7 @@ opt_unique_or_fulltext: key_alg: /* empty */ { $$= HA_KEY_ALG_UNDEF; } | USING opt_btree_or_rtree { $$= $2; }; - | TYPE opt_btree_or_rtree { $$= $2; }; + | TYPE_SYM opt_btree_or_rtree { $$= $2; }; opt_btree_or_rtree: BTREE_SYM { $$= HA_KEY_ALG_BTREE; } @@ -2516,14 +2516,14 @@ join_table: { SELECT_LEX *sel= Select->select_lex(); sel->use_index_ptr=sel->ignore_index_ptr=0; - sel->table_join_ptions= 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, - lex->table_join_options(), + sel->get_table_join_options(), lex->lock_option, sel->get_use_index(), sel->get_ignore_index()))) @@ -2569,6 +2569,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(); @@ -2578,8 +2585,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 From 045b2f233601167cb25ff8da0d964d3333f248eb Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Thu, 9 Jan 2003 17:56:34 -0800 Subject: [PATCH 15/48] Remove/change unwanted variables in client protocol Add missed mysql_stmt_affected_rows() sql_yacc.yy : Fix the compilation error .. bison 1.75 --- include/mysql.h | 14 +++++++------- libmysql/libmysql.c | 30 ++++++++++++++++++++++-------- sql/sql_prepare.cc | 5 ++++- sql/sql_yacc.yy | 2 +- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index d9da2bde73c..ce321f5b5ea 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -501,16 +501,16 @@ 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); /* 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_LONG_DATA (-2) +#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/libmysql/libmysql.c b/libmysql/libmysql.c index 4425d41f85f..7757050aad7 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4097,7 +4097,8 @@ 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->length == MYSQL_NULL_DATA) + if (param->buffer_type == MYSQL_TYPE_NULL || + *param->length == MYSQL_NULL_DATA) store_param_null(net, param); else { @@ -4189,7 +4190,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 || *param->length == MYSQL_LONG_DATA) + if (*param->length == MYSQL_LONG_DATA) { if (!param->long_ended) DBUG_RETURN(MYSQL_NEED_DATA); @@ -4224,6 +4225,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 @@ -4257,7 +4266,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)) { @@ -4280,7 +4289,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; @@ -4688,7 +4697,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; @@ -4788,6 +4797,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); @@ -4914,9 +4928,9 @@ int STDCALL mysql_fetch(MYSQL_STMT *stmt) mysql->status= MYSQL_STATUS_READY; if (res < 0) /* Network error */ { - set_stmt_errmsg(stmt,(char *)mysql->net.last_error, - mysql->net.last_errno); - DBUG_RETURN(MYSQL_STATUS_ERROR); + set_stmt_errmsg(stmt,(char *)mysql->net.last_error, + mysql->net.last_errno); + DBUG_RETURN(1); } DBUG_PRINT("info", ("end of data")); DBUG_RETURN(MYSQL_NO_DATA); /* no more data */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 93004ce2937..092f7c7a497 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -321,9 +321,12 @@ 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++; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8fa17f0d5ed..0985859caae 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1382,7 +1382,7 @@ 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: From 492eba0369bf7306c2058ec17fdd53f92d0982a0 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Thu, 9 Jan 2003 18:32:08 -0800 Subject: [PATCH 16/48] Added prepared statements sample from manual as a test --- tests/client_test.c | 202 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 177 insertions(+), 25 deletions(-) diff --git a/tests/client_test.c b/tests/client_test.c index b31268376ef..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 ) ***************************************************************************/ @@ -364,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; @@ -390,6 +390,8 @@ uint my_process_stmt_result(MYSQL_STMT *stmt) 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 @@ -1591,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]; @@ -1626,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); @@ -1699,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]; @@ -1732,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); @@ -1798,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]; @@ -1830,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; @@ -1894,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); @@ -1910,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]; @@ -1943,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); @@ -4442,6 +4449,155 @@ 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[] = { @@ -4552,6 +4708,7 @@ int main(int argc, char **argv) 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(); /* to fetch date,time and timestamp */ @@ -4566,9 +4723,9 @@ int main(int argc, char **argv) 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 */ @@ -4576,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(); /* simple prepare - update */ - test_prepare_resultset(); test_prepare_noparam();/* prepare without parameters */ test_select(); /* simple prepare-select */ test_insert(); /* prepare with insert */ From 192ad598198647023f2c2a8e8f5b23d02618afed Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 10 Jan 2003 16:34:53 +0400 Subject: [PATCH 17/48] xml.c: new file --- strings/xml.c | 374 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 strings/xml.c diff --git a/strings/xml.c b/strings/xml.c new file mode 100644 index 00000000000..4f6301249ae --- /dev/null +++ b/strings/xml.c @@ -0,0 +1,374 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "my_global.h" +#include "m_string.h" +#include "my_xml.h" + + +#define MY_XML_EOF 'E' +#define MY_XML_STRING 'S' +#define MY_XML_IDENT 'I' +#define MY_XML_EQ '=' +#define MY_XML_LT '<' +#define MY_XML_GT '>' +#define MY_XML_SLASH '/' +#define MY_XML_COMMENT 'C' +#define MY_XML_TEXT 'T' +#define MY_XML_QUESTION '?' +#define MY_XML_EXCLAM '!' + +typedef struct xml_attr_st +{ + const char *beg; + const char *end; +} MY_XML_ATTR; + +static const char *lex2str(int lex) +{ + switch(lex) + { + case MY_XML_EOF: return "EOF"; + case MY_XML_STRING: return "STRING"; + case MY_XML_IDENT: return "IDENT"; + case MY_XML_EQ: return "'='"; + case MY_XML_LT: return "'<'"; + case MY_XML_GT: return "'>'"; + case MY_XML_SLASH: return "'/'"; + case MY_XML_COMMENT: return "COMMENT"; + case MY_XML_TEXT: return "TEXT"; + case MY_XML_QUESTION: return "'?'"; + case MY_XML_EXCLAM: return "'!'"; + } + return "UNKNOWN"; +} + +static void my_xml_norm_text(MY_XML_ATTR *a) +{ + for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->beg[0]) ; a->beg++ ); + for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->end[-1]) ; a->end-- ); +} + + +static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a) +{ + int lex; + + for( ; ( p->cur < p->end) && strchr(" \t\r\n",p->cur[0]) ; p->cur++); + + if (p->cur >= p->end) + { + a->beg=p->end; + a->end=p->end; + lex=MY_XML_EOF; + goto ret; + } + + a->beg=p->cur; + a->end=p->cur; + + if (!memcmp(p->cur,"", 3); p->cur++); + if(!memcmp(p->cur, "-->", 3)) + p->cur+=3; + a->end=p->cur; + lex=MY_XML_COMMENT; + } + else if (strchr("?=/<>!",p->cur[0])) + { + p->cur++; + a->end=p->cur; + lex=a->beg[0]; + } + else if ( (p->cur[0]=='"') || (p->cur[0]=='\'') ) + { + p->cur++; + for( ; ( p->cur < p->end ) && (p->cur[0]!=a->beg[0]); p->cur++); + a->end=p->cur; + if (a->beg[0]==p->cur[0])p->cur++; + a->beg++; + my_xml_norm_text(a); + lex=MY_XML_STRING; + } + else + { + for( ; (p->cur < p->end) && !strchr("?'\"=/<> \t\r\n", p->cur[0]); p->cur++); + a->end=p->cur; + my_xml_norm_text(a); + lex=MY_XML_IDENT; + } + +#if 0 + printf("LEX=%s[%d]\n",lex2str(lex),a->end-a->beg); +#endif + +ret: + return lex; +} + + +static int my_xml_value(MY_XML_PARSER *st, const char *str, uint len) +{ + return (st->value) ? (st->value)(st,str,len) : MY_XML_OK; +} + + +static int my_xml_enter(MY_XML_PARSER *st, const char *str, uint len) +{ + if ( (st->attrend-st->attr+len+1)>sizeof(st->attr)) + { + sprintf(st->errstr,"To deep XML"); + return MY_XML_ERROR; + } + if (st->attrend > st->attr) + { + st->attrend[0]='.'; + st->attrend++; + } + memcpy(st->attrend,str,len); + st->attrend+=len; + st->attrend[0]='\0'; + return st->enter ? st->enter(st,st->attr,st->attrend-st->attr) : MY_XML_OK; +} + +static void mstr(char *s,const char *src,uint l1, uint l2) +{ + l1 = l1attrend; (e>p->attr) && (e[0]!='.') ; e--); + glen = (e[0]=='.') ? (p->attrend-e-1) : p->attrend-e; + + if (str && (slen != glen)) + { + mstr(s,str,sizeof(s)-1,slen); + mstr(g,e+1,sizeof(g)-1,glen), + sprintf(p->errstr,"'' unexpected ('' wanted)",s,g); + return MY_XML_ERROR; + } + + rc = p->leave ? p->leave(p,p->attr,p->attrend-p->attr) : MY_XML_OK; + + *e='\0'; + p->attrend=e; + + return rc; +} + + +int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) +{ + p->attrend=p->attr; + p->beg=str; + p->cur=str; + p->end=str+len; + + while ( p->cur < p->end ) + { + MY_XML_ATTR a; + if(p->cur[0]=='<') + { + int lex; + int question=0; + int exclam=0; + + lex=my_xml_scan(p,&a); + + if (MY_XML_COMMENT==lex) + { + continue; + } + + lex=my_xml_scan(p,&a); + + if (MY_XML_SLASH==lex) + { + if(MY_XML_IDENT!=(lex=my_xml_scan(p,&a))) + { + sprintf(p->errstr,"1: %s unexpected (ident wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + if(MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg)) + return MY_XML_ERROR; + lex=my_xml_scan(p,&a); + goto gt; + } + + if (MY_XML_EXCLAM==lex) + { + lex=my_xml_scan(p,&a); + exclam=1; + } + else if (MY_XML_QUESTION==lex) + { + lex=my_xml_scan(p,&a); + question=1; + } + + if (MY_XML_IDENT==lex) + { + if(MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) + return MY_XML_ERROR; + } + else + { + sprintf(p->errstr,"3: %s unexpected (ident or '/' wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + + while ((MY_XML_IDENT==(lex=my_xml_scan(p,&a))) || (MY_XML_STRING==lex)) + { + MY_XML_ATTR b; + if(MY_XML_EQ==(lex=my_xml_scan(p,&b))) + { + lex=my_xml_scan(p,&b); + if ( (lex==MY_XML_IDENT) || (lex=MY_XML_STRING) ) + { + if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || + (MY_XML_OK!=my_xml_value(p,b.beg,b.end-b.beg)) || + (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) + return MY_XML_ERROR; + } + else + { + sprintf(p->errstr,"4: %s unexpected (ident or string wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + } + else if ( (MY_XML_STRING==lex) || (MY_XML_IDENT==lex) ) + { + if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || + (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) + return MY_XML_ERROR; + } + else + break; + } + + if (lex==MY_XML_SLASH) + { + if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + return MY_XML_ERROR; + lex=my_xml_scan(p,&a); + } + +gt: + if (question) + { + if (lex!=MY_XML_QUESTION) + { + sprintf(p->errstr,"6: %s unexpected ('?' wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + return MY_XML_ERROR; + lex=my_xml_scan(p,&a); + } + + if (exclam) + { + if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + return MY_XML_ERROR; + } + + if (lex!=MY_XML_GT) + { + sprintf(p->errstr,"5: %s unexpected ('>' wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + } + else + { + a.beg=p->cur; + for ( ; (p->cur < p->end) && (p->cur[0]!='<') ; p->cur++); + a.end=p->cur; + + my_xml_norm_text(&a); + if (a.beg!=a.end) + { + my_xml_value(p,a.beg,a.end-a.beg); + } + } + } + return MY_XML_OK; +} + +void my_xml_parser_create(MY_XML_PARSER *p) +{ + bzero((void*)p,sizeof(p[0])); +} + +void my_xml_parser_free(MY_XML_PARSER *p __attribute__((unused))) +{ +} + +void my_xml_set_value_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) +{ + p->value=action; +} + +void my_xml_set_enter_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) +{ + p->enter=action; +} + +void my_xml_set_leave_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) +{ + p->leave=action; +} + +void my_xml_set_user_data(MY_XML_PARSER *p, void *user_data) +{ + p->user_data=user_data; +} + +const char *my_xml_error_string(MY_XML_PARSER *p) +{ + return p->errstr; +} + + +uint my_xml_error_pos(MY_XML_PARSER *p) +{ + const char *beg=p->beg; + const char *s; + for ( s=p->beg ; scur; s++) + if (s[0]=='\n') + beg=s; + return p->cur-beg; +} + +uint my_xml_error_lineno(MY_XML_PARSER *p) +{ + uint res=0; + const char *s; + for ( s=p->beg ; scur; s++) + if (s[0]=='\n') + res++; + return res; +} From 04ba0e85f0e5fa619be12870630fa1240cbff649 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 10 Jan 2003 17:01:55 +0400 Subject: [PATCH 18/48] xml.c has been moved to /strings from /mysys This is to reuse code to generate charset related C files from ther descriptions written in XML files --- libmysql/Makefile.shared | 4 ++-- mysys/Makefile.am | 2 +- strings/Makefile.am | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 4d8b703fb2d..1aba7bbed43 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -42,7 +42,7 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.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,7 +58,7 @@ 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_getopt.lo my_gethostbyname.lo my_port.lo diff --git a/mysys/Makefile.am b/mysys/Makefile.am index c8b7987a506..cd823186a2b 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 \ + my_vsnprintf.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/strings/Makefile.am b/strings/Makefile.am index ac0b6d7f1e0..c2684769cff 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 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 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 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 \ From 2f0690e17397759bf67eba49f9b28d5fb0d2d105 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 10 Jan 2003 17:05:17 +0400 Subject: [PATCH 19/48] .del-xml.c~d20ceb97a91fcc2d: Delete: mysys/xml.c xml.c: Rename: BitKeeper/deleted/.del-xml.c~d20ceb97a91fcc2d -> mysys/xml.c It is actually moved to /strings --- mysys/xml.c | 374 ---------------------------------------------------- 1 file changed, 374 deletions(-) delete mode 100644 mysys/xml.c diff --git a/mysys/xml.c b/mysys/xml.c deleted file mode 100644 index 4f6301249ae..00000000000 --- a/mysys/xml.c +++ /dev/null @@ -1,374 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "my_global.h" -#include "m_string.h" -#include "my_xml.h" - - -#define MY_XML_EOF 'E' -#define MY_XML_STRING 'S' -#define MY_XML_IDENT 'I' -#define MY_XML_EQ '=' -#define MY_XML_LT '<' -#define MY_XML_GT '>' -#define MY_XML_SLASH '/' -#define MY_XML_COMMENT 'C' -#define MY_XML_TEXT 'T' -#define MY_XML_QUESTION '?' -#define MY_XML_EXCLAM '!' - -typedef struct xml_attr_st -{ - const char *beg; - const char *end; -} MY_XML_ATTR; - -static const char *lex2str(int lex) -{ - switch(lex) - { - case MY_XML_EOF: return "EOF"; - case MY_XML_STRING: return "STRING"; - case MY_XML_IDENT: return "IDENT"; - case MY_XML_EQ: return "'='"; - case MY_XML_LT: return "'<'"; - case MY_XML_GT: return "'>'"; - case MY_XML_SLASH: return "'/'"; - case MY_XML_COMMENT: return "COMMENT"; - case MY_XML_TEXT: return "TEXT"; - case MY_XML_QUESTION: return "'?'"; - case MY_XML_EXCLAM: return "'!'"; - } - return "UNKNOWN"; -} - -static void my_xml_norm_text(MY_XML_ATTR *a) -{ - for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->beg[0]) ; a->beg++ ); - for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->end[-1]) ; a->end-- ); -} - - -static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a) -{ - int lex; - - for( ; ( p->cur < p->end) && strchr(" \t\r\n",p->cur[0]) ; p->cur++); - - if (p->cur >= p->end) - { - a->beg=p->end; - a->end=p->end; - lex=MY_XML_EOF; - goto ret; - } - - a->beg=p->cur; - a->end=p->cur; - - if (!memcmp(p->cur,"", 3); p->cur++); - if(!memcmp(p->cur, "-->", 3)) - p->cur+=3; - a->end=p->cur; - lex=MY_XML_COMMENT; - } - else if (strchr("?=/<>!",p->cur[0])) - { - p->cur++; - a->end=p->cur; - lex=a->beg[0]; - } - else if ( (p->cur[0]=='"') || (p->cur[0]=='\'') ) - { - p->cur++; - for( ; ( p->cur < p->end ) && (p->cur[0]!=a->beg[0]); p->cur++); - a->end=p->cur; - if (a->beg[0]==p->cur[0])p->cur++; - a->beg++; - my_xml_norm_text(a); - lex=MY_XML_STRING; - } - else - { - for( ; (p->cur < p->end) && !strchr("?'\"=/<> \t\r\n", p->cur[0]); p->cur++); - a->end=p->cur; - my_xml_norm_text(a); - lex=MY_XML_IDENT; - } - -#if 0 - printf("LEX=%s[%d]\n",lex2str(lex),a->end-a->beg); -#endif - -ret: - return lex; -} - - -static int my_xml_value(MY_XML_PARSER *st, const char *str, uint len) -{ - return (st->value) ? (st->value)(st,str,len) : MY_XML_OK; -} - - -static int my_xml_enter(MY_XML_PARSER *st, const char *str, uint len) -{ - if ( (st->attrend-st->attr+len+1)>sizeof(st->attr)) - { - sprintf(st->errstr,"To deep XML"); - return MY_XML_ERROR; - } - if (st->attrend > st->attr) - { - st->attrend[0]='.'; - st->attrend++; - } - memcpy(st->attrend,str,len); - st->attrend+=len; - st->attrend[0]='\0'; - return st->enter ? st->enter(st,st->attr,st->attrend-st->attr) : MY_XML_OK; -} - -static void mstr(char *s,const char *src,uint l1, uint l2) -{ - l1 = l1attrend; (e>p->attr) && (e[0]!='.') ; e--); - glen = (e[0]=='.') ? (p->attrend-e-1) : p->attrend-e; - - if (str && (slen != glen)) - { - mstr(s,str,sizeof(s)-1,slen); - mstr(g,e+1,sizeof(g)-1,glen), - sprintf(p->errstr,"'' unexpected ('' wanted)",s,g); - return MY_XML_ERROR; - } - - rc = p->leave ? p->leave(p,p->attr,p->attrend-p->attr) : MY_XML_OK; - - *e='\0'; - p->attrend=e; - - return rc; -} - - -int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) -{ - p->attrend=p->attr; - p->beg=str; - p->cur=str; - p->end=str+len; - - while ( p->cur < p->end ) - { - MY_XML_ATTR a; - if(p->cur[0]=='<') - { - int lex; - int question=0; - int exclam=0; - - lex=my_xml_scan(p,&a); - - if (MY_XML_COMMENT==lex) - { - continue; - } - - lex=my_xml_scan(p,&a); - - if (MY_XML_SLASH==lex) - { - if(MY_XML_IDENT!=(lex=my_xml_scan(p,&a))) - { - sprintf(p->errstr,"1: %s unexpected (ident wanted)",lex2str(lex)); - return MY_XML_ERROR; - } - if(MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg)) - return MY_XML_ERROR; - lex=my_xml_scan(p,&a); - goto gt; - } - - if (MY_XML_EXCLAM==lex) - { - lex=my_xml_scan(p,&a); - exclam=1; - } - else if (MY_XML_QUESTION==lex) - { - lex=my_xml_scan(p,&a); - question=1; - } - - if (MY_XML_IDENT==lex) - { - if(MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) - return MY_XML_ERROR; - } - else - { - sprintf(p->errstr,"3: %s unexpected (ident or '/' wanted)",lex2str(lex)); - return MY_XML_ERROR; - } - - while ((MY_XML_IDENT==(lex=my_xml_scan(p,&a))) || (MY_XML_STRING==lex)) - { - MY_XML_ATTR b; - if(MY_XML_EQ==(lex=my_xml_scan(p,&b))) - { - lex=my_xml_scan(p,&b); - if ( (lex==MY_XML_IDENT) || (lex=MY_XML_STRING) ) - { - if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || - (MY_XML_OK!=my_xml_value(p,b.beg,b.end-b.beg)) || - (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) - return MY_XML_ERROR; - } - else - { - sprintf(p->errstr,"4: %s unexpected (ident or string wanted)",lex2str(lex)); - return MY_XML_ERROR; - } - } - else if ( (MY_XML_STRING==lex) || (MY_XML_IDENT==lex) ) - { - if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || - (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) - return MY_XML_ERROR; - } - else - break; - } - - if (lex==MY_XML_SLASH) - { - if(MY_XML_OK!=my_xml_leave(p,NULL,0)) - return MY_XML_ERROR; - lex=my_xml_scan(p,&a); - } - -gt: - if (question) - { - if (lex!=MY_XML_QUESTION) - { - sprintf(p->errstr,"6: %s unexpected ('?' wanted)",lex2str(lex)); - return MY_XML_ERROR; - } - if(MY_XML_OK!=my_xml_leave(p,NULL,0)) - return MY_XML_ERROR; - lex=my_xml_scan(p,&a); - } - - if (exclam) - { - if(MY_XML_OK!=my_xml_leave(p,NULL,0)) - return MY_XML_ERROR; - } - - if (lex!=MY_XML_GT) - { - sprintf(p->errstr,"5: %s unexpected ('>' wanted)",lex2str(lex)); - return MY_XML_ERROR; - } - } - else - { - a.beg=p->cur; - for ( ; (p->cur < p->end) && (p->cur[0]!='<') ; p->cur++); - a.end=p->cur; - - my_xml_norm_text(&a); - if (a.beg!=a.end) - { - my_xml_value(p,a.beg,a.end-a.beg); - } - } - } - return MY_XML_OK; -} - -void my_xml_parser_create(MY_XML_PARSER *p) -{ - bzero((void*)p,sizeof(p[0])); -} - -void my_xml_parser_free(MY_XML_PARSER *p __attribute__((unused))) -{ -} - -void my_xml_set_value_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) -{ - p->value=action; -} - -void my_xml_set_enter_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) -{ - p->enter=action; -} - -void my_xml_set_leave_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) -{ - p->leave=action; -} - -void my_xml_set_user_data(MY_XML_PARSER *p, void *user_data) -{ - p->user_data=user_data; -} - -const char *my_xml_error_string(MY_XML_PARSER *p) -{ - return p->errstr; -} - - -uint my_xml_error_pos(MY_XML_PARSER *p) -{ - const char *beg=p->beg; - const char *s; - for ( s=p->beg ; scur; s++) - if (s[0]=='\n') - beg=s; - return p->cur-beg; -} - -uint my_xml_error_lineno(MY_XML_PARSER *p) -{ - uint res=0; - const char *s; - for ( s=p->beg ; scur; s++) - if (s[0]=='\n') - res++; - return res; -} From 2430b322ba9dcb23b0e64c417aa96914ae985738 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Fri, 10 Jan 2003 11:18:43 -0800 Subject: [PATCH 20/48] Prepared statements - Doc to be incorporated in manual --- Docs/prepare.texi | 1422 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1422 insertions(+) create mode 100755 Docs/prepare.texi diff --git a/Docs/prepare.texi b/Docs/prepare.texi new file mode 100755 index 00000000000..7a526800213 --- /dev/null +++ b/Docs/prepare.texi @@ -0,0 +1,1422 @@ +\input texinfo @c -*-texinfo-*- +@c Copyright 1997-2002 TcX AB, Detron HB and MySQL Finland AB +@c +@c This manual is NOT distributed under a GPL style license. +@c Use of the manual is subject to the following terms: +@c - Conversion to other formats is allowed, but the actual +@c content may not be altered or edited in any way. +@c - You may create a printed copy for your own personal use. +@c - For all other uses, such as selling printed copies or +@c using (parts of) the manual in another publication, +@c prior written agreement from MySQL AB is required. +@c +@c Please e-mail docs@mysql.com for more information or if +@c you are interested in doing a translation. +@c +@c ********************************************************* +@c Note that @node names are used on our web site. +@c So do not change node names without checking +@c Makefile.am and SitePages first. +@c ********************************************************* +@c +@c %**start of header + +@c there's a better way to do this... i just don't know it yet +@c sed will remove the "@c ifnusphere " to make this valid +@c ifnusphere @set nusphere 1 + +@setfilename prepare.info + +@c We want the types in the same index +@c @syncodeindex tp fn + +@c Get version information. This file is generated by the Makefile!! +@include include.texi + +@ifclear tex-debug +@c This removes the black squares in the right margin +@finalout +@end ifclear + +@c Set background for HTML +@set _body_tags BGCOLOR=#FFFFFF TEXT=#000000 LINK=#101090 VLINK=#7030B0 +@c Set some style elements for the manual in HTML form. 'suggested' +@c natural language colors: aqua, black, blue, fuchsia, gray, green, +@c lime, maroon, navy, olive, purple, red, silver, teal, white, and +@c yellow. From Steeve Buehler +@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 From 0d294e1b64745051c14f17d017f44a9ea005f3ab Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Sat, 11 Jan 2003 00:36:13 -0800 Subject: [PATCH 21/48] Fix to make the tables re-inited for every execute call --- sql/sql_prepare.cc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 092f7c7a497..3907995676f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -628,7 +628,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; @@ -642,6 +642,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), @@ -722,6 +740,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; From 8e6a4c6201ab14414837dcba79cfb4180b92e18d Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Sun, 12 Jan 2003 23:58:56 +0200 Subject: [PATCH 22/48] ut0mem.c, row0sel.c, row0mysql.c, ut0mem.h, row0sel.h, row0mysql.h: Test allocation of memory beforehand if we are trying to return a > 2 MB BLOB; normally InnoDB asserts if memory allocation fails ha_innodb.cc: Do not fetch all columns if change_active_index() is called during a query; a sum(a), max(a) query seemed to do that, doing unnecessary copying (the change actually made in the previous bk ci) Free BLOB heap of handle when MySQL calls some ::extra()'s --- innobase/include/row0mysql.h | 8 ++++++++ innobase/include/row0sel.h | 3 ++- innobase/include/ut0mem.h | 10 ++++++++++ innobase/row/row0mysql.c | 13 +++++++++++++ innobase/row/row0sel.c | 37 +++++++++++++++++++++++++++++++----- innobase/ut/ut0mem.c | 37 +++++++++++++++++++++++++++++++++++- sql/ha_innodb.cc | 34 ++++++++++++++++++++++----------- 7 files changed, 124 insertions(+), 18 deletions(-) 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/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/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0d56f216b3b..cfec8282e42 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1624,6 +1624,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 +1638,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; @@ -2506,11 +2506,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 +3744,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: From de596e897e579c7b70da86d4ff5d8dc7903c9718 Mon Sep 17 00:00:00 2001 From: "ram@mysql.r18.ru" <> Date: Mon, 13 Jan 2003 16:36:04 +0400 Subject: [PATCH 23/48] Fix for spatial objects --- sql/item_strfunc.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7818a23fcd8..963dd6968f4 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2771,10 +2771,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 +2784,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); From 4bf33c022a2ccc113998e9922e92972fe4701964 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 13 Jan 2003 18:20:59 +0200 Subject: [PATCH 24/48] sql_handler.cc: Fix InnoDB HANDLER: InnoDB must know in each call that the handle is used by HANDLER; the previous implementation worked only by pure luck --- sql/sql_handler.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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) { From 63a656c55c20773fb6e0923ddacb00bbb038e804 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 13 Jan 2003 23:25:55 +0200 Subject: [PATCH 25/48] ha_innodb.cc: Added some assertions to make sure index_init is only called with a properly prepared InnoDB table handle --- sql/ha_innodb.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index cfec8282e42..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) { @@ -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) { From a5f77c820b1cc7017035690fbcc58cc913e13c17 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Tue, 14 Jan 2003 11:32:40 +0400 Subject: [PATCH 26/48] Some reorganization to move loading related code to /strings library. This is to reuse code in conf_to_src.c --- mysys/charset.c | 477 +++++++++++++++++++++++++----------------------- 1 file changed, 244 insertions(+), 233 deletions(-) diff --git a/mysys/charset.c b/mysys/charset.c index 8d852fd99c2..4216de67c7e 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -22,17 +22,7 @@ #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 CS_MAX_NM_LEN 32 #define CTYPE_TABLE_SIZE 257 #define TO_LOWER_TABLE_SIZE 256 #define TO_UPPER_TABLE_SIZE 256 @@ -40,38 +30,13 @@ static int charset_initialized=0; #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) +static char *mstr(char *str,const char *src,uint l1,uint l2) { l1= l1like_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)); - - 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); - } -} - - -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) @@ -273,37 +168,16 @@ 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; - 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; - } + switch(state){ + case _CS_COLLATION: + rc= i->add_collation ? i->add_collation(&i->cs) : MY_XML_OK; + break; + default: + rc=MY_XML_OK; } - return MY_XML_OK; + return rc; } @@ -326,14 +200,10 @@ static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) 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; + i->cs.name=mstr(i->name,attr,len,CS_MAX_NM_LEN-1); 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; + case _CS_CSNAME: + i->cs.csname=mstr(i->csname,attr,len,CS_MAX_NM_LEN-1); break; case _CS_FLAG: if (!strncmp("primary",attr,len)) @@ -364,49 +234,6 @@ static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) } -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 +253,30 @@ 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->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; } @@ -563,6 +372,208 @@ 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, + 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); + } +} + + +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; +} + + +static my_bool my_parse_charset_xml(const char *buf, uint len) +{ + 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; +} + + +#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)) + { +#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 +617,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); From 3523650ac8b595b899bffa214efc8bf2893155c5 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Tue, 14 Jan 2003 13:36:22 +0400 Subject: [PATCH 27/48] Charset loading has been moved to /string library --- include/m_ctype.h | 10 +- mysys/charset.c | 241 ++-------------------------------------------- strings/ctype.c | 223 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+), 236 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index 85397796e73..f141e592d8c 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 @@ -145,7 +152,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); diff --git a/mysys/charset.c b/mysys/charset.c index 4216de67c7e..c89e1d60c7e 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -22,217 +22,6 @@ #include -#define CS_MAX_NM_LEN 32 -#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 - - -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; -} - -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; - int (*add_collation)(CHARSET_INFO *cs); -}; - - - -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; - 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; - -#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: - i->cs.name=mstr(i->name,attr,len,CS_MAX_NM_LEN-1); - break; - case _CS_CSNAME: - i->cs.csname=mstr(i->csname,attr,len,CS_MAX_NM_LEN-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,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 void set_max_sort_char(CHARSET_INFO *cs) { @@ -385,23 +174,23 @@ static void simple_cs_copy_data(CHARSET_INFO *to, CHARSET_INFO *from) if (from->ctype) to->ctype= (uchar*) my_once_memdup((char*) from->ctype, - CTYPE_TABLE_SIZE, MYF(MY_WME)); + MY_CS_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)); + MY_CS_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)); + MY_CS_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, + MY_CS_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); + 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); @@ -448,24 +237,6 @@ static int add_collation(CHARSET_INFO *cs) } -static my_bool my_parse_charset_xml(const char *buf, uint len) -{ - 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; -} - - #define MAX_BUF 1024*16 #define MY_CHARSET_INDEX "Index.xml" @@ -490,7 +261,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) len=read(fd,buf,MAX_BUF); my_close(fd,myflags); - if (my_parse_charset_xml(buf,len)) + if (my_parse_charset_xml(buf,len,add_collation)) { #ifdef NOT_YET printf("ERROR at line %d pos %d '%s'\n", diff --git a/strings/ctype.c b/strings/ctype.c index 61fb57d9ac3..c2a7e928493 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -16,6 +16,7 @@ #include #include +#include #ifndef SCO #include #endif @@ -3895,6 +3896,228 @@ static CHARSET_INFO compiled_charsets[] = { }; +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) +{ + 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; + 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; + +#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: + 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]; From 7e9b27eaf5e4add82c98fb8cf87ad68ea72de6a8 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Tue, 14 Jan 2003 14:28:36 +0200 Subject: [PATCH 28/48] Updates for multi-byte character sets (Note: test 'union' fails, but Sanja promised to fix this) --- include/m_ctype.h | 4 +- include/m_string.h | 6 + include/my_sys.h | 3 - libmysql/Makefile.shared | 4 +- mysql-test/r/alter_table.result | 4 +- mysql-test/r/create.result | 12 +- mysql-test/r/ctype_many.result | 8 +- mysql-test/r/fulltext.result | 2 +- mysql-test/r/innodb.result | 2 +- mysql-test/r/merge.result | 2 +- mysql-test/r/select.result | 16 +- mysql-test/r/show_check.result | 14 +- mysql-test/r/type_blob.result | 20 +- mysql-test/r/type_enum.result | 4 +- mysql-test/r/type_ranges.result | 34 +-- mysql-test/r/type_set.result | 4 +- mysys/Makefile.am | 2 +- sql/field.cc | 406 ++++++++++++++---------------- sql/field.h | 5 +- sql/item.cc | 17 +- sql/item.h | 8 +- sql/item_func.cc | 8 +- sql/item_func.h | 2 +- sql/item_strfunc.cc | 3 +- sql/item_sum.cc | 3 +- sql/item_sum.h | 3 +- sql/item_timefunc.cc | 2 +- sql/mysqld.cc | 7 +- sql/opt_range.cc | 2 +- sql/procedure.h | 5 +- sql/sql_class.cc | 6 +- sql/sql_string.cc | 158 ++++++++---- sql/sql_string.h | 1 + sql/sql_update.cc | 1 + strings/Makefile.am | 6 +- strings/ctype-simple.c | 186 ++++++-------- strings/ctype-utf8.c | 32 +-- {mysys => strings}/my_vsnprintf.c | 57 ++++- 38 files changed, 567 insertions(+), 492 deletions(-) rename {mysys => strings}/my_vsnprintf.c (74%) diff --git a/include/m_ctype.h b/include/m_ctype.h index 85397796e73..7f4a13f0fae 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -134,7 +134,7 @@ typedef struct charset_info_st 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); + double (*strntod)(struct charset_info_st *, char *s, uint l, char **e); } CHARSET_INFO; @@ -178,7 +178,7 @@ long my_strntol_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int 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); +double my_strntod_8bit(CHARSET_INFO *, char *s, uint l,char **e); 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); diff --git a/include/m_string.h b/include/m_string.h index c6943613b1a..fabd6c9bb59 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -238,6 +238,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_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/libmysql/Makefile.shared b/libmysql/Makefile.shared index 4d8b703fb2d..08128b3936d 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -37,7 +37,7 @@ 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 \ @@ -60,7 +60,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \ charset.lo xml.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/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..88b9bfce51a 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -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/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/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/mysys/Makefile.am b/mysys/Makefile.am index c8b7987a506..a50dd51a174 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 xml.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/sql/field.cc b/sql/field.cc index 21330a2ffaa..f81f72635b9 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,15 @@ 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) { - 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 +279,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 +289,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 +303,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 +332,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 +349,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 +393,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 +455,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 +463,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 +500,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 +522,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 +540,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 +832,29 @@ int Field_decimal::store(longlong nr) double Field_decimal::val_real(void) { - CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr,field_length,NULL); + return my_strntod(my_charset_bin, ptr, field_length, NULL); } longlong Field_decimal::val_int(void) { - CHARSET_INFO *cs=charset(); if (unsigned_flag) - return my_strntoull(cs,ptr,field_length,NULL,10); + return my_strntoull(my_charset_bin, ptr, field_length, NULL, 10); else - return my_strntoll(cs,ptr,field_length,NULL,10); + return my_strntoll( my_charset_bin, ptr, field_length, NULL, 10); } + 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 +871,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 +901,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 +913,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 +926,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 +942,8 @@ 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); + char *end; + long tmp= my_strntol(cs, from, len, &end,10); int error= 0; if (unsigned_flag) @@ -968,7 +960,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 +980,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,7 +1090,7 @@ 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); @@ -1140,22 +1132,19 @@ 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); + char *end; + long tmp= my_strntol(cs, from, len, &end, 10); int error= 0; if (unsigned_flag) { @@ -1171,7 +1160,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 +1180,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 +1326,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 +1340,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->l10tostr(cs, to, mlength, 10, (long) (uint16) j); else - length=(uint) cs->l10tostr(cs,to,mlength,-10, (long) j); + length=(uint) cs->l10tostr(cs, to, mlength,-10, (long) j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -1414,22 +1403,20 @@ 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); + char *end; + long tmp= my_strntol(cs, from, len, &end, 10); int error= 0; if (unsigned_flag) @@ -1446,7 +1433,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 +1453,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,16 +1559,18 @@ 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); @@ -1632,9 +1621,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,26 +1631,23 @@ 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 @@ -1670,9 +1655,9 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) } else tmp=my_strntol(cs,from,len,&end,10); - if (errno || + if (my_errno || (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; @@ -1817,7 +1802,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); @@ -1896,34 +1881,32 @@ 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 @@ -1931,9 +1914,9 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) } else tmp=my_strntoll(cs,from,len,&end,10); - if (errno || + if (my_errno || (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 +2025,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); @@ -2128,9 +2111,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,8 +2122,8 @@ 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)); + errno=0; // my_strntod() changes errno + Field_float::store(my_strntod(cs,(char*) from,len,(char**)NULL)); if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) { current_thd->cuted_fields++; @@ -2394,18 +2376,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,9 +2395,9 @@ void Field_float::sql_type(String &res) const int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) { - errno=0; + errno=0; // my_strntod() changes errno int error= 0; - double j= my_strntod(cs,from,len,(char**)0); + double j= my_strntod(cs,(char*) from,len,(char**)0); if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) { current_thd->cuted_fields++; @@ -2655,17 +2635,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 +2700,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 +2832,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 +2974,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 +3102,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 +3172,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 +3183,8 @@ 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); + char *end; + long nr= my_strntol(cs, from, len, &end, 10); if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { @@ -3210,7 +3192,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 +3269,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 +3356,7 @@ int Field_date::store(longlong nr) return error; } + bool Field_date::send_binary(Protocol *protocol) { longlong tmp= Field_date::val_int(); @@ -3469,9 +3451,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 +3619,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 +3850,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 +3905,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); } @@ -4118,7 +4094,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); } @@ -4464,22 +4440,23 @@ 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) { char *blob; - memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) return 0.0; @@ -4496,8 +4473,7 @@ longlong Field_blob::val_int(void) 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,NULL,10); } @@ -4507,9 +4483,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 +4543,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); @@ -4695,22 +4672,26 @@ void Field_blob::sort_string(char *to,uint 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); } @@ -5452,8 +5433,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 +5445,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..06a9b534b16 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; @@ -1094,7 +1096,8 @@ 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); +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/item.cc b/sql/item.cc index b0b56bf9101..925ee9ac0f4 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)) { @@ -380,7 +380,8 @@ double Item_param::val() { 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); case INT_RESULT: return (double)int_value; default: @@ -1149,7 +1150,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 +1205,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 @@ -1263,8 +1264,8 @@ void Item_cache_str::store(Item *item) double Item_cache_str::val() { 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); else return (double)0; } diff --git a/sql/item.h b/sql/item.h index 3decdc388eb..907c293d454 100644 --- a/sql/item.h +++ b/sql/item.h @@ -344,7 +344,7 @@ public: enum Type type() const { return STRING_ITEM; } double val() { - return my_strntod(str_value.charset(), str_value.ptr(), + return my_strntod(str_value.charset(), (char*) str_value.ptr(), str_value.length(), (char**) 0); } longlong val_int() @@ -598,7 +598,11 @@ 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); } + { + return (null_value ? 0.0 : + my_strntod(str_value.charset(), (char*) str_value.ptr(), + str_value.length(),NULL)); + } longlong val_int() { return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10); } String *val_str(String*); diff --git a/sql/item_func.cc b/sql/item_func.cc index dcf4638c48a..62cf4c0d291 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -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..11793b11bdb 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -813,7 +813,7 @@ public: double val() { 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) : 0.0; } longlong val_int() { diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7818a23fcd8..2292c6115a0 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -54,7 +54,8 @@ double Item_str_func::val() { 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) : 0.0; } longlong Item_str_func::val_int() diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d78e535010f..b15fceda686 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -341,7 +341,8 @@ double Item_sum_hybrid::val() 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) : 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..ffc9558822d 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -484,7 +484,8 @@ public: double val() { 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) : 0.0; } longlong val_int() { 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/mysqld.cc b/sql/mysqld.cc index f66122e72a6..27c7fb369a1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4665,8 +4665,11 @@ 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); + char *end; + uint length= strlen(argument); + long value= my_strntol(my_charset_latin1, argument, length, &end, 10); + 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); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0adde4d39e0..43066a29624 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2796,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..bc77803230f 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); } + { value=my_strntod(cs,(char*) str,length,(char**)0); } double val() { return value; } longlong val_int() { return (longlong) value; } String *val_str(String *s) { s->set(value,decimals,thd_charset()); return s; } @@ -99,7 +99,8 @@ public: double val() { 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); } longlong val_int() { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ab789370660..4416f5259bd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -526,7 +526,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 +649,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 +857,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_string.cc b/sql/sql_string.cc index 5b84b86c277..4c499af8f9e 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" @@ -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/strings/Makefile.am b/strings/Makefile.am index ac0b6d7f1e0..ac4a994872d 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 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 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 endif endif diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 49801478504..9bcafa9f164 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -110,88 +110,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; } @@ -690,28 +642,48 @@ noconv: 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 pointer to end of converted string + + 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) { - char buf[256]; - double res; - if((l+1)>sizeof(buf)) - { - if (e) - memcpy(*e,s,sizeof(s)); - return 0; - } - strncpy(buf,s,l); - buf[l]='\0'; - res=strtod(buf,e); - if (e) - memcpy(*e,*e-buf+s,sizeof(s)); - return res; + char end_char; + double result; + + if (length == INT_MAX32 || str[length] == 0) + return strtod(str, end); + end_char= str[length]; + str[length]= 0; + result= strtod(str, end); + str[length]= end_char; /* Restore end char */ + 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)), @@ -720,18 +692,19 @@ int my_l10tostr_8bit(CHARSET_INFO *cs __attribute__((unused)), 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 +719,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)), 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 +770,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; } diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 42a70731ab5..4f72a4c2334 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2874,37 +2874,31 @@ bs: double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), - const char *nptr, uint l, char **endptr) + char *nptr, uint length, char **endptr) { 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) + /* 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); + res=strtod(buf, endptr); if (endptr) *endptr=(char*) (*endptr-buf+nptr); return res; 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 */ From 09eac4793bb627bc7cf6db13ca285200bc39be8e Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Tue, 14 Jan 2003 18:28:50 +0400 Subject: [PATCH 29/48] bin chatset now handles strnncoll itself so we don't have to check if charset is binary anymore --- sql/field.cc | 30 ------------------------------ strings/ctype-bin.c | 4 ++-- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index f81f72635b9..467096a4a71 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4017,11 +4017,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); @@ -4036,11 +4031,6 @@ int Field_string::pack_cmp(const char *b, uint length) 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); @@ -4231,11 +4221,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); @@ -4254,11 +4239,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); @@ -4747,11 +4727,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); @@ -4775,11 +4750,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); diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 0d7729721ad..e20afff1470 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)), From 9e9ea3504f70e6e89b77e9128eb9f8f55a06de85 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Tue, 14 Jan 2003 18:00:34 +0200 Subject: [PATCH 30/48] after merging fixing --- include/m_string.h | 3 +++ mysql-test/r/union.result | 2 +- sql/sql_base.cc | 8 ++------ sql/sql_lex.cc | 2 +- sql/sql_lex.h | 1 + sql/sql_yacc.yy | 40 +++++++++++++++++++++++++++++++++++---- 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/include/m_string.h b/include/m_string.h index fabd6c9bb59..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 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/sql/sql_base.cc b/sql/sql_base.cc index a384e723e32..038a286f4df 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1749,12 +1749,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; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index dda3d4e822e..b656f698e89 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -943,7 +943,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() diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4b6ac927f07..e4a17838cd2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -212,6 +212,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) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0985859caae..318d563b88a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3740,17 +3740,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); }; @@ -4535,7 +4559,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); @@ -4547,8 +4572,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: From 5743f94b57b55ee463edb0ac36727f01f1d3e403 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Wed, 15 Jan 2003 18:06:07 +0400 Subject: [PATCH 31/48] All charsets now have strnxfrm. Some function names have been renamed to be more self-descriptive --- include/m_ctype.h | 11 ++--- mysys/charset.c | 1 + sql/field.cc | 20 ++++----- sql/sql_string.cc | 4 +- strings/ctype-big5.c | 6 +-- strings/ctype-bin.c | 15 +++++-- strings/ctype-czech.c | 6 +-- strings/ctype-euc_kr.c | 6 +-- strings/ctype-gb2312.c | 6 +-- strings/ctype-gbk.c | 6 +-- strings/ctype-latin1_de.c | 6 +-- strings/ctype-simple.c | 7 +-- strings/ctype-sjis.c | 6 +-- strings/ctype-tis620.c | 6 +-- strings/ctype-ujis.c | 6 +-- strings/ctype-utf8.c | 8 ++-- strings/ctype-win1250ch.c | 6 +-- strings/ctype.c | 92 +++++++++++++++++++-------------------- 18 files changed, 114 insertions(+), 104 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index d99fda8d2b9..cd6bfc15f8a 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -57,6 +57,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) @@ -133,8 +134,8 @@ 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); @@ -188,8 +189,8 @@ longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); double my_strntod_8bit(CHARSET_INFO *, char *s, uint l,char **e); -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, @@ -253,7 +254,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) \ diff --git a/mysys/charset.c b/mysys/charset.c index c89e1d60c7e..865441444bc 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -47,6 +47,7 @@ static void simple_cs_init_functions(CHARSET_INFO *cs) { cs->like_range = my_like_range_simple; cs->wildcmp = my_wildcmp_8bit; + cs->strnxfrm = my_strnxfrm_simple; cs->strnncoll = my_strnncoll_simple; cs->caseup_str = my_caseup_str_8bit; cs->casedn_str = my_casedn_str_8bit; diff --git a/sql/field.cc b/sql/field.cc index 467096a4a71..e789188e552 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1097,9 +1097,9 @@ String *Field_tiny::val_str(String *val_buffer, 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) @@ -1340,9 +1340,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); @@ -1577,7 +1577,7 @@ String *Field_medium::val_str(String *val_buffer, 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 */ @@ -1816,9 +1816,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); @@ -2038,7 +2038,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); @@ -3914,7 +3914,7 @@ 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); } @@ -4093,7 +4093,7 @@ 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); } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 4c499af8f9e..646621ac2eb 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -100,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; } @@ -111,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; } diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 408c7f8fe35..3d26918f1c8 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,8 +6250,8 @@ 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, diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index e20afff1470..3cf5bb763cd 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -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,8 +298,8 @@ 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, diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c index bb0afe98032..8feb83cbeb4 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,8 +628,8 @@ 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, diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index 814f43166c4..ff7d0e9a5ae 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,8 +8668,8 @@ 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, diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index d575e48a59a..a94778118e3 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,8 +5718,8 @@ 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, diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 0094a93e5f8..7c48e239f2d 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,8 +9905,8 @@ 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, diff --git a/strings/ctype-latin1_de.c b/strings/ctype-latin1_de.c index 166e059ef42..6891e4cf944 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,8 +446,8 @@ 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, diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 9bcafa9f164..44379cdc15a 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -31,9 +31,10 @@ int my_strnxfrm_simple(CHARSET_INFO * cs, uchar *map= cs->sort_order; DBUG_ASSERT(len >= srclen); + len= min(len,srclen); for ( ; len > 0 ; len-- ) *dest++= map[*src++]; - return srclen; + return len; } int my_strnncoll_simple(CHARSET_INFO * cs, const uchar *s, uint slen, @@ -686,7 +687,7 @@ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), 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]; @@ -725,7 +726,7 @@ int my_l10tostr_8bit(CHARSET_INFO *cs __attribute__((unused)), } -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]; diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 3949be5e215..b3d81bb9c8a 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,8 +4492,8 @@ 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, diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 7168026eea5..b07b08bba9f 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,8 +720,8 @@ 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, diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index 0a0024594e4..eaf39ff0aa7 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,8 +8462,8 @@ 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, diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 4f72a4c2334..7ca3395c2cc 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1958,7 +1958,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,8 +1990,8 @@ 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, @@ -3019,7 +3019,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 */ diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index 358cede442c..6ec96693fec 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,8 +654,8 @@ 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, diff --git a/strings/ctype.c b/strings/ctype.c index c2a7e928493..cafa2542a06 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -2843,8 +2843,8 @@ 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, @@ -2889,8 +2889,8 @@ 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, @@ -2934,8 +2934,8 @@ 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, @@ -2979,8 +2979,8 @@ 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, @@ -3025,8 +3025,8 @@ 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, @@ -3070,8 +3070,8 @@ 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, @@ -3115,8 +3115,8 @@ 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, @@ -3160,8 +3160,8 @@ 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, @@ -3206,8 +3206,8 @@ 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, @@ -3251,8 +3251,8 @@ 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, @@ -3296,8 +3296,8 @@ 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, @@ -3341,8 +3341,8 @@ 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, @@ -3386,8 +3386,8 @@ 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, @@ -3431,8 +3431,8 @@ 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, @@ -3476,8 +3476,8 @@ 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, @@ -3522,8 +3522,8 @@ 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, @@ -3567,8 +3567,8 @@ 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, @@ -3613,8 +3613,8 @@ 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, @@ -3659,8 +3659,8 @@ 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, @@ -3704,8 +3704,8 @@ 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, @@ -3749,8 +3749,8 @@ 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, @@ -3794,8 +3794,8 @@ 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, @@ -3839,8 +3839,8 @@ 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, From 94cc7d751e93874f45f028cbee9f86bd03403404 Mon Sep 17 00:00:00 2001 From: "jani@rhols221.adsl.netsonic.fi" <> Date: Thu, 16 Jan 2003 02:04:50 +0200 Subject: [PATCH 32/48] Added support sql_mode, which can be used to produce various outputs of SHOW CREATE TABLE 'name'. Depending on the mode, the output can be compatible with various databases, including earlier versions of MySQL . --- mysql-test/r/sql_mode.result | 87 ++++++++++++++++++ mysql-test/t/sql_mode.test | 30 +++++++ sql/field.cc | 67 +++++++++----- sql/field.h | 3 +- sql/item_func.cc | 2 +- sql/mysql_priv.h | 5 ++ sql/mysqld.cc | 24 ++--- sql/set_var.cc | 81 ++++++++++++++++- sql/set_var.h | 19 +++- sql/sql_class.cc | 1 - sql/sql_class.h | 2 +- sql/sql_lex.cc | 4 +- sql/sql_parse.cc | 8 +- sql/sql_select.cc | 4 +- sql/sql_show.cc | 168 ++++++++++++++++++++--------------- sql/sql_yacc.yy | 6 +- 16 files changed, 392 insertions(+), 119 deletions(-) create mode 100644 mysql-test/r/sql_mode.result create mode 100644 mysql-test/t/sql_mode.test diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result new file mode 100644 index 00000000000..eade1ca02ea --- /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 CHARSET=latin1 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/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/sql/field.cc b/sql/field.cc index e789188e552..68717ee51a1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -248,7 +248,15 @@ void Field_str::add_binary_or_charset(String &res) const { if (binary()) res.append(" binary"); - else if (field_charset != table->table_charset) + 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)) { res.append(" character set "); res.append(field_charset->csname); @@ -5037,38 +5045,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++; @@ -5080,7 +5102,10 @@ 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); + 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 */ diff --git a/sql/field.h b/sql/field.h index 06a9b534b16..af479c81b40 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1095,7 +1095,8 @@ 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); +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); diff --git a/sql/item_func.cc b/sql/item_func.cc index 62cf4c0d291..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; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index cdc668d9b28..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 diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 27c7fb369a1..18da509529b 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,"", @@ -4301,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': @@ -4730,16 +4731,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/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/sql_class.cc b/sql/sql_class.cc index 4416f5259bd..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 : 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_lex.cc b/sql/sql_lex.cc index b656f698e89..1a33ac0760b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -122,7 +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) + if (global_system_variables.sql_mode & MODE_ANSI_QUOTES) { state_map[(uchar) '"'] = STATE_USER_VARIABLE_DELIMITER; } @@ -167,7 +167,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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 81fb5a6d12c..1e2ce9e9a86 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -588,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) @@ -3458,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); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index aab8d883204..5912f3021dc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6947,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); @@ -6969,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 281fa92de6a..451a0956cf8 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,70 @@ 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) { - 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); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 318d563b88a..5964ce68559 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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)); } @@ -1129,7 +1129,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; @@ -1200,7 +1200,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; }; From e79ed81d11001ef107a3b0eddf032ddf27be99d8 Mon Sep 17 00:00:00 2001 From: "jani@rhols221.adsl.netsonic.fi" <> Date: Thu, 16 Jan 2003 05:35:59 +0200 Subject: [PATCH 33/48] Added --compatible mode to mysqldump. --- client/client_priv.h | 3 +- client/mysqldump.c | 180 ++++++++++++++++++++++++++++------- mysql-test/r/sql_mode.result | 2 +- sql/sql_show.cc | 4 +- 4 files changed, 149 insertions(+), 40 deletions(-) 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/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/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index eade1ca02ea..8ded3daf114 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -70,7 +70,7 @@ t1 CREATE TABLE `t1` ( `email` varchar(60) NOT NULL default '', PRIMARY KEY (`a`), UNIQUE KEY `email` (`email`) -) TYPE=HEAP CHARSET=latin1 ROW_FORMAT=DYNAMIC +) TYPE=HEAP ROW_FORMAT=DYNAMIC set @@sql_mode="postgresql,oracle,mssql,db2,sapdb"; show variables like 'sql_mode'; Variable_name Value diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 451a0956cf8..3ec45c8eca9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1198,7 +1198,9 @@ store_create_info(THD *thd, TABLE *table, String *packet) char buff[128]; char* p; - if (table->table_charset) + if (table->table_charset && + !(thd->variables.sql_mode & MODE_MYSQL323) && + !(thd->variables.sql_mode & MODE_MYSQL40)) { packet->append(" CHARSET="); packet->append(table->table_charset->csname); From 4b9d29c83b3d04eaf82f4272a32f7e72d5686afa Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Thu, 16 Jan 2003 15:20:38 +0400 Subject: [PATCH 34/48] strnxfrm() for simple and binary charsets fixes --- sql/field.cc | 38 ++++------------------------------ strings/ctype-simple.c | 3 ++- strings/ctype.c | 46 +++++++++++++++++++++--------------------- 3 files changed, 29 insertions(+), 58 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 68717ee51a1..31ec6bf4a46 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3964,23 +3964,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); } @@ -4145,27 +4133,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); } diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 44379cdc15a..07e7a382f8a 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -29,10 +29,11 @@ int my_strnxfrm_simple(CHARSET_INFO * cs, const uchar *src, uint srclen) { uchar *map= cs->sort_order; + const uchar *end; DBUG_ASSERT(len >= srclen); len= min(len,srclen); - for ( ; len > 0 ; len-- ) + for ( end=src+len; src < end ; ) *dest++= map[*src++]; return len; } diff --git a/strings/ctype.c b/strings/ctype.c index cafa2542a06..76636d17ace 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -2823,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 */ @@ -2869,7 +2869,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 */ @@ -2914,7 +2914,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 */ @@ -2959,7 +2959,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 */ @@ -3005,7 +3005,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 */ @@ -3050,7 +3050,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 */ @@ -3095,7 +3095,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 */ @@ -3140,7 +3140,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 */ @@ -3186,7 +3186,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 */ @@ -3231,7 +3231,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 */ @@ -3276,7 +3276,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 */ @@ -3321,7 +3321,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 */ @@ -3366,7 +3366,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 */ @@ -3411,7 +3411,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 */ @@ -3456,7 +3456,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 */ @@ -3502,7 +3502,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 */ @@ -3547,7 +3547,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 */ @@ -3593,7 +3593,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 */ @@ -3639,7 +3639,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 */ @@ -3684,7 +3684,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 */ @@ -3729,7 +3729,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 */ @@ -3774,7 +3774,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 */ @@ -3819,7 +3819,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 */ From 4a77f335f42b22705611a5f323e461b6886614ce Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Thu, 16 Jan 2003 15:52:37 +0400 Subject: [PATCH 35/48] field.cc: strnxfrm for binary and simple charsets --- sql/field.cc | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 31ec6bf4a46..0ba2bbc5aa1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4591,38 +4591,19 @@ 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++]; - } + + blob_length=my_strnxfrm(field_charset, + (unsigned char *)to, length, + (unsigned char *)blob, blob_length); + if (blob_length >= length) + return; + to+=blob_length; bzero(to,length-blob_length); } } From 4f9d82700db57fea35a1caca39520dd8c44db9a2 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Thu, 16 Jan 2003 17:17:07 +0400 Subject: [PATCH 36/48] strnto family functions now return error in a new argument --- include/m_ctype.h | 30 +++++++------- libmysql/libmysql.c | 13 +++--- sql/field.cc | 91 ++++++++++++++++++++++-------------------- sql/item.cc | 14 +++++-- sql/item.h | 14 +++++-- sql/item_func.h | 6 ++- sql/item_strfunc.cc | 11 +++-- sql/item_sum.cc | 3 +- sql/item_sum.h | 6 ++- sql/mysqld.cc | 3 +- sql/procedure.h | 10 +++-- strings/ctype-simple.c | 32 ++++++++------- strings/ctype-utf8.c | 48 ++++++++++++---------- strings/ctype.c | 10 +++-- 14 files changed, 166 insertions(+), 125 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index cd6bfc15f8a..8e3cffc5613 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -138,11 +138,11 @@ typedef struct charset_info_st 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 *, 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); } CHARSET_INFO; @@ -183,11 +183,11 @@ int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e); 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 *, 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_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); @@ -274,11 +274,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/libmysql/libmysql.c b/libmysql/libmysql.c index 7757050aad7..7c4f6acfa07 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4522,41 +4522,42 @@ static void send_data_double(MYSQL_BIND *param, double value) static void send_data_str(MYSQL_BIND *param, char *value, uint length) { char *buffer= param->buffer; + int err=0; switch(param->buffer_type) { case MYSQL_TYPE_TINY: { - uchar data= (uchar)my_strntol(system_charset_info,value,length,NULL,10); + uchar data= (uchar)my_strntol(system_charset_info,value,length,10,NULL,&err); *buffer= data; break; } case MYSQL_TYPE_SHORT: { - short data= (short)my_strntol(system_charset_info,value,length,NULL,10); + short data= (short)my_strntol(system_charset_info,value,length,10,NULL,&err); int2store(buffer, data); break; } case MYSQL_TYPE_LONG: { - int32 data= (int32)my_strntol(system_charset_info,value,length,NULL,10); + int32 data= (int32)my_strntol(system_charset_info,value,length,10,NULL,&err); int4store(buffer, data); break; } case MYSQL_TYPE_LONGLONG: { - longlong data= my_strntoll(system_charset_info,value,length,NULL,10); + longlong data= my_strntoll(system_charset_info,value,length,10,NULL,&err); int8store(buffer, data); break; } case MYSQL_TYPE_FLOAT: { - float data = (float)my_strntod(system_charset_info,value,length,NULL); + float data = (float)my_strntod(system_charset_info,value,length,NULL,&err); float4store(buffer, data); break; } case MYSQL_TYPE_DOUBLE: { - double data= my_strntod(system_charset_info,value,length,NULL); + double data= my_strntod(system_charset_info,value,length,NULL,&err); float8store(buffer, data); break; } diff --git a/sql/field.cc b/sql/field.cc index 0ba2bbc5aa1..c287c716cc1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -840,15 +840,17 @@ int Field_decimal::store(longlong nr) double Field_decimal::val_real(void) { - return my_strntod(my_charset_bin, ptr, field_length, NULL); + int err; + return my_strntod(my_charset_bin, ptr, field_length, NULL, &err); } longlong Field_decimal::val_int(void) { + int err; if (unsigned_flag) - return my_strntoull(my_charset_bin, ptr, field_length, NULL, 10); + return my_strntoull(my_charset_bin, ptr, field_length, 10, NULL, &err); else - return my_strntoll( my_charset_bin, ptr, field_length, NULL, 10); + return my_strntoll( my_charset_bin, ptr, field_length, 10, NULL, &err); } @@ -950,8 +952,9 @@ void Field_decimal::sql_type(String &res) const int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) { + int err; char *end; - long tmp= my_strntol(cs, from, len, &end,10); + long tmp= my_strntol(cs, from, len, 10, &end, &err); int error= 0; if (unsigned_flag) @@ -1151,8 +1154,9 @@ void Field_tiny::sql_type(String &res) const int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) { + int err; char *end; - long tmp= my_strntol(cs, from, len, &end, 10); + long tmp= my_strntol(cs, from, len, 10, &end, &err); int error= 0; if (unsigned_flag) { @@ -1423,8 +1427,9 @@ void Field_short::sql_type(String &res) const int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) { + int err; char *end; - long tmp= my_strntol(cs, from, len, &end, 10); + long tmp= my_strntol(cs, from, len, 10, &end, &err); int error= 0; if (unsigned_flag) @@ -1659,16 +1664,15 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) 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 (my_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,end,cs))) { current_thd->cuted_fields++; - error= 1; } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -1918,11 +1922,11 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) 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 (my_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,end,cs))) current_thd->cuted_fields++; @@ -2130,14 +2134,14 @@ void Field_longlong::sql_type(String &res) const int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) { - errno=0; // my_strntod() changes errno - Field_float::store(my_strntod(cs,(char*) from,len,(char**)NULL)); - if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) + int err=0; + 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; } @@ -2403,19 +2407,17 @@ void Field_float::sql_type(String &res) const int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) { - errno=0; // my_strntod() changes errno - int error= 0; - double j= my_strntod(cs,(char*) from,len,(char**)0); - if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) + int err= 0; + 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) @@ -2425,7 +2427,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) else #endif doublestore(ptr,j); - return error; + return err; } @@ -3191,8 +3193,9 @@ void Field_time::sql_type(String &res) const int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) { + int err; char *end; - long nr= my_strntol(cs, from, len, &end, 10); + long nr= my_strntol(cs, from, len, 10, &end, &err); if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { @@ -3929,15 +3932,17 @@ int Field_string::store(longlong nr) double Field_string::val_real(void) { + int err; CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr,field_length,(char**)0); + return my_strntod(cs,ptr,field_length,(char**)0,&err); } longlong Field_string::val_int(void) { + int err; CHARSET_INFO *cs=charset(); - return my_strntoll(cs,ptr,field_length,NULL,10); + return my_strntoll(cs,ptr,field_length,10,NULL,&err); } @@ -4096,17 +4101,19 @@ int Field_varstring::store(longlong nr) double Field_varstring::val_real(void) { + int err; 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,&err); } longlong Field_varstring::val_int(void) { + int err; 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,&err); } @@ -4414,24 +4421,26 @@ int Field_blob::store(longlong nr) double Field_blob::val_real(void) { + int err; 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,&err); } longlong Field_blob::val_int(void) { + int err; char *blob; memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) return 0; uint32 length=get_length(ptr); - return my_strntoll(charset(),blob,length,NULL,10); + return my_strntoll(charset(),blob,length,10,NULL,&err); } @@ -4846,7 +4855,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) { @@ -4854,20 +4863,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; } @@ -5052,7 +5059,7 @@ ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { - int error= 0; + int err= 0; char *not_used; uint not_used2; @@ -5061,19 +5068,17 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { /* 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; } diff --git a/sql/item.cc b/sql/item.cc index 925ee9ac0f4..ecc63aa4b95 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -378,10 +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(), (char*) str_value.ptr(), - str_value.length(), (char**) 0); + str_value.length(), (char**) 0, &err); case INT_RESULT: return (double)int_value; default: @@ -392,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: @@ -1263,17 +1267,19 @@ void Item_cache_str::store(Item *item) } double Item_cache_str::val() { + int err; if (value) return my_strntod(value->charset(), (char*) value->ptr(), - value->length(), (char**) 0); + 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 907c293d454..03e9a542eea 100644 --- a/sql/item.h +++ b/sql/item.h @@ -344,13 +344,15 @@ public: enum Type type() const { return STRING_ITEM; } double val() { + int err; return my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(), (char**) 0); + 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); @@ -599,12 +601,16 @@ public: enum_field_types field_type() const { return cached_field_type; } double val() { + int err; return (null_value ? 0.0 : my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(),NULL)); + 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.h b/sql/item_func.h index 11793b11bdb..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(),(char*) 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 4358f14f08e..2b9bdfe9a1e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -52,17 +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(), (char*) res->ptr(),res->length(), - NULL) : 0.0; + 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; } @@ -1956,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 || @@ -1966,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; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index b15fceda686..2a96594af4e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -336,13 +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(), (char*) res->ptr(),res->length(), - (char**) 0) : 0.0); + (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 ffc9558822d..c49311082e8 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -483,14 +483,16 @@ public: String *val_str(String *); double val() { + int err; String *res; res=val_str(&str_value); return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(), - (char**) 0) : 0.0; + (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/mysqld.cc b/sql/mysqld.cc index 18da509529b..f30034049f0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4666,9 +4666,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), berkeley_lock_type=berkeley_lock_types[type-1]; else { + int err; char *end; uint length= strlen(argument); - long value= my_strntol(my_charset_latin1, argument, length, &end, 10); + 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 diff --git a/sql/procedure.h b/sql/procedure.h index bc77803230f..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,(char*) 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,14 +98,16 @@ public: { str_value.copy(str,length,cs); } double val() { + int err; CHARSET_INFO *cs=str_value.charset(); return my_strntod(cs, (char*) str_value.ptr(), str_value.length(), - (char**) 0); + (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/strings/ctype-simple.c b/strings/ctype-simple.c index 07e7a382f8a..df1609c983d 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" @@ -203,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; @@ -303,14 +303,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; @@ -318,7 +318,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; @@ -409,14 +410,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; @@ -424,7 +425,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; @@ -524,14 +526,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; @@ -539,7 +541,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; @@ -631,14 +634,14 @@ 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; @@ -667,7 +670,8 @@ noconv: double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), - char *str, uint length, char **end) + char *str, uint length, + char **end, int *err __attribute__ ((unused))) { char end_char; double result; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 7ca3395c2cc..e57f35bab19 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -21,7 +21,6 @@ #include #include "m_string.h" #include "m_ctype.h" -#include "my_sys.h" /* defines errno */ #include #ifdef HAVE_CHARSET_utf8 @@ -2446,7 +2445,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; @@ -2475,7 +2475,7 @@ 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; @@ -2518,7 +2518,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]=EILSEQ; return 0; } else @@ -2533,7 +2533,7 @@ bs: if (s == save) { - my_errno=EDOM; + err[0]=EDOM; return 0L; } @@ -2547,7 +2547,7 @@ bs: if (overflow) { - my_errno=(ERANGE); + err[0]=ERANGE; return negative ? LONG_MIN : LONG_MAX; } @@ -2556,7 +2556,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; @@ -2585,7 +2586,7 @@ 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; @@ -2628,7 +2629,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]=EILSEQ; return 0; } else @@ -2643,13 +2644,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 +2661,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; @@ -2689,7 +2691,7 @@ 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; @@ -2732,7 +2734,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]=EILSEQ; return 0; } else @@ -2747,7 +2749,7 @@ bs: if (s == save) { - my_errno=EDOM; + err[0]=EDOM; return 0L; } @@ -2761,7 +2763,7 @@ bs: if (overflow) { - my_errno=(ERANGE); + err[0]=ERANGE; return negative ? LONGLONG_MIN : LONGLONG_MAX; } @@ -2772,7 +2774,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; @@ -2801,7 +2804,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; @@ -2844,7 +2847,7 @@ bs: { if (endptr !=NULL ) *endptr = (char*)s; - my_errno=EILSEQ; + err[0]= EILSEQ; return 0; } else @@ -2859,13 +2862,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,7 +2877,8 @@ bs: double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), - char *nptr, uint length, char **endptr) + char *nptr, uint length, + char **endptr, int *err __attribute__ ((unused))) { char buf[256]; double res; diff --git a/strings/ctype.c b/strings/ctype.c index 76636d17ace..615f0b7ef49 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -3983,6 +3983,7 @@ typedef struct my_cs_file_info 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; @@ -3993,7 +3994,7 @@ static int fill_uchar(uchar *a,uint size,const char *str, uint len) 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); + a[i]= my_strntoul(my_charset_latin1,b,s-b,16,NULL,&err); } return 0; } @@ -4001,6 +4002,8 @@ static int fill_uchar(uchar *a,uint size,const char *str, uint len) 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++) { @@ -4009,7 +4012,7 @@ static int fill_uint16(uint16 *a,uint size,const char *str, uint len) 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); + a[i]= my_strntol(my_charset_latin1,b,s-b,16,NULL,&err); } return 0; } @@ -4051,6 +4054,7 @@ 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){ @@ -4062,7 +4066,7 @@ static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) switch (state) { case _CS_ID: - i->cs.number= my_strntoul(my_charset_latin1,attr,len,(char**)NULL,0); + i->cs.number= my_strntoul(my_charset_latin1,attr,len,0,(char**)NULL,&err); break; case _CS_COLNAME: i->cs.name=mstr(i->name,attr,len,MY_CS_NAME_SIZE-1); From eb22615ec78db2d3cdd967732b33f351e9976a30 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Thu, 16 Jan 2003 18:35:04 +0200 Subject: [PATCH 37/48] lock0lock.c: Fix a bug in the query cache algorithm for the AUTOCOMMIT=0 case --- innobase/lock/lock0lock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 From c2ddffb4a204b037084bbc9d5c586bac080e6440 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Thu, 16 Jan 2003 14:57:49 -0800 Subject: [PATCH 38/48] Remove un-used code --- sql/sql_prepare.cc | 62 ---------------------------------------------- 1 file changed, 62 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3907995676f..69228c6ec4c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -333,53 +333,6 @@ static bool setup_params_data(PREP_STMT *stmt) 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 @@ -519,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 */ From 370b88f94cb2ad51fa65926abc508da61f7aa497 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Thu, 16 Jan 2003 15:00:22 -0800 Subject: [PATCH 39/48] Implement store_result (read_binary_rows & mysql_stmt_store_result) --- include/mysql.h | 2 + libmysql/libmysql.c | 196 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 165 insertions(+), 33 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index ce321f5b5ea..f25ccf79cf6 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -476,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,6 +503,7 @@ int STDCALL mysql_multi_query(MYSQL *mysql,const char *query, 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 */ diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 7757050aad7..082477d35ae 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); } @@ -4102,8 +4103,18 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) 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); } @@ -4859,12 +4872,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 */ @@ -4884,7 +4899,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) { @@ -4892,23 +4907,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 */ @@ -4916,24 +4917,153 @@ 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 */ + { + 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); } - DBUG_PRINT("info", ("end of data")); - DBUG_RETURN(MYSQL_NO_DATA); /* no more data */ + 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() */ } From 89931690ca656c50c44fad9dc7d9f0d8e096d28a Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 17 Jan 2003 12:35:47 +0400 Subject: [PATCH 40/48] ctype-utf8.c: Workaround for platforms which don't support EILSEQ --- strings/ctype-utf8.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index e57f35bab19..4a99d7465a7 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -23,6 +23,10 @@ #include "m_ctype.h" #include +#ifndef EILSEQ +#define EILSEQ ENOENT +#endif + #ifdef HAVE_CHARSET_utf8 #define HAVE_UNIDATA #endif From 72fcf5e4e79c4a73b8aba2f2878559abf753154b Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 17 Jan 2003 13:17:22 +0400 Subject: [PATCH 41/48] Use always base "10" to remove base guesser in strntoul() implementation --- strings/ctype-simple.c | 30 +++++++++++++++++++++++++++--- strings/ctype-utf8.c | 20 ++++++++++++++------ strings/ctype.c | 2 +- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index df1609c983d..4ecd3717ca1 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -213,10 +213,12 @@ long my_strntol_8bit(CHARSET_INFO *cs, register unsigned char c; const char *save, *e; int overflow; - + +#if 0 if (base < 0 || base == 1 || base > 36) base = 10; - +#endif + s = nptr; e = nptr+l; @@ -241,9 +243,12 @@ long my_strntol_8bit(CHARSET_INFO *cs, else negative = 0; +#if 0 if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x')) s += 2; +#endif +#if 0 if (base == 0) { if (*s == '0') @@ -259,6 +264,7 @@ long my_strntol_8bit(CHARSET_INFO *cs, else base = 10; } +#endif save = s; cutoff = ((ulong)~0L) / (unsigned long int) base; @@ -330,9 +336,11 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, const char *save, *e; int overflow; +#if 0 if (base < 0 || base == 1 || base > 36) base = 10; - +#endif + s = nptr; e = nptr+l; @@ -356,9 +364,12 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, else negative = 0; +#if 0 if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x')) s += 2; +#endif +#if 0 if (base == 0) { if (*s == '0') @@ -374,6 +385,7 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, else base = 10; } +#endif save = s; cutoff = ((ulong)~0L) / (unsigned long int) base; @@ -437,8 +449,10 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), const char *save; int overflow; +#if 0 if (base < 0 || base == 1 || base > 36) base = 10; +#endif s = nptr; e = nptr+l; @@ -463,9 +477,12 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), else negative = 0; +#if 0 if (base == 16 && s[0] == '0' && (s[1]=='X'|| s[1]=='x')) s += 2; +#endif +#if 0 if (base == 0) { if (*s == '0') @@ -481,6 +498,7 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), else base = 10; } +#endif save = s; @@ -553,8 +571,10 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, const char *save; int overflow; +#if 0 if (base < 0 || base == 1 || base > 36) base = 10; +#endif s = nptr; e = nptr+l; @@ -579,9 +599,12 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, else negative = 0; +#if 0 if (base == 16 && s[0] == '0' && (s[1]=='X' || s[1]=='x')) s += 2; +#endif +#if 0 if (base == 0) { if (*s == '0') @@ -597,6 +620,7 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, else base = 10; } +#endif save = s; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 4a99d7465a7..2418a6ab574 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2486,9 +2486,11 @@ long my_strntol_ucs2(CHARSET_INFO *cs, } while (1); bs: - + +#if 0 if (base <= 0 || base == 1 || base > 36) base = 10; +#endif overflow = 0; res = 0; @@ -2597,10 +2599,12 @@ ulong my_strntoul_ucs2(CHARSET_INFO *cs, } while (1); bs: - + +#if 0 if (base <= 0 || base == 1 || base > 36) base = 10; - +#endif + overflow = 0; res = 0; save = s; @@ -2702,10 +2706,12 @@ longlong my_strntoll_ucs2(CHARSET_INFO *cs, } while (1); bs: - + +#if 0 if (base <= 0 || base == 1 || base > 36) base = 10; - +#endif + overflow = 0; res = 0; save = s; @@ -2816,9 +2822,11 @@ 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; diff --git a/strings/ctype.c b/strings/ctype.c index 615f0b7ef49..04ae5917da2 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -4066,7 +4066,7 @@ static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) switch (state) { case _CS_ID: - i->cs.number= my_strntoul(my_charset_latin1,attr,len,0,(char**)NULL,&err); + 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); From 4306940bb4956093e3d23c8a800dc6438d730d10 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 17 Jan 2003 16:25:10 +0400 Subject: [PATCH 42/48] Some comments have been added XXX10_to_str were not inizialized --- mysys/charset.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/mysys/charset.c b/mysys/charset.c index 865441444bc..c5b2bcc2757 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -22,6 +22,17 @@ #include +/* + + The code below implements this functionality: + + - 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 void set_max_sort_char(CHARSET_INFO *cs) { @@ -45,10 +56,13 @@ static void set_max_sort_char(CHARSET_INFO *cs) static void simple_cs_init_functions(CHARSET_INFO *cs) { - cs->like_range = my_like_range_simple; - cs->wildcmp = my_wildcmp_8bit; + 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; @@ -56,11 +70,11 @@ static void simple_cs_init_functions(CHARSET_INFO *cs) 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->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; From 6ac602142ad100b7d9528b5ba1417c3c14476bcb Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Fri, 17 Jan 2003 16:39:29 +0400 Subject: [PATCH 43/48] Replication: Optimize away string.append Fixed problem with replication LOAD DATA INFILE when using --old-rpl-compat Fixed rpl_temporary test --- BitKeeper/etc/logging_ok | 1 + mysql-test/r/rpl_temporary.result | 2 +- mysql-test/t/rpl_temporary.test | 3 + sql/log_event.cc | 248 +++++++++++++++++------------- 4 files changed, 142 insertions(+), 112 deletions(-) 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/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/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/sql/log_event.cc b/sql/log_event.cc index 8f98fa511a0..17a84f17d21 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 @@ -558,7 +560,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 +683,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 +959,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 +1066,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 +1319,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 +1330,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) @@ -1565,15 +1595,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 +1736,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 +1942,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 @@ -2259,20 +2287,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 From 1dde85db7c940b37112e6be284c7c6be4f6fead4 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Fri, 17 Jan 2003 15:36:08 +0200 Subject: [PATCH 44/48] using internal name conversion in query cache as it was suggested by Shurik --- sql/sql_cache.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) 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)")); From 2a41e291dc0913b8e1d73e75d8d631893dd9d26b Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 17 Jan 2003 18:14:54 +0400 Subject: [PATCH 45/48] New scan() function in CHARSET_INFO structure (not used yet) --- include/m_ctype.h | 7 ++++ mysys/charset.c | 1 + strings/ctype-big5.c | 3 +- strings/ctype-bin.c | 1 + strings/ctype-czech.c | 3 +- strings/ctype-euc_kr.c | 3 +- strings/ctype-gb2312.c | 3 +- strings/ctype-gbk.c | 1 + strings/ctype-latin1_de.c | 3 +- strings/ctype-simple.c | 26 +++++++++++++++ strings/ctype-sjis.c | 3 +- strings/ctype-tis620.c | 3 +- strings/ctype-ujis.c | 3 +- strings/ctype-utf8.c | 4 ++- strings/ctype-win1250ch.c | 3 +- strings/ctype.c | 70 ++++++++++++++++++++++++++------------- 16 files changed, 104 insertions(+), 33 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index 8e3cffc5613..ee6a50e6b8d 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -49,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 */ @@ -144,6 +147,8 @@ typedef struct charset_info_st 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; @@ -181,6 +186,8 @@ 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, int base, char **e, int *err); diff --git a/mysys/charset.c b/mysys/charset.c index c5b2bcc2757..591ba568e3d 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -80,6 +80,7 @@ static void simple_cs_init_functions(CHARSET_INFO *cs) cs->strntoll = my_strntoll_8bit; cs->strntoull = my_strntoull_8bit; cs->strntod = my_strntod_8bit; + cs->scan = my_scan_8bit; cs->mbmaxlen = 1; } diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 3d26918f1c8..a475a36d049 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -6257,7 +6257,8 @@ CHARSET_INFO my_charset_big5 = 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 3cf5bb763cd..7d174d510e2 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -305,6 +305,7 @@ static CHARSET_INFO my_charset_bin_st = 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 8feb83cbeb4..6397d3d902e 100644 --- a/strings/ctype-czech.c +++ b/strings/ctype-czech.c @@ -634,7 +634,8 @@ CHARSET_INFO my_charset_czech = 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 ff7d0e9a5ae..ee75673e1c5 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8674,7 +8674,8 @@ CHARSET_INFO my_charset_euc_kr = 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 a94778118e3..0820d03b2d0 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5724,7 +5724,8 @@ CHARSET_INFO my_charset_gb2312 = 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 7c48e239f2d..3aff098cd14 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -9912,6 +9912,7 @@ CHARSET_INFO my_charset_gbk = 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 6891e4cf944..6a5a9b78e8d 100644 --- a/strings/ctype-latin1_de.c +++ b/strings/ctype-latin1_de.c @@ -452,7 +452,8 @@ CHARSET_INFO my_charset_latin1_de = 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 4ecd3717ca1..d9270a6de93 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -968,3 +968,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 b3d81bb9c8a..b19bcf1a45a 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4498,7 +4498,8 @@ CHARSET_INFO my_charset_sjis = 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 b07b08bba9f..ac959105736 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -726,7 +726,8 @@ CHARSET_INFO my_charset_tis620 = 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 eaf39ff0aa7..12e177a89be 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -8468,7 +8468,8 @@ CHARSET_INFO my_charset_ujis = 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 2418a6ab574..2d6a37dd5a7 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2000,6 +2000,7 @@ CHARSET_INFO my_charset_utf8 = my_strntoll_8bit, my_strntoull_8bit, my_strntod_8bit, + my_scan_8bit }; @@ -3073,7 +3074,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 6ec96693fec..86ddb82e1a2 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -660,7 +660,8 @@ CHARSET_INFO my_charset_win1250ch = 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 04ae5917da2..0873429f9ab 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -2849,7 +2849,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -2895,7 +2896,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -2940,7 +2942,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -2985,7 +2988,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3031,7 +3035,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3076,7 +3081,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3121,7 +3127,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3166,7 +3173,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3212,7 +3220,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3257,7 +3266,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3302,7 +3312,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3347,7 +3358,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3392,7 +3404,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3437,7 +3450,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3482,7 +3496,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3528,7 +3543,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3573,7 +3589,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3619,7 +3636,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3665,7 +3683,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3710,7 +3729,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3755,7 +3775,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3800,7 +3821,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3845,7 +3867,8 @@ static CHARSET_INFO compiled_charsets[] = { my_strntoul_8bit, my_strntoll_8bit, my_strntoull_8bit, - my_strntod_8bit + my_strntod_8bit, + my_scan_8bit }, #endif @@ -3891,6 +3914,7 @@ static CHARSET_INFO compiled_charsets[] = { NULL, NULL, NULL, + NULL, NULL } }; From 762cb225c9efd361e31879115e3dbbd9b93e5e90 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Fri, 17 Jan 2003 16:33:54 +0200 Subject: [PATCH 46/48] Changed my_strntoxxx functions to clear error number on start Allow one to change ANSI_QUOTES mode per thread and on the fly --- sql/field.cc | 65 +++++++++++++++++++++--------------------- sql/sql_base.cc | 1 + sql/sql_lex.cc | 27 +++++++++++------- sql/sql_lex.h | 3 +- strings/ctype-simple.c | 26 +++++++++++------ strings/ctype-utf8.c | 26 ++++++++++++----- 6 files changed, 88 insertions(+), 60 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index c287c716cc1..1b388287811 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -840,17 +840,19 @@ int Field_decimal::store(longlong nr) double Field_decimal::val_real(void) { - int err; - return my_strntod(my_charset_bin, ptr, field_length, NULL, &err); + int not_used; + return my_strntod(my_charset_bin, ptr, field_length, NULL, ¬_used); } longlong Field_decimal::val_int(void) { - int err; + int not_used; if (unsigned_flag) - return my_strntoull(my_charset_bin, ptr, field_length, 10, NULL, &err); + return my_strntoull(my_charset_bin, ptr, field_length, 10, NULL, + ¬_used); else - return my_strntoll( my_charset_bin, ptr, field_length, 10, NULL, &err); + return my_strntoll( my_charset_bin, ptr, field_length, 10, NULL, + ¬_used); } @@ -952,9 +954,9 @@ void Field_decimal::sql_type(String &res) const int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) { - int err; + int not_used; // We can ignore result from str2int char *end; - long tmp= my_strntol(cs, from, len, 10, &end, &err); + long tmp= my_strntol(cs, from, len, 10, &end, ¬_used); int error= 0; if (unsigned_flag) @@ -1154,10 +1156,11 @@ void Field_tiny::sql_type(String &res) const int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) { - int err; + int not_used; // We can ignore result from str2int char *end; - long tmp= my_strntol(cs, from, len, 10, &end, &err); + long tmp= my_strntol(cs, from, len, 10, &end, ¬_used); int error= 0; + if (unsigned_flag) { if (tmp < 0) @@ -1427,9 +1430,9 @@ void Field_short::sql_type(String &res) const int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) { - int err; + int not_used; // We can ignore result from str2int char *end; - long tmp= my_strntol(cs, from, len, 10, &end, &err); + long tmp= my_strntol(cs, from, len, 10, &end, ¬_used); int error= 0; if (unsigned_flag) @@ -2134,7 +2137,7 @@ void Field_longlong::sql_type(String &res) const int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) { - int err=0; + 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)) { @@ -2407,7 +2410,7 @@ void Field_float::sql_type(String &res) const int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) { - int err= 0; + 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)) { @@ -3193,9 +3196,9 @@ void Field_time::sql_type(String &res) const int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) { - int err; + int not_used; // We can ignore result from str2int char *end; - long nr= my_strntol(cs, from, len, 10, &end, &err); + long nr= my_strntol(cs, from, len, 10, &end, ¬_used); if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { @@ -3932,17 +3935,17 @@ int Field_string::store(longlong nr) double Field_string::val_real(void) { - int err; + int not_used; CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr,field_length,(char**)0,&err); + return my_strntod(cs,ptr,field_length,(char**)0,¬_used); } longlong Field_string::val_int(void) { - int err; + int not_used; CHARSET_INFO *cs=charset(); - return my_strntoll(cs,ptr,field_length,10,NULL,&err); + return my_strntoll(cs,ptr,field_length,10,NULL,¬_used); } @@ -4017,7 +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++; - return my_strnncoll(field_charset, (const uchar*)a,a_length, (const uchar*)b,b_length); @@ -4031,7 +4033,6 @@ int Field_string::pack_cmp(const char *b, uint length) while (end > ptr && end[-1] == ' ') end--; uint a_length = (uint) (end - ptr); - return my_strnncoll(field_charset, (const uchar*)ptr,a_length, (const uchar*)b, b_length); @@ -4101,19 +4102,19 @@ int Field_varstring::store(longlong nr) double Field_varstring::val_real(void) { - int err; + int not_used; uint length=uint2korr(ptr)+2; CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr+2,length,(char**)0,&err); + return my_strntod(cs,ptr+2,length,(char**)0, ¬_used); } longlong Field_varstring::val_int(void) { - int err; + int not_used; uint length=uint2korr(ptr)+2; CHARSET_INFO *cs=charset(); - return my_strntoll(cs,ptr+2,length,10,NULL,&err); + return my_strntoll(cs,ptr+2,length,10,NULL, ¬_used); } @@ -4421,26 +4422,26 @@ int Field_blob::store(longlong nr) double Field_blob::val_real(void) { - int err; + 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,&err); + return my_strntod(cs,blob,length,(char**)0, ¬_used); } longlong Field_blob::val_int(void) { - int err; + int not_used; char *blob; memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) return 0; uint32 length=get_length(ptr); - return my_strntoll(charset(),blob,length,10,NULL,&err); + return my_strntoll(charset(),blob,length,10,NULL,¬_used); } @@ -4610,10 +4611,8 @@ void Field_blob::sort_string(char *to,uint length) blob_length=my_strnxfrm(field_charset, (unsigned char *)to, length, (unsigned char *)blob, blob_length); - if (blob_length >= length) - return; - to+=blob_length; - bzero(to,length-blob_length); + if (blob_length < length) + bzero(to+blob_length, length-blob_length); } } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 038a286f4df..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) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1a33ac0760b..aebaf745fc0 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 (global_system_variables.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 @@ -652,12 +649,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)) { @@ -673,16 +671,15 @@ int yylex(void *arg, void *yythd) else #endif { - 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) ; } yylval->lex_str=get_token(lex,yyLength()); 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) { @@ -795,6 +792,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))) { @@ -889,6 +893,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; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e4a17838cd2..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 }; diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index df1609c983d..b47a15d2cfa 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -214,6 +214,7 @@ long my_strntol_8bit(CHARSET_INFO *cs, const char *save, *e; int overflow; + *err= 0; /* Initialize error indicator */ if (base < 0 || base == 1 || base > 36) base = 10; @@ -330,6 +331,7 @@ ulong my_strntoul_8bit(CHARSET_INFO *cs, const char *save, *e; int overflow; + *err= 0; /* Initialize error indicator */ if (base < 0 || base == 1 || base > 36) base = 10; @@ -437,6 +439,7 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)), const char *save; int overflow; + *err= 0; /* Initialize error indicator */ if (base < 0 || base == 1 || base > 36) base = 10; @@ -553,6 +556,7 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs, const char *save; int overflow; + *err= 0; /* Initialize error indicator */ if (base < 0 || base == 1 || base > 36) base = 10; @@ -655,7 +659,8 @@ noconv: cs Character set information str String to convert to double length Optional length for string. - end pointer to end of converted 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 @@ -665,23 +670,28 @@ noconv: It's implemented this way to save a buffer allocation and a memory copy. RETURN - value of number in string + Value of number in string */ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), char *str, uint length, - char **end, int *err __attribute__ ((unused))) + char **end, int *err) { char end_char; double result; + errno= 0; /* Safety */ if (length == INT_MAX32 || str[length] == 0) - return strtod(str, end); - end_char= str[length]; - str[length]= 0; - result= strtod(str, end); - str[length]= end_char; /* Restore end char */ + result= strtod(str, end); + else + { + end_char= str[length]; + str[length]= 0; + result= strtod(str, end); + str[length]= end_char; /* Restore end char */ + } + *err= errno; return result; } diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index e57f35bab19..b247075622e 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2459,7 +2459,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) @@ -2570,7 +2572,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) @@ -2675,7 +2679,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) @@ -2788,7 +2794,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) @@ -2821,7 +2829,8 @@ bs: 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; @@ -2878,7 +2887,7 @@ bs: double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), char *nptr, uint length, - char **endptr, int *err __attribute__ ((unused))) + char **endptr, int *err) { char buf[256]; double res; @@ -2887,7 +2896,8 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), register const char *end; my_wc_t wc; int cnv; - + + *err= 0; /* Cut too long strings */ if (length >= sizeof(buf)) length= sizeof(buf)-1; @@ -2902,7 +2912,9 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), } *b= 0; + errno= 0; res=strtod(buf, endptr); + *err= errno; if (endptr) *endptr=(char*) (*endptr-buf+nptr); return res; From 4b5a313c1a90e7b5d70c5e9dc3ef09f34a386fe4 Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Fri, 17 Jan 2003 21:52:56 +0400 Subject: [PATCH 47/48] new option --local-load in mysqlbinlog --- client/mysqlbinlog.cc | 176 +++++++++++++++++++++++++++++++++++++++++- sql/log_event.cc | 31 ++++++-- sql/log_event.h | 8 ++ 3 files changed, 207 insertions(+), 8 deletions(-) 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/sql/log_event.cc b/sql/log_event.cc index d56bbe53847..924cbf71f51 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1333,7 +1333,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 "); @@ -2220,13 +2223,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 diff --git a/sql/log_event.h b/sql/log_event.h index c4f93c7a9b6..186d3f30f7a 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -445,6 +445,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; @@ -687,6 +694,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); From 545b469948d8ef0b1a502f93483cdb002b2d416a Mon Sep 17 00:00:00 2001 From: "vva@eagle.mysql.r18.ru" <> Date: Fri, 17 Jan 2003 23:34:56 +0400 Subject: [PATCH 48/48] 'removed redundant -I include dirs' returned! --- readline/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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