===== configure.in 1.309 vs edited ===== --- 1.309/configure.in 2004-10-21 16:11:16 +02:00 +++ edited/configure.in 2004-10-22 04:28:55 +02:00 @@ -2810,7 +2810,7 @@ dnl This probably should be cleaned up more - for now the threaded dnl client is just using plain-old libs. -sql_client_dirs="libmysql client" +sql_client_dirs="libmysql strings regex client" linked_client_targets="linked_libmysql_sources" CLIENT_LIBS=$NON_THREADED_CLIENT_LIBS if test "$THREAD_SAFE_CLIENT" != "no" ===== client/Makefile.am 1.34 vs edited ===== --- 1.34/client/Makefile.am 2004-09-27 16:53:41 +02:00 +++ edited/client/Makefile.am 2004-10-22 02:04:59 +02:00 @@ -17,7 +17,8 @@ # This file is public domain and comes with NO WARRANTY of any kind #AUTOMAKE_OPTIONS = nostdinc -INCLUDES = -I$(top_srcdir)/include $(openssl_includes) +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \ + $(openssl_includes) LIBS = @CLIENT_LIBS@ DEPLIB= ../libmysql/libmysqlclient.la LDADD = @CLIENT_EXTRA_LDFLAGS@ $(DEPLIB) @@ -36,6 +37,7 @@ mysqlimport_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) mysqltest_SOURCES= mysqltest.c ../mysys/my_getsystime.c mysqltest_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) +mysqltest_LDADD = $(LDADD) $(top_builddir)/regex/libregex.a mysqlbinlog_SOURCES = mysqlbinlog.cc ../mysys/mf_tempdir.c mysqlbinlog_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) mysqlmanagerc_SOURCES = mysqlmanagerc.c ===== client/mysqltest.c 1.152 vs edited ===== --- 1.152/client/mysqltest.c 2004-10-20 00:28:33 +02:00 +++ edited/client/mysqltest.c 2004-10-22 00:49:57 +02:00 @@ -53,11 +53,20 @@ #include #include #include +#include /* Error codes */ #include #include #include #include #include +#include /* Our own version of lib */ +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 256 +#endif #define MAX_QUERY 131072 #define MAX_VAR_NAME 256 @@ -93,14 +102,14 @@ enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, - OPT_SSL_CIPHER}; + OPT_SSL_CIPHER,OPT_PS_PROTOCOL}; static int record = 0, opt_sleep=0; static char *db = 0, *pass=0; const char* user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; static int port = 0; static my_bool opt_big_test= 0, opt_compress= 0, silent= 0, verbose = 0, - tty_password= 0; + tty_password= 0, ps_protocol= 0; static uint start_lineno, *lineno; const char* manager_user="root",*manager_host=0; char *manager_pass=0; @@ -139,6 +148,12 @@ static void timer_output(void); static ulonglong timer_now(void); +static regex_t ps_re; /* Holds precompiled re for valid PS statements */ +static void ps_init_re(void); +static int ps_match_re(char *); +static char *ps_eprint(int); + + static const char *embedded_server_groups[] = { "server", "embedded", @@ -1976,6 +1991,9 @@ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + {"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication", + (gptr*) &ps_protocol, (gptr*) &ps_protocol, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"quiet", 's', "Suppress all normal output.", (gptr*) &silent, (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"record", 'r', "Record output of test_file into result file.", @@ -2254,7 +2272,34 @@ * the result will be read - for regular query, both bits must be on */ -int run_query(MYSQL* mysql, struct st_query* q, int flags) +static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags); +static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags); +static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds); +static int run_query_stmt_handle_error(char *query, struct st_query *q, + MYSQL_STMT *stmt, DYNAMIC_STRING *ds); +static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, + DYNAMIC_STRING *ds); + +static int run_query(MYSQL *mysql, struct st_query *q, int flags) +{ + + /* Try to find out if we can run this statement using the + prepared statement protocol. */ + + /* We don't have a mysql_stmt_send_execute() so we only handle + complete SEND+REAP. */ + + /* If it is a '?' in the query it may be a SQL level prepared + statement already and we can't do it twice */ + + if (ps_protocol && + (flags & QUERY_SEND) && (flags & QUERY_REAP) && ps_match_re(q->query)) + return run_query_stmt (mysql, q, flags); + else + return run_query_normal(mysql, q, flags); +} + +static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) { MYSQL_RES* res= 0; uint i; @@ -2264,7 +2309,7 @@ DYNAMIC_STRING eval_query; char* query; int query_len, got_error_on_send= 0; - DBUG_ENTER("run_query"); + DBUG_ENTER("run_query_normal"); DBUG_PRINT("enter",("flags: %d", flags)); if (q->type != Q_EVAL) @@ -2387,56 +2432,14 @@ { if (res) { - MYSQL_FIELD *field, *field_end; + MYSQL_FIELD *field= mysql_fetch_fields(res); uint num_fields= mysql_num_fields(res); if (display_metadata) - { - dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\tColumn_alias\tName\tType\tLength\tMax length\tIs_null\tFlags\tDecimals\tCharsetnr\n"); - for (field= mysql_fetch_fields(res), field_end= field+num_fields ; - field < field_end ; - field++) - { - char buff[22]; - dynstr_append_mem(ds, field->catalog, field->catalog_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->db, field->db_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->org_table, field->org_table_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->table, field->table_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->org_name, field->org_name_length); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, field->name, field->name_length); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->type, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->length, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->max_length, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ? - "N" : "Y"), 1); - dynstr_append_mem(ds, "\t", 1); - - int10_to_str((int) field->flags, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->decimals, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->charsetnr, buff, 10); - dynstr_append(ds, buff); - dynstr_append_mem(ds, "\n", 1); - } - } + run_query_display_metadata(field, num_fields, ds); + if (!display_result_vertically) { - field= mysql_fetch_fields(res); for (i = 0; i < num_fields; i++) { if (i) @@ -2512,6 +2515,542 @@ } +/****************************************************************************\ + * If --ps-protocol run ordinary statements using prepared statemnt C API +\****************************************************************************/ + +/* + We don't have a mysql_stmt_send_execute() so we only handle + complete SEND+REAP +*/ + +static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) +{ + MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ + uint num_rows= 0; + int error= 0; /* Function return code if "goto end;" */ + int err= 0; /* Temporary storage of return code from calls */ + DYNAMIC_STRING *ds; + DYNAMIC_STRING ds_tmp; + DYNAMIC_STRING eval_query; + char *query; + int query_len, got_error_on_execute= 0; + static MYSQL_STMT *stmt= NULL; /* Global data to this function */ + DBUG_ENTER("run_query_stmt"); + + /* Allocate and init stmt if not done before */ + if (!stmt && !(stmt= mysql_stmt_init(mysql))) + die("At line %u: unable init stmt structure"); + + if (q->type != Q_EVAL) + { + query= q->query; + query_len= strlen(query); + } + else + { + init_dynamic_string(&eval_query, "", 16384, 65536); + do_eval(&eval_query, q->query); + query= eval_query.str; + query_len= eval_query.length; + } + DBUG_PRINT("enter", ("query: '%-.60s'", query)); + + if (q->record_file[0]) + { + init_dynamic_string(&ds_tmp, "", 16384, 65536); + ds= &ds_tmp; + } + else + ds= &ds_res; + + /* Store the query into the output buffer if not disabled */ + if (!disable_query_log) + { + replace_dynstr_append_mem(ds,query, query_len); + dynstr_append_mem(ds, delimiter, delimiter_length); + dynstr_append_mem(ds, "\n", 1); + } + + /* + We use the prepared statement interface but there is actually no + '?' in the query. If unpreparable we fall back to use normal + C API. + */ + err= mysql_stmt_prepare(stmt, query, query_len); + + if (err == CR_NO_PREPARE_STMT) + return run_query_normal(mysql, q, flags); + + if (err != 0) + { + if (!q->expected_errno[0]) + { + die("At line %u: unable to prepare statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, + mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + } + else + { + /* + Preparing is part of normal execution and some errors may be expected + */ + error= run_query_stmt_handle_error(query, q, stmt, ds); + goto end; + } + } + + /* We may have got warnings already, collect them if any */ + /* FIXME we only want this if the statement succeeds I think */ + run_query_stmt_handle_warnings(mysql, ds); + + /* + No need to call mysql_stmt_bind_param() because we have no + parameter markers. + + To optimize performance we use a global 'stmt' that is initiated + once. A new prepare will implicitely close the old one. When we + terminate we will lose the connection, this also closes the last + prepared statement. + */ + + if ((got_error_on_execute= mysql_stmt_execute(stmt)) != 0) /* 0 == Success */ + { + if (!q->expected_errno[0]) + { + /* We got an error, unexcpected */ + die("At line %u: unable to execute statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, mysql_stmt_error(stmt), + mysql_stmt_errno(stmt), got_error_on_execute); + } + else + { + /* We got an error, maybe expected */ + error= run_query_stmt_handle_error(query, q, stmt, ds); + goto end; + } + } + + /* If we got here the statement succeeded */ + + if (q->expected_errno[0]) + { + verbose_msg("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0]); + error= 1; + goto end; + } + + /* + We instruct that we want to update the "max_length" field in + mysql_stmt_store_result(), this is our only way to know how much + buffer to allocate for result data + */ + { + my_bool one= 1; + if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, + (void*) &one) != 0) + die("At line %u: unable to set stmt attribute " + "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)", + start_lineno, query, err); + } + + /* + If we got here the statement succeeded and was exptected to do so, + get data + */ + if ((err= mysql_stmt_store_result(stmt)) != 0) + die("At line %u: unable to store result from statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, + mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + + num_rows= mysql_stmt_num_rows(stmt); + + /* + Not all statements creates a result set. If there is one we can + now create another normal result set that contains the meta + data. This set can be handled almost like any other non prepared + statement result set. + */ + if (!disable_result_log && ((res= mysql_stmt_result_metadata(stmt)) != NULL)) + { + /* Take the column count from meta info */ + MYSQL_FIELD *field= mysql_fetch_fields(res); + uint num_fields= mysql_num_fields(res); + + /* FIXME check error from the above? */ + + if (display_metadata) + run_query_display_metadata(field, num_fields, ds); + + if (!display_result_vertically) + { + /* Display the table heading with the names tab separated */ + uint col_idx; + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + if (col_idx) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, field[col_idx].name, + strlen(field[col_idx].name)); + } + dynstr_append_mem(ds, "\n", 1); + } + + /* Now we are to put the real result into the output buffer */ + /* FIXME when it works, create function append_stmt_result() */ + { + MYSQL_BIND *bind; + my_bool *is_null; + unsigned long *length; + /* FIXME we don't handle vertical display ..... */ + uint col_idx, row_idx; + + /* Allocate array with bind structs, lengths and NULL flags */ + bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND), + MYF(MY_WME | MY_FAE)); + length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long), + MYF(MY_WME | MY_FAE)); + is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool), + MYF(MY_WME | MY_FAE)); + + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + /* Allocate data for output */ + /* + FIXME it may be a bug that for non string/blob types + 'max_length' is 0, should try out 'length' in that case + */ + uint max_length= max(field[col_idx].max_length + 1, 1024); + char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE)); + + bind[col_idx].buffer_type= MYSQL_TYPE_STRING; + bind[col_idx].buffer= (char *)str_data; + bind[col_idx].buffer_length= max_length; + bind[col_idx].is_null= &is_null[col_idx]; + bind[col_idx].length= &length[col_idx]; + } + + /* Fill in the data into the structures created above */ + if ((err= mysql_stmt_bind_result(stmt, bind)) != 0) + die("At line %u: unable to bind result to statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, + mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + + /* Read result from each row */ + for (row_idx= 0; row_idx < num_rows; row_idx++) + { + if ((err= mysql_stmt_fetch(stmt)) != 0) + die("At line %u: unable to fetch all rows from statement '%s': " + "%s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, + mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + + /* Read result from each column */ + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + /* FIXME is string terminated? */ + const char *val= (const char *)bind[col_idx].buffer; + ulonglong len= *bind[col_idx].length; + if (col_idx < max_replace_column && replace_column[col_idx]) + { + val= replace_column[col_idx]; + len= strlen(val); + } + if (*bind[col_idx].is_null) + { + val= "NULL"; + len= 4; + } + if (!display_result_vertically) + { + if (col_idx) /* No tab before first col */ + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, len); + } + else + { + dynstr_append(ds, field[col_idx].name); + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, len); + dynstr_append_mem(ds, "\n", 1); + } + } + if (!display_result_vertically) + dynstr_append_mem(ds, "\n", 1); + } + + if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA) + die("At line %u: fetch didn't end with MYSQL_NO_DATA from statement " + "'%s': %s (mysql_stmt_errno=%d returned=%d)", + start_lineno, query, + mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + + free_replace_column(); + + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + /* Free data for output */ + my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE)); + } + /* Free array with bind structs, lengths and NULL flags */ + my_free((gptr)bind , MYF(MY_WME | MY_FAE)); + my_free((gptr)length , MYF(MY_WME | MY_FAE)); + my_free((gptr)is_null , MYF(MY_WME | MY_FAE)); + } + + /* Add all warnings to the result */ + run_query_stmt_handle_warnings(mysql, ds); + + if (!disable_info) + { + char buf[40]; + sprintf(buf,"affected rows: %lu\n",(ulong) mysql_affected_rows(mysql)); + dynstr_append(ds, buf); + if (mysql_info(mysql)) + { + dynstr_append(ds, "info: "); + dynstr_append(ds, mysql_info(mysql)); + dynstr_append_mem(ds, "\n", 1); + } + } + + } + + if (record) + { + if (!q->record_file[0] && !result_file) + die("At line %u: Missing result file", start_lineno); + if (!result_file) + str_to_file(q->record_file, ds->str, ds->length); + } + else if (q->record_file[0]) + { + error= check_result(ds, q->record_file, q->require_file); + } + if (res) + mysql_free_result(res); /* Free normal result set with meta data */ + last_result= 0; /* FIXME have no idea what this is about... */ + + if (err >= 1) + mysql_error(mysql); /* FIXME strange, has no effect... */ + +end: + free_replace(); + last_result=0; + if (ds == &ds_tmp) + dynstr_free(&ds_tmp); + if (q->type == Q_EVAL) + dynstr_free(&eval_query); + DBUG_RETURN(error); +} + + +/****************************************************************************\ + * Broken out sub functions to run_query_stmt() +\****************************************************************************/ + +static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, + DYNAMIC_STRING *ds) +{ + uint col_idx; + dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t" + "Column_alias\tName\tType\tLength\tMax length\tIs_null\t" + "Flags\tDecimals\tCharsetnr\n"); + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + char buff[22]; + dynstr_append_mem(ds, field[col_idx].catalog, + field[col_idx].catalog_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field[col_idx].db, field[col_idx].db_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field[col_idx].org_table, + field[col_idx].org_table_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field[col_idx].table, + field[col_idx].table_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field[col_idx].org_name, + field[col_idx].org_name_length); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, field[col_idx].name, field[col_idx].name_length); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field[col_idx].type, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field[col_idx].length, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field[col_idx].max_length, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field[col_idx].flags) ? + "N" : "Y"), 1); + dynstr_append_mem(ds, "\t", 1); + + int10_to_str((int) field[col_idx].flags, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field[col_idx].decimals, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\t", 1); + int10_to_str((int) field[col_idx].charsetnr, buff, 10); + dynstr_append(ds, buff); + dynstr_append_mem(ds, "\n", 1); + } +} + +static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) +{ + if (!disable_warnings && mysql_warning_count(mysql)) + { + MYSQL_RES *warn_res=0; + uint count= mysql_warning_count(mysql); + if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0) + { + warn_res= mysql_store_result(mysql); + } + if (!warn_res) + verbose_msg("Warning count is %u but didn't get any warnings\n", count); + else + { + dynstr_append_mem(ds, "Warnings:\n", 10); + append_result(ds, warn_res); + mysql_free_result(warn_res); + } + } +} + +static int run_query_stmt_handle_error(char *query, struct st_query *q, + MYSQL_STMT *stmt, DYNAMIC_STRING *ds) +{ + if (q->require_file) /* FIXME don't understand this one */ + { + abort_not_supported_test(); + } + + if (q->abort_on_error) + die("At line %u: query '%s' failed: %d: %s", start_lineno, query, + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + else + { + int i; + + for (i=0 ; (uint) i < q->expected_errors ; i++) + { + if ((q->expected_errno[i] == mysql_stmt_errno(stmt))) + { + if (i == 0 && q->expected_errors == 1) + { + /* Only log error if there is one possible error */ + dynstr_append_mem(ds,"ERROR ",6); + replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt), + strlen(mysql_stmt_sqlstate(stmt))); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append_mem(ds,mysql_stmt_error(stmt), + strlen(mysql_stmt_error(stmt))); + dynstr_append_mem(ds,"\n",1); + } + /* Don't log error if we may not get an error */ + else if (q->expected_errno[0] != 0) + dynstr_append(ds,"Got one of the listed errors\n"); + return 0; /* Ok */ + } + } + DBUG_PRINT("info",("i: %d expected_errors: %d", i, + q->expected_errors)); + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt), + strlen(mysql_stmt_sqlstate(stmt))); + dynstr_append_mem(ds,": ",2); + replace_dynstr_append_mem(ds, mysql_stmt_error(stmt), + strlen(mysql_stmt_error(stmt))); + dynstr_append_mem(ds,"\n",1); + if (i) + { + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_stmt_errno(stmt), q->expected_errno[0]); + return 1; /* Error */ + } + verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + /* + if we do not abort on error, failure to run the query does + not fail the whole test case + */ + return 0; + } + + return 0; +} + +/****************************************************************************\ + * Functions to match SQL statements that can be prepared +\****************************************************************************/ + +static void ps_init_re(void) +{ + const char *ps_re_str = + "^(" + "[[:space:]]*REPLACE[[:space:]]|" + "[[:space:]]*INSERT[[:space:]]|" + "[[:space:]]*UPDATE[[:space:]]|" + "[[:space:]]*DELETE[[:space:]]|" + "[[:space:]]*SELECT[[:space:]]|" + "[[:space:]]*CREATE[[:space:]]+TABLE[[:space:]]|" + "[[:space:]]*DO[[:space:]]|" + "[[:space:]]*SET[[:space:]]+OPTION[[:space:]]|" + "[[:space:]]*DELETE[[:space:]]+MULTI[[:space:]]|" + "[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|" + "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])"; + + int err= regcomp(&ps_re, ps_re_str, (REG_EXTENDED | REG_ICASE | REG_NOSUB), + &my_charset_latin1); + if (err) + { + char erbuf[100]; + int len= regerror(err, &ps_re, erbuf, sizeof(erbuf)); + fprintf(stderr, "error %s, %d/%d `%s'\n", + ps_eprint(err), len, (int)sizeof(erbuf), erbuf); + exit(1); + } +} + + +static int ps_match_re(char *stmt_str) +{ + int err= regexec(&ps_re, stmt_str, (size_t)0, NULL, 0); + + if (err == 0) + return 1; + else if (err == REG_NOMATCH) + return 0; + else + { + char erbuf[100]; + int len= regerror(err, &ps_re, erbuf, sizeof(erbuf)); + fprintf(stderr, "error %s, %d/%d `%s'\n", + ps_eprint(err), len, (int)sizeof(erbuf), erbuf); + exit(1); + } +} + +static char *ps_eprint(int err) +{ + static char epbuf[100]; + size_t len= regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf)); + assert(len <= sizeof(epbuf)); + return(epbuf); +} + + +/****************************************************************************/ + void get_query_type(struct st_query* q) { char save; @@ -2665,6 +3204,8 @@ if (manager_host) init_manager(); #endif + if (ps_protocol) + ps_init_re(); if (!( mysql_init(&cur_con->mysql))) die("Failed in mysql_init()"); if (opt_compress) ===== libmysqld/examples/Makefile.am 1.18 vs edited ===== --- 1.18/libmysqld/examples/Makefile.am 2004-08-23 13:55:33 +02:00 +++ edited/libmysqld/examples/Makefile.am 2004-10-22 07:52:22 +02:00 @@ -14,13 +14,14 @@ DEFS = -DEMBEDDED_LIBRARY INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include -I$(srcdir) \ - -I$(top_srcdir) -I$(top_srcdir)/client $(openssl_includes) + -I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \ + $(openssl_includes) LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @innodb_system_libs@ @LIBDL@ $(CXXLDFLAGS) mysqltest_LINK = $(CXXLINK) - mysqltest_SOURCES = mysqltest.c +mysqltest_LDADD = $(LDADD) $(top_builddir)/regex/libregex.a mysql_SOURCES = mysql.cc readline.cc completion_hash.cc \ my_readline.h sql_string.h completion_hash.h ===== mysql-test/mysql-test-run.sh 1.220 vs edited ===== --- 1.220/mysql-test/mysql-test-run.sh 2004-10-08 20:38:05 +02:00 +++ edited/mysql-test/mysql-test-run.sh 2004-10-22 00:56:26 +02:00 @@ -321,6 +321,8 @@ EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" SLEEP_TIME_AFTER_RESTART=`$ECHO "$1" | $SED -e "s;--sleep=;;"` ;; + --ps-protocol) + EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; --user-test=*) USER_TEST=`$ECHO "$1" | $SED -e "s;--user-test=;;"` ;;