From f0909cd71a7a1d0904845af4e5e06d213f911de1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 23 Apr 2003 19:37:33 +0500 Subject: [PATCH] SCRUM Protocol_cursor class and sql-common/ directory Makefile.am: pack.c added to linked sources include/mysql.h: net_field_length_ll declaration added include/mysql_com.h: net_field_length declaration added libmysql/Makefile.am: sql-common files symlinked libmysql/Makefile.shared: pack.lo target added libmysql/libmysql.c: net_field_length removed from here sql/Makefile.am: pack.c added to the sources sql/mini_client.cc: mc_net_field_length functions replaced with net_field_length sql/protocol.h: Protocol_cursor class added --- Makefile.am | 2 +- include/mysql.h | 4 ++ include/mysql_com.h | 4 ++ libmysql/Makefile.am | 5 ++ libmysql/Makefile.shared | 4 +- libmysql/libmysql.c | 72 ++------------------ sql-common/pack.c | 64 ++++++++++++++++++ sql/Makefile.am | 6 +- sql/mini_client.cc | 84 +++-------------------- sql/protocol.h | 26 ++++++- sql/protocol_cursor.cc | 143 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 267 insertions(+), 147 deletions(-) create mode 100644 sql-common/pack.c create mode 100644 sql/protocol_cursor.cc diff --git a/Makefile.am b/Makefile.am index f8b559c4238..26c26357400 100644 --- a/Makefile.am +++ b/Makefile.am @@ -70,7 +70,7 @@ linked_netware_sources: #avoid recursive make calls in sql directory linked_server_sources: - cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c + cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c; rm -f pack.c;@LN_CP_F@ ../sql-common/pack.c pack.c echo timestamp > linked_server_sources # Create permission databases diff --git a/include/mysql.h b/include/mysql.h index e2a1ef0850e..af1073237cf 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -597,6 +597,10 @@ simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, unsigned long net_safe_read(MYSQL* mysql); void mysql_once_init(void); +#ifdef _global_h +my_ulonglong net_field_length_ll(uchar **packet); +#endif + #ifdef __NETWARE__ #pragma pack(pop) /* restore alignment */ #endif diff --git a/include/mysql_com.h b/include/mysql_com.h index 7a12413bc23..2cc29f6bd0b 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -330,6 +330,10 @@ void load_defaults(const char *conf_file, const char **groups, my_bool my_thread_init(void); void my_thread_end(void); +#ifdef _global_h +ulong STDCALL net_field_length(uchar **packet); +#endif + #ifdef __cplusplus } #endif diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index c366c034154..2e0a18d4677 100644 --- a/libmysql/Makefile.am +++ b/libmysql/Makefile.am @@ -36,6 +36,7 @@ link_sources: ds=`echo $(dbugobjects) | sed "s;\.lo;.c;g"`; \ ms=`echo $(mysysobjects) | sed "s;\.lo;.c;g"`; \ vs=`echo $(vio_objects) | sed "s;\.lo;.c;g"`; \ + scs=`echo $(sql_cmn_objects) | sed "s;\.lo;.c;g"`; \ for f in $$ss; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ @@ -44,6 +45,10 @@ link_sources: rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../vio/$$f $(srcdir)/$$f; \ done; \ + for f in $$scs; do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ $(srcdir)/../sql-common/$$f $(srcdir)/$$f; \ + done; \ for f in $(mystringsextra); do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(srcdir)/../strings/$$f $(srcdir)/$$f; \ diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 60d6b320bb6..1067bc2bd41 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -63,12 +63,13 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ my_pread.lo mf_cache.lo md5.lo sha1.lo\ my_getopt.lo my_gethostbyname.lo my_port.lo sqlobjects = net.lo +sql_cmn_objects = pack.lo # Not needed in the minimum library mysysobjects2 = my_lib.lo mysysobjects = $(mysysobjects1) $(mysysobjects2) target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \ - $(vio_objects) $(sqlobjects) + $(sql_cmn_objects) $(vio_objects) $(sqlobjects) target_ldflags = -version-info @SHARED_LIB_VERSION@ vio_objects= vio.lo viosocket.lo viossl.lo viosslfactories.lo CLEANFILES = $(target_libadd) $(SHLIBOBJS) \ @@ -85,6 +86,7 @@ clean-local: `echo $(dbugobjects) | sed "s;\.lo;.c;g"` \ `echo $(mysysobjects) | sed "s;\.lo;.c;g"` \ `echo $(vio_objects) | sed "s;\.lo;.c;g"` \ + `echo $(sql_cmn_objects) | sed "s;\.lo;.c;g"` \ $(CHARSET_SRCS) $(CHARSET_OBJS) \ $(mystringsextra) $(mysysheaders) \ ../linked_client_sources net.c diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index c289867b85e..2f64bb3bd44 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -612,71 +612,6 @@ net_safe_read(MYSQL *mysql) return len; } - -/* Get the length of next field. Change parameter to point at fieldstart */ -static ulong -net_field_length(uchar **packet) -{ - reg1 uchar *pos= *packet; - if (*pos < 251) - { - (*packet)++; - return (ulong) *pos; - } - if (*pos == 251) - { - (*packet)++; - return NULL_LENGTH; - } - if (*pos == 252) - { - (*packet)+=3; - return (ulong) uint2korr(pos+1); - } - if (*pos == 253) - { - (*packet)+=4; - return (ulong) uint3korr(pos+1); - } - (*packet)+=9; /* Must be 254 when here */ - return (ulong) uint4korr(pos+1); -} - -/* Same as above, but returns ulonglong values */ - -static my_ulonglong -net_field_length_ll(uchar **packet) -{ - reg1 uchar *pos= *packet; - if (*pos < 251) - { - (*packet)++; - return (my_ulonglong) *pos; - } - if (*pos == 251) - { - (*packet)++; - return (my_ulonglong) NULL_LENGTH; - } - if (*pos == 252) - { - (*packet)+=3; - return (my_ulonglong) uint2korr(pos+1); - } - if (*pos == 253) - { - (*packet)+=4; - return (my_ulonglong) uint3korr(pos+1); - } - (*packet)+=9; /* Must be 254 when here */ -#ifdef NO_CLIENT_LONGLONG - return (my_ulonglong) uint4korr(pos+1); -#else - return (my_ulonglong) uint8korr(pos+1); -#endif -} - - static void free_rows(MYSQL_DATA *cur) { if (cur) @@ -1388,7 +1323,8 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) { uint field; ulong pkt_len,len; - uchar *pos,*prev_pos, *end_pos; + uchar *pos, *end_pos; + uchar *prev_pos; if ((pkt_len=net_safe_read(mysql)) == packet_error) return -1; @@ -1422,7 +1358,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths) } if (prev_pos) *prev_pos=0; /* Terminate prev field */ - prev_pos=pos; + prev_pos= pos; } row[field]=(char*) prev_pos+1; /* End of last field */ *prev_pos=0; /* Terminate last field */ @@ -5009,7 +4945,7 @@ static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row, { MYSQL_TIME tm; - length= read_binary_date(&tm,row); + length= read_binary_date(&tm, row); tm.time_type= MYSQL_TIMESTAMP_DATE; send_data_time(param, tm, length); break; diff --git a/sql-common/pack.c b/sql-common/pack.c new file mode 100644 index 00000000000..e363d600e20 --- /dev/null +++ b/sql-common/pack.c @@ -0,0 +1,64 @@ +#include +#include +#include + +/* Get the length of next field. Change parameter to point at fieldstart */ +ulong STDCALL net_field_length(uchar **packet) +{ + reg1 uchar *pos= (uchar *)*packet; + if (*pos < 251) + { + (*packet)++; + return (ulong) *pos; + } + if (*pos == 251) + { + (*packet)++; + return NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + return (ulong) uint2korr(pos+1); + } + if (*pos == 253) + { + (*packet)+=4; + return (ulong) uint3korr(pos+1); + } + (*packet)+=9; /* Must be 254 when here */ + return (ulong) uint4korr(pos+1); +} + +/* The same as above but returns longlong */ +my_ulonglong net_field_length_ll(uchar **packet) +{ + reg1 uchar *pos= *packet; + if (*pos < 251) + { + (*packet)++; + return (my_ulonglong) *pos; + } + if (*pos == 251) + { + (*packet)++; + return (my_ulonglong) NULL_LENGTH; + } + if (*pos == 252) + { + (*packet)+=3; + return (my_ulonglong) uint2korr(pos+1); + } + if (*pos == 253) + { + (*packet)+=4; + return (my_ulonglong) uint3korr(pos+1); + } + (*packet)+=9; /* Must be 254 when here */ +#ifdef NO_CLIENT_LONGLONG + return (my_ulonglong) uint4korr(pos+1); +#else + return (my_ulonglong) uint8korr(pos+1); +#endif +} + diff --git a/sql/Makefile.am b/sql/Makefile.am index b1d9149ddf4..a4858ab2b38 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -83,9 +83,9 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ slave.cc sql_repl.cc sql_union.cc sql_derived.cc \ - mini_client.cc mini_client_errors.c \ + mini_client.cc mini_client_errors.c pack.c\ stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\ - gstream.cc spatial.cc sql_help.cc + gstream.cc spatial.cc sql_help.cc protocol_cursor.cc gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) @@ -102,6 +102,8 @@ AM_YFLAGS = -d link_sources: rm -f mini_client_errors.c @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c + rm -f pack.c + @LN_CP_F@ ../sql-common/pack.c pack.c gen_lex_hash.o: gen_lex_hash.cc lex.h $(CXXCOMPILE) -c $(INCLUDES) $< diff --git a/sql/mini_client.cc b/sql/mini_client.cc index db3a51712f2..b4441ab910d 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -23,6 +23,7 @@ */ #include + #ifdef HAVE_EXTERNAL_CLIENT /* my_pthread must be included early to be able to fix things */ @@ -80,8 +81,6 @@ void mc_end_server(MYSQL *mysql); static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to); static void mc_free_old_query(MYSQL *mysql); static int mc_send_file_to_server(MYSQL *mysql, const char *filename); -static my_ulonglong mc_net_field_length_ll(uchar **packet); -static ulong mc_net_field_length(uchar **packet); static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths); static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, @@ -1085,15 +1084,15 @@ int mc_mysql_read_query_result(MYSQL *mysql) mc_free_old_query(mysql); /* Free old result */ get_info: pos=(uchar*) mysql->net.read_pos; - if ((field_count= mc_net_field_length(&pos)) == 0) + if ((field_count= net_field_length(&pos)) == 0) { - mysql->affected_rows= mc_net_field_length_ll(&pos); - mysql->insert_id= mc_net_field_length_ll(&pos); + mysql->affected_rows= net_field_length_ll(&pos); + mysql->insert_id= net_field_length_ll(&pos); if (mysql->server_capabilities & CLIENT_TRANSACTIONS) { mysql->server_status=uint2korr(pos); pos+=2; } - if (pos < mysql->net.read_pos+length && mc_net_field_length(&pos)) + if (pos < mysql->net.read_pos+length && net_field_length(&pos)) mysql->info=(char*) pos; DBUG_RETURN(0); } @@ -1107,7 +1106,7 @@ get_info: if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) mysql->server_status|= SERVER_STATUS_IN_TRANS; - mysql->extra_info= mc_net_field_length_ll(&pos); /* Maybe number of rec */ + mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ if (!(fields=mc_read_rows(mysql,(MYSQL_FIELD*) 0,5))) DBUG_RETURN(-1); if (!(mysql->fields=mc_unpack_fields(fields,&mysql->field_alloc, @@ -1190,68 +1189,6 @@ err: DBUG_RETURN(result); } - -/* Get the length of next field. Change parameter to point at fieldstart */ -static ulong mc_net_field_length(uchar **packet) -{ - reg1 uchar *pos= *packet; - if (*pos < 251) - { - (*packet)++; - return (ulong) *pos; - } - if (*pos == 251) - { - (*packet)++; - return NULL_LENGTH; - } - if (*pos == 252) - { - (*packet)+=3; - return (ulong) uint2korr(pos+1); - } - if (*pos == 253) - { - (*packet)+=4; - return (ulong) uint3korr(pos+1); - } - (*packet)+=9; /* Must be 254 when here */ - return (ulong) uint4korr(pos+1); -} - -/* Same as above, but returns ulonglong values */ - -static my_ulonglong mc_net_field_length_ll(uchar **packet) -{ - reg1 uchar *pos= *packet; - if (*pos < 251) - { - (*packet)++; - return (my_ulonglong) *pos; - } - if (*pos == 251) - { - (*packet)++; - return (my_ulonglong) NULL_LENGTH; - } - if (*pos == 252) - { - (*packet)+=3; - return (my_ulonglong) uint2korr(pos+1); - } - if (*pos == 253) - { - (*packet)+=4; - return (my_ulonglong) uint3korr(pos+1); - } - (*packet)+=9; /* Must be 254 when here */ -#ifdef NO_CLIENT_LONGLONG - return (my_ulonglong) uint4korr(pos+1); -#else - return (my_ulonglong) uint8korr(pos+1); -#endif -} - /* Read all rows (fields or data) from server */ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, @@ -1301,7 +1238,7 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, to= (char*) (cur->data+fields+1); for (field=0 ; field < fields ; field++) { - if ((len=(ulong) mc_net_field_length(&cp)) == NULL_LENGTH) + if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH) { /* null field */ cur->data[field] = 0; } @@ -1342,7 +1279,8 @@ static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, { uint field; ulong pkt_len,len; - uchar *pos,*prev_pos; + uchar *pos; + uchar *prev_pos; if ((pkt_len=mc_net_safe_read(mysql)) == packet_error) return -1; @@ -1352,7 +1290,7 @@ static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, pos=mysql->net.read_pos; for (field=0 ; field < fields ; field++) { - if ((len=(ulong) mc_net_field_length(&pos)) == NULL_LENGTH) + if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH) { /* null field */ row[field] = 0; *lengths++=0; @@ -1365,7 +1303,7 @@ static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, } if (prev_pos) *prev_pos=0; /* Terminate prev field */ - prev_pos=pos; + prev_pos= (uchar *)pos; } row[field]=(char*) prev_pos+1; /* End of last field */ *prev_pos=0; /* Terminate last field */ diff --git a/sql/protocol.h b/sql/protocol.h index 89b838ff6e4..dd644afd335 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -22,9 +22,9 @@ class i_string; class THD; -#ifdef EMBEDDED_LIBRARY typedef struct st_mysql_field MYSQL_FIELD; -#endif +typedef struct st_mysql_rows MYSQL_ROWS; + class Protocol { protected: @@ -135,6 +135,28 @@ public: virtual bool store(Field *field); }; +class Protocol_cursor :public Protocol_simple +{ +public: + MEM_ROOT *alloc; + MYSQL_FIELD *fields; + MYSQL_ROWS *data; + MYSQL_ROWS **prev_record; + ulong row_count; + + Protocol_cursor() {} + Protocol_cursor(THD *thd, MEM_ROOT *ini_alloc) :Protocol_simple(thd), alloc(ini_alloc) {} + bool prepare_for_send(List *item_list) + { + fields= NULL; + data= NULL; + prev_record= &data; + return Protocol_simple::prepare_for_send(item_list); + } + bool send_fields(List *list, uint flag); + bool write(); +}; + void send_warning(THD *thd, uint sql_errno, const char *err=0); void net_printf(THD *thd,uint sql_errno, ...); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc new file mode 100644 index 00000000000..19e3bb06d74 --- /dev/null +++ b/sql/protocol_cursor.cc @@ -0,0 +1,143 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Low level functions for storing data to be send to the MySQL client + The actual communction is handled by the net_xxx functions in net_serv.cc +*/ + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +#include "mysql_priv.h" +#include + +bool Protocol_cursor::send_fields(List *list, uint flag) +{ + List_iterator_fast it(*list); + Item *item; + MYSQL_FIELD *field, *client_field; + + DBUG_ENTER("send_fields"); + if (prepare_for_send(list)) + return FALSE; + + fields= (MYSQL_FIELD *)alloc_root(alloc, sizeof(MYSQL_FIELD) * field_count); + if (!fields) + goto err; + + client_field= fields; + while ((item= it++)) + { + Send_field server_field; + item->make_field(&server_field); + + client_field->db= strdup_root(alloc, server_field.db_name); + client_field->table= strdup_root(alloc, server_field.table_name); + client_field->name= strdup_root(alloc, server_field.col_name); + client_field->org_table= strdup_root(alloc, server_field.org_table_name); + client_field->org_name= strdup_root(alloc, server_field.org_col_name); + client_field->length= server_field.length; + client_field->type= server_field.type; + client_field->flags= server_field.flags; + client_field->decimals= server_field.decimals; + client_field->db_length= strlen(client_field->db); + client_field->table_length= strlen(client_field->table); + client_field->name_length= strlen(client_field->name); + client_field->org_name_length= strlen(client_field->org_name); + client_field->org_table_length= strlen(client_field->org_table); + client_field->charsetnr= server_field.charsetnr; + + if (INTERNAL_NUM_FIELD(client_field)) + client_field->flags|= NUM_FLAG; + + if (flag & 2) + { + char buff[80]; + String tmp(buff, sizeof(buff), default_charset_info), *res; + + if (!(res=item->val_str(&tmp))) + client_field->def= strdup_root(alloc, ""); + else + client_field->def= strdup_root(alloc, tmp.ptr()); + } + else + client_field->def=0; + client_field->max_length= 0; + ++client_field; + } + + DBUG_RETURN(FALSE); + err: + send_error(thd, ER_OUT_OF_RESOURCES); /* purecov: inspected */ + DBUG_RETURN(TRUE); /* purecov: inspected */ +} + +/* Get the length of next field. Change parameter to point at fieldstart */ +bool Protocol_cursor::write() +{ + byte *cp= (byte *)packet->ptr(); + byte *end_pos= (byte *)packet->ptr() + packet->length(); + ulong len; + MYSQL_FIELD *cur_field= fields; + MYSQL_FIELD *fields_end= fields + field_count; + MYSQL_ROWS *new_record; + byte **data; + byte *to; + + new_record= (MYSQL_ROWS *)alloc_root(alloc, + sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length()); + if (!new_record) + goto err; + data= (byte **)(new_record + 1); + new_record->data= (char **)data; + + to= (byte *)(fields + field_count + 1); + + for (; cur_field < fields_end; ++cur_field, ++data) + { + if ((len=net_field_length((uchar **)&cp))) + { + *data= 0; + } + else + { + if ((long)len > (end_pos - cp)) + { +// TODO error signal send_error(thd, CR_MALFORMED_PACKET); + return TRUE; + } + memcpy(to,(char*) cp,len); + to[len]=0; + to+=len+1; + cp+=len; + if (cur_field->max_length < len) + cur_field->max_length=len; + } + } + + *prev_record= new_record; + prev_record= &new_record->next; + new_record->next= NULL; + row_count++; + return FALSE; + err: +// TODO error signal send_error(thd, ER_OUT_OF_RESOURCES); + return TRUE; +} + +