Browse Source
Merge trift2.:/MySQL/M51/mysql-5.1
Merge trift2.:/MySQL/M51/mysql-5.1
into trift2.:/MySQL/M51/push-5.1 BUILD/check-cpu: Auto merged BitKeeper/deleted/.del-libmysqld.vcproj~a75d5b9a5967dea0: Auto merged BitKeeper/deleted/.del-make_win_bin_dist: Auto merged BitKeeper/deleted/.del-mysql.sln~76a9ff1e793b3547: Auto merged BitKeeper/deleted/.del-mysqld.vcproj~6aa7b3f9c3e28fcb: Auto merged BitKeeper/deleted/.del-mysqldemb.vcproj~54c64d55ccc51a7c: Auto merged BitKeeper/deleted/.del-mysys.vcproj~40a49d09c4184822: Auto merged BitKeeper/deleted/.del-vio.vcproj~b7c21b4e2d6a9b85: Auto merged mysql-test/mysql-test-run.pl: Auto mergedpull/374/head
10 changed files with 31 additions and 2096 deletions
-
26BUILD/check-cpu
-
37Docs/.cvsignore
-
101Docs/internals.texi
-
2Docs/linuxthreads.txt
-
140Docs/my_sys.txt
-
943Docs/net_doc.txt
-
2extra/yassl/taocrypt/benchmark/Makefile.am
-
12mysql-test/mysql-test-run.pl
-
250scripts/fill_func_tables.sh
-
614scripts/fill_help_tables.sh
@ -1,40 +1,5 @@ |
|||
COPYING |
|||
COPYING.LIB |
|||
INSTALL-SOURCE |
|||
INSTALL-BINARY |
|||
Makefile |
|||
Makefile.in |
|||
Manual-updates |
|||
before-gpl-changes-manual.texi |
|||
include.texi |
|||
manual-before-gpl.texi |
|||
manual-tmp.aux |
|||
manual-tmp.cp |
|||
manual-tmp.fn |
|||
manual-tmp.ky |
|||
manual-tmp.log |
|||
manual-tmp.pdf |
|||
manual-tmp.pg |
|||
manual-tmp.texi |
|||
manual-tmp.toc |
|||
manual-tmp.tp |
|||
manual-tmp.vr |
|||
manual.aux |
|||
manual.cp |
|||
manual.cps |
|||
manual.fn |
|||
manual.fns |
|||
manual.html |
|||
manual.ky |
|||
manual.log |
|||
manual.pdf |
|||
manual.pg |
|||
manual.toc |
|||
manual.tp |
|||
manual.txt |
|||
manual.vr |
|||
manual_a4.ps |
|||
manual_a4.ps.gz |
|||
manual_letter.ps |
|||
manual_letter.ps.gz |
|||
manual_toc.html |
|||
mysql.info |
@ -1,101 +0,0 @@ |
|||
\input texinfo @c -*-texinfo-*- |
|||
@c |
|||
@c ********************************************************* |
|||
@c |
|||
@c This is a dummy placeholder file for internals.texi in the |
|||
@c MySQL source trees. |
|||
@c |
|||
@c Note, that the internals documentation has been moved into a separate |
|||
@c BitKeeper source tree named "mysqldoc" - do not attempt to edit this |
|||
@c file! All changes to internals.texi should be done in the mysqldoc tree. |
|||
@c |
|||
@c See http://www.mysql.com/doc/en/Installing_source_tree.html |
|||
@c for information about how to work with BitKeeper source trees. |
|||
@c |
|||
@c This dummy file is being replaced with the actual file from the |
|||
@c mysqldoc tree when building the official source distribution. |
|||
@c |
|||
@c Please e-mail docs@mysql.com for more information or if |
|||
@c you are interested in doing a translation. |
|||
@c |
|||
@c ********************************************************* |
|||
@c |
|||
@c %**start of header |
|||
|
|||
@setfilename internals.info |
|||
|
|||
@c We want the types in the same index |
|||
@syncodeindex tp fn |
|||
|
|||
@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=silver 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 <ahr@YogElements.com> |
|||
@set _extra_head <style> code {color:purple} tt {color:green} samp {color:navy} pre {color:maroon} </style> |
|||
|
|||
@settitle Dummy MySQL internals documentation for version @value{mysql_version}. |
|||
|
|||
@c We want single-sided heading format, with chapters on new pages. To |
|||
@c get double-sided format change 'on' below to 'odd' |
|||
@setchapternewpage on |
|||
|
|||
@paragraphindent 0 |
|||
|
|||
@c %**end of header |
|||
|
|||
@ifinfo |
|||
@format |
|||
START-INFO-DIR-ENTRY |
|||
* mysql: (mysql). MySQL documentation. |
|||
END-INFO-DIR-ENTRY |
|||
@end format |
|||
@end ifinfo |
|||
|
|||
@titlepage |
|||
@sp 10 |
|||
@center @titlefont{Empty placeholder for the MySQL Internals Documentation} |
|||
@sp 10 |
|||
@center 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. |
|||
@page |
|||
@end titlepage |
|||
|
|||
@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 |
|||
|
|||
@oddheading @thischapter @| @| @thispage |
|||
@evenheading @thispage @| @| MySQL Internal Reference for Version @value{mysql_version} |
|||
|
|||
@end iftex |
|||
|
|||
@node Top, (dir), (dir), (dir) |
|||
|
|||
@ifinfo |
|||
This is an empty placeholder file for the MySQL internals documentation. |
|||
|
|||
The real version of this file is now maintained in a separate BitKeeper |
|||
source tree! Please see |
|||
@url{http://www.mysql.com/doc/en/Installing_source_tree.html} for more info |
|||
on how to work with BitKeeper. |
|||
|
|||
Please do not attempt to edit this file directly - use the one in the |
|||
@code{mysqldoc} BK tree instead. |
|||
|
|||
This file will be replaced with the current @code{internals.texi} when |
|||
building the official source distribution. |
|||
@end ifinfo |
|||
|
|||
@bye |
@ -1,140 +0,0 @@ |
|||
Functions i mysys: (For flags se my_sys.h) |
|||
|
|||
int my_copy _A((const char *from,const char *to,myf MyFlags)); |
|||
- Copy file |
|||
|
|||
int my_delete _A((const char *name,myf MyFlags)); |
|||
- Delete file |
|||
|
|||
int my_getwd _A((string buf,uint size,myf MyFlags)); |
|||
int my_setwd _A((const char *dir,myf MyFlags)); |
|||
- Get and set working directory |
|||
|
|||
string my_tempnam _A((const char *pfx,myf MyFlags)); |
|||
- Make a uniq temp file name by using dir and adding something after |
|||
pfx to make name uniq. Name is made by adding a uniq 6 length-string |
|||
and TMP_EXT after pfx. |
|||
Returns pointer to malloced area for filename. Should be freed by |
|||
free(). |
|||
|
|||
File my_open _A((const char *FileName,int Flags,myf MyFlags)); |
|||
File my_create _A((const char *FileName,int CreateFlags, |
|||
int AccsesFlags, myf MyFlags)); |
|||
int my_close _A((File Filedes,myf MyFlags)); |
|||
uint my_read _A((File Filedes,byte *Buffer,uint Count,myf MyFlags)); |
|||
uint my_write _A((File Filedes,const byte *Buffer,uint Count, |
|||
myf MyFlags)); |
|||
ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags)); |
|||
ulong my_tell _A((File fd,myf MyFlags)); |
|||
- Use instead of open,open-with-create-flag, close read and write |
|||
to get automatic error-messages (flag: MYF_WME) and only have |
|||
to test for != 0 if error (flag: MY_NABP). |
|||
|
|||
int my_rename _A((const char *from,const char *to,myf MyFlags)); |
|||
- Rename file |
|||
|
|||
FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags)); |
|||
FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags)); |
|||
int my_fclose _A((FILE *fd,myf MyFlags)); |
|||
uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags)); |
|||
uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count, |
|||
myf MyFlags)); |
|||
ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags)); |
|||
ulong my_ftell _A((FILE *stream,myf MyFlags)); |
|||
- Same read-interface for streams as for files |
|||
|
|||
gptr _mymalloc _A((uint uSize,const char *sFile, |
|||
uint uLine, myf MyFlag)); |
|||
gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile, |
|||
uint uLine, myf MyFlag)); |
|||
void _myfree _A((gptr pPtr,const char *sFile,uint uLine)); |
|||
int _sanity _A((const char *sFile,unsigned int uLine)); |
|||
gptr _myget_copy_of_memory _A((const byte *from,uint length, |
|||
const char *sFile, uint uLine, |
|||
myf MyFlag)); |
|||
- malloc(size,myflag) is mapped to this functions if not compiled |
|||
with -DSAFEMALLOC |
|||
|
|||
void TERMINATE _A((void)); |
|||
- Writes malloc-info on stdout if compiled with -DSAFEMALLOC. |
|||
|
|||
int my_chsize _A((File fd,ulong newlength,myf MyFlags)); |
|||
- Change size of file |
|||
|
|||
void my_error _D((int nr,myf MyFlags, ...)); |
|||
- Writes message using error number (se mysys/errors.h) on |
|||
stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called. |
|||
|
|||
void my_message _A((const char *str,myf MyFlags)); |
|||
- Writes message-string on |
|||
stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called. |
|||
|
|||
void my_init _A((void )); |
|||
- Start each program (in main) with this. |
|||
void my_end _A((int infoflag)); |
|||
- Gives info about program. |
|||
- If infoflag & MY_CHECK_ERROR prints if some files are left open |
|||
- If infoflag & MY_GIVE_INFO prints timing info and malloc info |
|||
about prog. |
|||
|
|||
int my_redel _A((const char *from, const char *to, int MyFlags)); |
|||
- Delete from before rename of to to from. Copyes state from old |
|||
file to new file. If MY_COPY_TIME is set sets old time. |
|||
|
|||
int my_copystat _A((const char *from, const char *to, int MyFlags)); |
|||
- Copye state from old file to new file. |
|||
If MY_COPY_TIME is set sets copy also time. |
|||
|
|||
string my_filename _A((File fd)); |
|||
- Give filename of open file. |
|||
|
|||
int dirname _A((string to,const char *name)); |
|||
- Copy name of directory from filename. |
|||
|
|||
int test_if_hard_path _A((const char *dir_name)); |
|||
- Test if dirname is a hard path (Starts from root) |
|||
|
|||
void convert_dirname _A((string name)); |
|||
- Convert dirname acording to system. |
|||
- In MSDOS changes all caracters to capitals and changes '/' to |
|||
'\' |
|||
string fn_ext _A((const char *name)); |
|||
- Returns pointer to extension in filename |
|||
string fn_format _A((string to,const char *name,const char *dsk, |
|||
const char *form,int flag)); |
|||
format a filename with replace of library and extension and |
|||
converts between different systems. |
|||
params to and name may be identicall |
|||
function dosn't change name if name != to |
|||
Flag may be: 1 force replace filnames library with 'dsk' |
|||
2 force replace extension with 'form' */ |
|||
4 force Unpack filename (replace ~ with home) |
|||
8 Pack filename as short as possibly for output to |
|||
user. |
|||
All open requests should allways use at least: |
|||
"open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and |
|||
convert filename to system-form. |
|||
|
|||
string fn_same _A((string toname,const char *name,int flag)); |
|||
- Copys directory and extension from name to toname if neaded. |
|||
copy can be forced by same flags that in fn_format. |
|||
|
|||
int wild_compare _A((const char *str,const char *wildstr)); |
|||
- Compare if str matches wildstr. Wildstr can contain "*" and "?" |
|||
as match-characters. |
|||
Returns 0 if match. |
|||
|
|||
void get_date _A((string to,int timeflag)); |
|||
- Get current date in a form ready for printing. |
|||
|
|||
void soundex _A((string out_pntr, string in_pntr)) |
|||
- Makes in_pntr to a 5 chars long string. All words that sounds |
|||
alike have the same string. |
|||
|
|||
int init_key_cache _A((ulong use_mem,ulong leave_this_much_mem)); |
|||
- Use cacheing of keys in MISAM, PISAM, and ISAM. |
|||
KEY_CACHE_SIZE is a good size. |
|||
- Remember to lock databases for optimal cacheing |
|||
|
|||
void end_key_cache _A((void)); |
|||
- End key-cacheing. |
@ -1,943 +0,0 @@ |
|||
MySQL Client/Server Protocol Documentation |
|||
|
|||
|
|||
|
|||
Introduction |
|||
------------ |
|||
|
|||
|
|||
This paper has the objective of presenting a through description |
|||
of the client/server protocol that is embodied in MySQL. Particularly, |
|||
this paper aims to document and describe: |
|||
|
|||
- manner in which MySQL server detects client connection requests and |
|||
creates connection |
|||
- manner in which MySQL client C API call connects to server - the |
|||
entire protocol of sending/receiving data by MySQL server and C API |
|||
code |
|||
- manner in which queries are sent by client C API calls to server |
|||
- manner in which query results are sent by server |
|||
- manner in which query results are resolved by server |
|||
- sending and receiving of error messages |
|||
|
|||
|
|||
This paper does not have the goal or describing nor documenting other |
|||
related MySQL issues, like usage of thread libraries, MySQL standard |
|||
library set, MySQL strings library and other MySQL specific libraries, |
|||
type definitions and utilities. |
|||
|
|||
Issues that are covered by this paper are contained in the following |
|||
source code files: |
|||
|
|||
- libmysql/net.c and sql/net_serv.cc, the two being identical |
|||
- client/libmysql.c (not entire file is covered) |
|||
- include/mysql_com.h |
|||
- include/mysql.h |
|||
- sql/mysqld.cc (not entire file is covered) |
|||
- sql/net_pkg.cc |
|||
- sql/sql_base.cc (not entire file is covered) |
|||
- sql/sql_select.cc (not entire file is covered) |
|||
- sql/sql_parse.cc (not entire file is covered) |
|||
|
|||
Note: libmysql/net.c was client/net.c prior to MySQL 3.23.11. |
|||
sql/net_serv.cc was sql/net_serv.c prior to MySQL 3.23.16. |
|||
|
|||
Beside this introduction this paper presents basic definitions, |
|||
constants, structures and global variables, all related functions in |
|||
server and in C API. Textual description of the entire protocol |
|||
functioning is described in the last chapter of this paper. |
|||
|
|||
|
|||
Constants, structures and global variables |
|||
------------------------------------------ |
|||
|
|||
This chapter will describe all constants, structures and |
|||
global variables relevant to client/server protocol. |
|||
|
|||
Constants |
|||
|
|||
They are important as they contain default values, the ones |
|||
that are valid if options are not set in any other way. Beside that |
|||
MySQL source code does not contain a single non-defined constant in |
|||
its code. This description of constants does not include |
|||
configuration and conditional compilation #defines. |
|||
|
|||
NAME_LEN - field and table name length, current value 64 |
|||
HOSTNAME_LENGTH - length of the hostname, current value 64 |
|||
USERNAME_LENGTH - username length, current value 16 |
|||
MYSQL_PORT - default TCP/IP port number, current value 3306 |
|||
MYSQL_UNIX_ADDR - full path of the default Unix socket file, current value |
|||
"/tmp/mysql.sock" |
|||
MYSQL_NAMEDPIPE - full path of the default NT pipe file, current value |
|||
"MySQL" |
|||
MYSQL_SERVICENAME - name of the MySQL Service on NT, current value "MySQL" |
|||
NET_HEADER_SIZE - size of the network header, when no |
|||
compression is used, current value 4 |
|||
COMP_HEADER_SIZE - additional size of network header when |
|||
compression is used, current value 3 |
|||
|
|||
What follows are set of constants, defined in source only, which |
|||
define capabilities of the client built with that version of C |
|||
API. Simply, when some new feature is added in client, that client |
|||
feature is defined, so that server can detect what capabilities a |
|||
client program has. |
|||
|
|||
CLIENT_LONG_PASSWORD - client supports new more secure passwords |
|||
CLIENT_LONG_FLAG - client uses longer flags |
|||
CLIENT_CONNECT_WITH_DB - client can specify db on connect |
|||
CLIENT_COMPRESS - client can use compression protocol |
|||
CLIENT_ODBC - ODBC client |
|||
CLIENT_LOCAL_FILES - client can use LOAD DATA INFILE LOCAL |
|||
CLIENT_IGNORE_SPACE - client can ignore spaces before '(' |
|||
CLIENT_CHANGE_USER - client supports the mysql_change_user() |
|||
|
|||
What follows are other constants, pertaining to timeouts and sizes |
|||
|
|||
MYSQL_ERRMSG_SIZE - maximum size of error message string, current value 200 |
|||
NET_READ_TIMEOUT - read timeout, current value 30 seconds |
|||
NET_WRITE_TIMEOUT - write timeout, current value 60 seconds |
|||
NET_WAIT_TIMEOUT - wait for new query timeout, current value 8*60*60 |
|||
seconds, that is, 8 hours |
|||
packet_error - value returned in case of socket errors, current |
|||
value -1 |
|||
TES_BLOCKING - used in debug mode for setting up blocking testing |
|||
RETRY COUNT - number of times network read and write will be |
|||
retried, current value 1 |
|||
|
|||
There are also error messages for last_errno, which depict system |
|||
errors, and are used on the server only. |
|||
|
|||
ER_NET_PACKAGE_TOO_LARGE - packet is larger than max_allowed_packet |
|||
ER_OUT_OF_RESOURCES - practically no more memory |
|||
ER_NET_ERROR_ON_WRITE - error in writing to NT Named Pipe |
|||
ER_NET_WRITE_INTERRUPTED - some signal or interrupt happened |
|||
during write |
|||
ER_NET_READ_ERROR_FROM_PIPE - error in reading from NT Named Pipe |
|||
ER_NET_FCNTL_ERROR - error in trying to set fcntl on socket |
|||
descriptor |
|||
ER_NET_PACKETS_OUT_OF_ORDER - packet numbers on client and |
|||
server side differ |
|||
ER_NET_UNCOMPRESS_ERROR - error in uncompress of compressed packet |
|||
|
|||
|
|||
Structs and enums |
|||
|
|||
|
|||
struct NET |
|||
|
|||
This is MySQL's network handle structure, used in all client/server |
|||
read/write functions. On the server, it is initialized and preserved |
|||
in each thread. On the client, it is a part of the MYSQL struct, |
|||
which is the MySQL handle used in all C API functions. This structure |
|||
uniquely identifies a connection, either on the server or client |
|||
side. It consists of the following fields: |
|||
|
|||
Vio* vio - explained above |
|||
HANDLE hPipe - Handle for NT Named Pipe file |
|||
my_socket fd - file descriptor used for both TCP/IP socket and |
|||
Unix socket file |
|||
int fcntl - contains info on fcntl options used on fd. Mostly |
|||
used for saving info if blocking is used or not |
|||
unsigned char *buff - network buffer used for storing data for |
|||
reading from/writing to socket |
|||
unsigned char,*buff_end - points to the end of buff |
|||
unsigned char *write_pos - present writing position in buff |
|||
unsigned char *read_pos - present reading position in buff. This |
|||
pointer is used for reading data after |
|||
calling my_net_read function and function |
|||
that are just its wrappers |
|||
char last_error[MYSQL_ERRMSG_SIZE] - holds last error message |
|||
unsigned int last_errno - holds last error code of the network |
|||
protocol. Its possible values are listed |
|||
in above constants. It is used only on |
|||
the server side |
|||
unsigned int max_packet - holds current value of buff size |
|||
unsigned int timeout - stores read timeout value for that connection |
|||
unsigned int pkt_nr - stores the value of the current packet number in |
|||
a batch of packets. Used primarily for |
|||
detection of protocol errors resulting in a |
|||
mismatch |
|||
my_bool error - holds either 1 or 0 depending on the error condition |
|||
my_bool return_errno - if its value != 0 then there is an error in |
|||
protocol mismatch between client and server |
|||
my_bool compress - if true compression is used in the protocol |
|||
unsigned long remain_in_buf - used only in reading compressed packets. |
|||
Explained in my_net_read |
|||
unsigned long length - used only for storing the length of the read |
|||
packet. Explained in my_net_read |
|||
unsigned long buf_length - used only in reading compressed packets. |
|||
Explained in my_net_read |
|||
unsigned long where_b - used only in reading compressed packets. |
|||
Explained in my_net_read |
|||
short int more - used for reporting in mysql_list_processes |
|||
char save_char - used in reading compressed packets for saving chars |
|||
in order to make zero-delimited strings. Explained |
|||
in my_net_read |
|||
|
|||
A few typedefs will be defined for easier understanding of the text that |
|||
follows. |
|||
|
|||
typedef char **MYSQL_ROW - data containing one row of values |
|||
|
|||
typedef unsigned int MYSQL_FIELD_OFFSET - offset in bytes of the current field |
|||
|
|||
typedef MYSQL_ROWS *MYSQL_ROW_OFFSET - offset in bytes of the current row |
|||
|
|||
struct MYSQL_FIELD - contains all info on the attributes of a |
|||
specific column in a result set, plus info on lengths of the column in |
|||
a result set. This struct is tagged as st_mysql_field. This structure |
|||
consists of the following fields: |
|||
|
|||
char *name - name of column |
|||
char *table - table of column if column was a field and not |
|||
an expression or constant |
|||
char *def - default value (set by mysql_list_fields) |
|||
enum enum_field_types type - see above |
|||
unsigned int length - width of column in the current row |
|||
unsigned int max_length - maximum width of that column in entire |
|||
result set |
|||
unsigned int flags - corresponding to Extra in DESCRIBE |
|||
unsigned int decimals - number of decimals in field |
|||
|
|||
|
|||
struct MYSQL_ROWS - a node for each row in the single linked |
|||
list forming entire result set. This struct is tagged as |
|||
st_mysql_rows, and has two fields: |
|||
|
|||
struct st_mysql_rows *next - pointer to the next one |
|||
MYSQL_ROW data - see above |
|||
|
|||
|
|||
struct MYSQL_DATA - contains all rows from result set. It is |
|||
tagged as st_mysql_data and has following fields: |
|||
|
|||
my_ulonglong rows - how many rows |
|||
unsigned int fields - how many columns |
|||
MYSQL_ROWS *data - see above. This is the first node of the linked list |
|||
MEM_ROOT alloc - MEM_ROOT is MySQL memory allocation structure, and |
|||
this field is used to store all fields and rows. |
|||
|
|||
|
|||
struct st_mysql_options - holds various client options, and |
|||
contains following fields: |
|||
|
|||
unsigned int connect_timeout - time in seconds for connection |
|||
unsigned int client_flag - used to hold client capabilities |
|||
my_bool compress - boolean for compression |
|||
my_bool named_pipe - is Named Pipe used? (on NT) |
|||
unsigned int port - what TCP port is used |
|||
char *host - host to connect to |
|||
char *init_command - command to be executed upon connection |
|||
char *user - account name on MySQL server |
|||
char *password - password for the above |
|||
char *unix_socket - full path for Unix socket file |
|||
char *db - default database |
|||
char *my_cnf_file - optional configuration file |
|||
char *my_cnf_group - optional header for options |
|||
|
|||
|
|||
struct MYSQL - MySQL client's handle. Required for any |
|||
operation issued from client to server. Tagged as st_mysql and having |
|||
following fields: |
|||
|
|||
NET net - see above |
|||
char *host - host on which MySQL server is running |
|||
char *user - MySQL username |
|||
char *passwd - password for above |
|||
char *unix_socket- full path of Unix socket file |
|||
char *server_version - version of the server |
|||
char *host_info - contains info on how has connection been |
|||
established, TCP port, socket or Named Pipe |
|||
char *info - used to store information on the query results, |
|||
like number of rows affected etc. |
|||
char *db - current database |
|||
unsigned int port - TCP port in use |
|||
unsigned int client_flag - client capabilities |
|||
unsigned int server_capabilities - server capabilities |
|||
unsigned int protocol_version - version of the protocol |
|||
unsigned int field_count - used for storing number of fields |
|||
immediately upon execution of a query, |
|||
but before fetching rows |
|||
unsigned long thread_id - server thread to which this connection |
|||
is attached |
|||
my_ulonglong affected_rows - used for storing number of rows |
|||
immediately upon execution of a query, |
|||
but before fetching rows |
|||
my_ulonglong insert_id - fetching LAST_INSERT_ID() through client C API |
|||
my_ulonglong extra_info - used by mysqlshow |
|||
unsigned long packet_length - saving size of the first packet upon |
|||
execution of a query |
|||
enum mysql_status status - see above |
|||
MYSQL_FIELD *fields - see above |
|||
MEM_ROOT field_alloc - memory used for storing previous field (fields) |
|||
my_bool free_me - boolean that flags if MYSQL was allocated in mysql_init |
|||
my_bool reconnect - used to automatically reconnect |
|||
struct st_mysql_options options - see above |
|||
char scramble_buff[9] - key for scrambling password before sending it |
|||
to server |
|||
|
|||
|
|||
struct MYSQL_RES - tagged as st_mysql_res and used to store |
|||
entire result set from a single query. Contains following fields: |
|||
|
|||
my_ulonglong row_count - number of rows |
|||
unsigned int field_count - number of columns |
|||
unsigned int current_field - cursor for fetching fields |
|||
MYSQL_FIELD *fields - see above |
|||
MYSQL_DATA *data - see above, and used in buffered reads, that is, |
|||
mysql_store_result only |
|||
MYSQL_ROWS *data_cursor - pointing to the field of above "data" |
|||
MEM_ROOT field_alloc - memory allocation for above "fields" |
|||
MYSQL_ROW row - used for storing row by row in unbuffered reads, |
|||
that is, in mysql_use_result |
|||
MYSQL_ROW current_row - cursor to the current row for buffered reads |
|||
unsigned long *lengths - column lengths of current row |
|||
MYSQL *handle - see above, used in unbuffered reads, that is, in |
|||
mysql_use_result |
|||
my_bool eof - used by mysql_fetch_row as a marker for end of data |
|||
|
|||
|
|||
|
|||
Global variables |
|||
|
|||
|
|||
unsigned long max_allowed_packet - maximum allowable value of network |
|||
buffer. Default value - 1MB |
|||
|
|||
unsigned long net_buffer_length - default, starting value of network |
|||
buffer - 8KB |
|||
|
|||
unsigned long bytes_sent - total number of bytes written since startup |
|||
of the server |
|||
|
|||
unsigned long bytes_received - total number of bytes read since startup |
|||
of the server |
|||
|
|||
|
|||
Synopsis of the basic client/server protocol |
|||
-------------------------------------------- |
|||
|
|||
Purpose of this chapter is to provide a complete picture of |
|||
the basic client/server protocol implemented in MySQL. It was felt |
|||
it is necessary after writing descriptions for all of the functions |
|||
involved in basic protocol. There are at present 11 functions |
|||
involved, with several structures, many constants etc, which are all |
|||
described in detail. But as a forest could not be seen from the trees, |
|||
so the concept of the protocol could not be deciphered easily from a |
|||
thorough documentation of minutiae. |
|||
|
|||
Although the concept of the protocol was not changed with the |
|||
introduction of vio system, embodied in violate.cc source file and VIO |
|||
system, the introduction of these has changed the code substantially. Before |
|||
VIO was introduced, functions for reading from/writing to network |
|||
connection had to deal with various network standards. So, these functions |
|||
depended on whether TCP port or Unix socket file or NT Named Pipe file is |
|||
used. This is all changed now and single vio_ functions are called, while |
|||
all this diversity is covered by vio_ functions. |
|||
|
|||
In MySQL a specific buffered network input/output transport model |
|||
has been implemented. Although each operating system may have its |
|||
own buffering for network connections, MySQL has added its own |
|||
buffering model. This same for each of the three transport protocol |
|||
types that are used in MySQL client/server communications, which |
|||
are TCP/IP sockets (on all systems), Unix socket files on Unix and |
|||
Unix-like operating systems and Named Pipe files on NT. Although |
|||
TCP/IP sockets are omnipresent, the latter two types have been added |
|||
for local connections. Those two connection types can be used in |
|||
local mode only, that is, when both client and server reside on the |
|||
same host, and are introduced because they enable better speeds for |
|||
local connections. This is especially useful for WWW type of |
|||
applications. Startup options of MySQL server allow that either |
|||
TCP/IP sockets or local connection (OS dependent) can be disallowed. |
|||
|
|||
In order to implement buffered input/output, MySQL allocates a |
|||
buffer. The starting size of this buffer is determined by the value |
|||
of the global variable net_buffer_length, which can be changed at |
|||
MySQL server startup. This is, as explained, only the startup length |
|||
of MySQL network buffer. Because a single item that has to be read |
|||
or written can be larger than that value, MySQL will increase buffer |
|||
size as long as that size reaches value of the global variable |
|||
max_allowed_packet, which is also settable at server startup. Maximum |
|||
value of this variable is limited by the way MySQL stores/reads |
|||
sizes of packets to be sent/read, which means by the way MySQL |
|||
formats packages. |
|||
|
|||
Basically each packet consists of two parts, a header and data. In |
|||
the case when compression is not used, header consists of 4 bytes |
|||
of which 3 contain the length of the packet to be sent and one holds |
|||
the packet number. When compression is used there are onother 3 |
|||
bytes which store the size of uncompressed data. Because of the way |
|||
MySQL packs length into 3 bytes, plus due to the usage of some |
|||
special values in the most significant byte, maximum size of |
|||
max_allowed_packet is limited to 24MB at present. So, if compression |
|||
is not used, at first 4 bytes are written to the buffer and then |
|||
data itself. As MySQL buffers I/O logical packets are packet together |
|||
until packets fill up entire size of the buffer. That size no less |
|||
than net_buffer_size, but no greater than max_allowed_packet. So, |
|||
actual writing to the network is done when this buffer is filled |
|||
up. As frequently sequence of buffers make a logical unit, like a |
|||
result set, then at the end of sending data, even if buffer is not |
|||
full, data is written (flushed to the connection) with a call of |
|||
the net_flush function. So that no single packet can be larger than |
|||
this value, checks are made throughout the code to make sure that |
|||
no single field or command could exceed that value. |
|||
|
|||
In order to maintain coherency in consecutive packets, each packet |
|||
is numbered and their number stored as a part of a header, as |
|||
explained above. Packets start with 0, so whenever a logical packet |
|||
is written, that number is incremented. On the other side when |
|||
packets are read, value that is fetched is compared with the value |
|||
stored and if there is no mismatch that value is incremented, too. |
|||
Packet number is reset on the client side when unwanted connections |
|||
are removed from the connection and on the server side when a new |
|||
command has been started. |
|||
|
|||
|
|||
So, before writing, the buffer contains a sequence of logical |
|||
packets, consisting of header plus data consecutively. If compression |
|||
is used, packet numbers are not stored in each header of the logical |
|||
packets, but a whole buffer, or a part of it if flushing is done, |
|||
containing one or more logical packets are compressed. In that case |
|||
a new larger header, is formed, and all logical packets contained |
|||
in the buffer are compressed together. This way only one packet is |
|||
formed which makes several logical packets, which improves both |
|||
speed and compression ratio. On the other side, when this large |
|||
compressed packet is read, it is first uncompressed, and then logical |
|||
packets are sent, one by one, to the calling functions. |
|||
|
|||
|
|||
All this functionality is described in detail in the following |
|||
chapter. It does not contain functions that form logical packets, or |
|||
that read and write to connections but also functions that are used |
|||
for initialization, clearing of connections. There are functions at |
|||
higher level dealing with sending fields, rows, establishing |
|||
connections, sending commands, but those are not explained in the |
|||
following chapter. |
|||
|
|||
|
|||
Functions utilized in client/server protocol |
|||
-------------------------------------------- |
|||
|
|||
First of all, functions are described that are involved in preparing, |
|||
reading, or writing data over TCP port, Unix socket file, or named |
|||
pipe, and functions directly related to those. All of these functions |
|||
are used both in server and client. Server and client specific code |
|||
segments are documented in each function description. |
|||
|
|||
Each MySQL function checks for errors in memory allocation and |
|||
freeing, as well as in every OS call, like the one dealing with |
|||
files and sockets, and for errors in indigenous MySQL function |
|||
calls. This is expected, but has to be said here so as not to repeat |
|||
it in every function description. |
|||
|
|||
Older versions of MySQL have utilized the following macros for |
|||
reading from or writing to a socket. |
|||
|
|||
raw_net_read - calls OS function recv function that reads N bytes |
|||
from a socket into a buffer. Number of bytes read is returned. |
|||
|
|||
raw_net_write - calls OS function send to write N bytes from a |
|||
buffer to socket. Number of bytes written is returned. |
|||
|
|||
These macros are replaced with VIO (Virtual I/O) functions. |
|||
|
|||
|
|||
Function name: my_net_init |
|||
|
|||
Parameters: struct NET *, enum_net_type, struct Vio |
|||
|
|||
Return value: 1 for error, 0 for success |
|||
|
|||
Function purpose: To initialize properly all NET fields, |
|||
allocate memory and set socket options |
|||
|
|||
Function description |
|||
|
|||
First of all, buff field of NET struct is allocated to the size of |
|||
net_buffer_length, and on failure function exits with 0. All fields |
|||
in NET are set to their default or starting values. As net_buffer_length |
|||
and max_allowed_packet are configurable, max_allowed_packet is set |
|||
equal to net_buffer_length if the latter one is greater. max_packet |
|||
is set for that NET to net_buffer_length, and buff_end points to |
|||
buff end. vio field is set to the second parameter. If it is a |
|||
real connection, which is the case when second parameter is not |
|||
null, then fd field is set by calling vio_fd function. read_pos and |
|||
write_pos to buff, while remaining integers are set to 0. If function |
|||
is run on the MySQL server on Unix and server is started in a test |
|||
mode that would require testing of blocking, then vio_blocking |
|||
function is called. Last, fast throughput mode is set by a call to |
|||
vio_fastsend function. |
|||
|
|||
|
|||
Function name: net_end |
|||
|
|||
Parameters: struct NET * |
|||
|
|||
Return value: void |
|||
|
|||
Function purpose: To release memory allocated to buff |
|||
|
|||
|
|||
|
|||
Function name: net_realloc (private, static function) |
|||
|
|||
Parameters: struct NET, ulong (unsigned long) |
|||
|
|||
Return value: 1 for error, 0 for success |
|||
|
|||
Function purpose: To change memory allocated to buff |
|||
|
|||
Function description |
|||
|
|||
New length of buff field of NET struct is passed as second parameter. |
|||
It is first checked versus max_allowed_packet and if greater, an |
|||
error is returned. New length is aligned to 4096-byte boundary. Then, |
|||
buff is reallocated, buff_end, max_packet, and write_pas reset to |
|||
the same values as in my_net_init. |
|||
|
|||
|
|||
|
|||
Function name: net_clear (used on client side only) |
|||
|
|||
Parameters: struct NET * |
|||
|
|||
Return value: void |
|||
|
|||
Function purpose: To read unread packets |
|||
|
|||
Function description |
|||
|
|||
This function is used on client side only, and is executed |
|||
only if a program is not started in test mode. This function reads |
|||
unread packets without processing them. First, non-blocking mode is |
|||
set on systems that do not have non-blocking mode defined. This is |
|||
performed by checking the mode with vio_is_blocking function. and |
|||
setting non-blocking mode by vio_blocking function. If this operation |
|||
was successful, then packets are read by vio_read function, to which |
|||
vio field of NET is passed together with buff and max_packet field |
|||
values. field of the same struct at a length of max_packet. If |
|||
blocking was active before reading is performed, blocking is set with |
|||
vio_blocking function. After reading has been performed, pkt_nr is |
|||
reset to 0 and write_pos reset to buff. In order to clarify some |
|||
matters non-blocking mode enables executing program to dissociate from |
|||
a connection, so that error in connection would not hang entire |
|||
program or its thread. |
|||
|
|||
Function name: net_flush |
|||
|
|||
Parameters: struct NET * |
|||
|
|||
Return value: 1 for error, 0 for success |
|||
|
|||
Function purpose: To write remaining bytes in buff to socket |
|||
|
|||
Function description |
|||
|
|||
net_real_write (described below) is performed is write_pos |
|||
differs from buff, both being fields of the only parameter. write_pos |
|||
is reset to buff. This function has to be used, as MySQL uses buffered |
|||
writes (as will be explained more in the function net_write_buff). |
|||
|
|||
|
|||
Function name: my_net_write |
|||
|
|||
Parameters: struct NET *, const char *, ulong |
|||
|
|||
Return value: 1 for error, 0 for success |
|||
|
|||
Function purpose: Write a logical packet in the second parameter |
|||
of third parameter length |
|||
|
|||
Function description |
|||
|
|||
The purpose of this function is to prepare a logical packet such |
|||
that entire content of data, pointed to by second parameter and in |
|||
length of third parameter is sent to the other side. In case of |
|||
server, it is used for sending result sets, and in case of client |
|||
it is used for sending local data. This function foremost prepares |
|||
a header for the packet. Normally, the header consists of 4 bytes, |
|||
of which the first 3 bytes contain the length of the packet, thereby |
|||
limiting a maximum allowable length of a packet to 16MB, while the |
|||
fourth byte contains the packet number, which is used when one large |
|||
packet has to be divided into sequence of packets. This way each |
|||
sub-packet gets its number which should be matched on the other |
|||
side. When compression is used another three bytes are added to |
|||
packet header, thus packet header is in that case increased to 7 |
|||
bytes. Additional three bytes are used to save the length of |
|||
compressed data. As in connection that uses compression option, |
|||
code packs packets together,, a header prepared by this function |
|||
is later not used in writing to / reading from network, but only |
|||
to distinguish logical packets within a buffered read operation. |
|||
|
|||
|
|||
This function, first stores the value of the third parameter into the |
|||
first 3 bytes of local char variable of NET_HEADER_SIZE size by usage |
|||
of function int3store. Then, at this point, if compression is not |
|||
used, pkt_nr is increased, and its value stored in the last byte of |
|||
the said local char[] variable. If compression is used, 0 is stored in |
|||
both values. Then those four bytes are sent to other side by the usage |
|||
of the function net_write_buff(to be explained later on), and if |
|||
successful, entire packet in second parameter of the length described |
|||
in third parameter is sent by the usage of the same function. |
|||
|
|||
|
|||
Function name: net_write_command |
|||
|
|||
Parameters: struct NET *, char, const char *, ulong |
|||
|
|||
Return value: 1 for error, 0 for success |
|||
|
|||
Function purpose: Send a command with a packet as in previous function |
|||
|
|||
Function description |
|||
|
|||
This function is very similar to the previous one. The only |
|||
difference is that first packet is enlarged by one byte, so that the |
|||
command precedes the packet to be sent. This is implemented by |
|||
increasing first packet by one byte, which contains a command code. As |
|||
command codes do not use the range of values that are used by character |
|||
sets, so when the other side receives a packet, first byte after |
|||
header contains a command code. This function is used by client for |
|||
sending all commands and queries, and by server in connection process |
|||
and for sending errors. |
|||
|
|||
|
|||
Function name: net_write_buff (private, static function) |
|||
|
|||
Parameters: struct NET *, const char *, uint |
|||
|
|||
Return value: 1 for error, 0 for success |
|||
|
|||
Function purpose: To write a packet of any size by cutting it |
|||
and using next function for writing it |
|||
|
|||
Function description |
|||
|
|||
This function was created after compression feature has been |
|||
added to MySQL. This function supposes that packets have already been |
|||
properly formatted, regarding packet header etc. The principal reason for |
|||
this function to exist is because a packet that is sent by client or |
|||
server does not have to be less than max_packet. So this function |
|||
first calculates how much data has been left in a buff, by getting a |
|||
difference between buff_end and write_pos and storing it to local |
|||
variable left_length. Then a loop is run as long as the length to be |
|||
sent is greater than length of left bytes (left_length). In a loop |
|||
data from second parameter is copied to buff at write_pos, as much as |
|||
it can be, that is, by left_length. Then net_real_write function is called |
|||
(see below) with NET, buff, and max_packet parameters. This function |
|||
is the lowest level function that writes data over established |
|||
connection. In the loop, write_pos is reset to buff, the pointer to data |
|||
(second parameter) is moved by the amount of data sent (left_length), |
|||
length of data to be sent (third parameter) is decreased by the amount |
|||
sent (left_length) and left_length is reset to max_packet value, which |
|||
ends the loop. This logic was necessary, as there could have been some |
|||
data yet unsent (write_pos != buf), while data to be sent could be as |
|||
large as necessary, thus requiring many loops. At the end of function, |
|||
remaining data in second parameter are copied to buff at write_pos, by |
|||
the remaining length of data to be sent (third parameter). So, in the |
|||
next call of this function remaining data will be sent, as buff is |
|||
used in the call to net_real_write. It is very important to note that if |
|||
a packet to be sent is less than the number of bytes that are still |
|||
available in buff, then there will be no writing over network, but |
|||
only logical packets will be added one after another. This will |
|||
accelerate network traffic, plus if compression is used, the |
|||
expected compression rate would be higher. That is why server or |
|||
client functions that sends data uses at the end of data net_flush |
|||
function described above. |
|||
|
|||
|
|||
Function name: net_real_write |
|||
|
|||
Parameters: struct NET *, const char *, ulong |
|||
|
|||
Return value: 1 for error, 0 for success |
|||
|
|||
Function purpose: To write data to a socket or pipe, with |
|||
compression if used |
|||
|
|||
Function description |
|||
|
|||
First, more field is set to 2, to enable reporting in |
|||
mysql_list_processes. Then if compression is enabled on that |
|||
connection, a new local buffer (variable b) is initialized to the |
|||
length of total header (normal header + compression header) and if no |
|||
memory is available, an error is returned. This buffer (b) is used for |
|||
holding the final, compressed packet to be written over the |
|||
connection. Furthermore in compression initialization, second |
|||
parameter at length of third parameter is copied to the local buffer |
|||
b, and MySQL's wrapped zlib's compression function is run at total |
|||
header offset of the local buffer. Please, do note that this function |
|||
does not test effectiveness of compression. If compression is turned |
|||
on in some connection, it is used all of the time. Also, it is very |
|||
important to be cognizant of the fact that this algorithm makes |
|||
possible that a single compressed packet contains several logical |
|||
packets. In this way compression rate is increased and network |
|||
throughput is increased as well. However, this algorithm has |
|||
consequences on the other side, that reads compressed packet, which |
|||
is covered in my_net_read function. After compression is done, the full |
|||
compression header is properly formed with the packet number, |
|||
compressed and uncompressed lengths. At the end of compression code, |
|||
third parameter is increased by total header length, as the original |
|||
header is not used (see above), and second parameter, pointer to data, |
|||
is set to point to local buffer b, in order that the further flow of |
|||
function is independent of compression. If a function is executed |
|||
on server side, a thread alarm initialized and if non-blocking is |
|||
active set at NET_WRITE_TIMEOUT. Two local (char *) pointers are |
|||
initialized, pos at beginning of second parameter, and end at end of |
|||
data. Then the loop is run as long as all data is written, which means |
|||
as long as pos != end. First vio_write function is called, with |
|||
parameters of vio field, pos and size of data (end - pos). Number of |
|||
bytes written over connection is saved in local variable (length). If |
|||
error is returned local bool variable (interrupted) is set according |
|||
to the return value of the vio_should_retry called with vio field as |
|||
parameter. This bool variable indicates whether writing was |
|||
interrupted in some way or not. |
|||
|
|||
Further, error from vio_write is treated differently on Unix versus |
|||
other OS's (Win32 or OS/2). On Unix an alarm is set if one is not |
|||
in use, no bytes have been written and there has been no interruption. |
|||
Also, in that case, if connection is not in blocking mode, a sub-loop |
|||
is run as long as blocking is not set with vio_blocking function. |
|||
Within the loop another run of above vio_write is run based on |
|||
return value of vio_is_retry function, provided number of repeated |
|||
writes is less than RETRY_COUNT. If that is not the case, error |
|||
field of struct NET is set to 1 and function exits. At the exit |
|||
of sub-loop number of reruns already executed is reset to zero and |
|||
another run of above vio_write function is attempted. If the function |
|||
is run on Win32 and OS/2, and in the case that function flow was |
|||
not interrupted and thread alarm is not in use, again the main loop |
|||
is continued until pos != end. In the case that this function is |
|||
executed on thread safe client program, a communication flow is |
|||
tested on EINTR, caused by context switching, by use of vio_errno |
|||
function, in which case the loop is continued. At the end of |
|||
processing of the error from vio_write, error field of struct NET |
|||
is set, and if on server last_errno field is set to |
|||
ER_NET_WRITE_INTERRUPTED in the case that local bool variable |
|||
(interrupted) is true or to ER_NET_ERROR_ON_WRITE. Before the end |
|||
of loop, in order to make possible evaluation of the loop condition, |
|||
pos is increased by the value written in last iteration (length). |
|||
Also global variable bytes_sent is increased by the same value, for |
|||
status purposes. At the end of the functions more fields is reset, |
|||
in case of compression, compression buffer (b) memory is released |
|||
and if thread is still in use, it is ended and blocking state is |
|||
reset to its original state, and function returns error is all bytes |
|||
are not written. |
|||
|
|||
|
|||
|
|||
Function name: my_real_read (private, static function) |
|||
|
|||
Parameters: struct NET *, ulong * |
|||
|
|||
Return value: length of bytes read |
|||
|
|||
Function purpose: low level network connection read function |
|||
|
|||
Function description |
|||
|
|||
This function has made as a separate one when compression was |
|||
introduced in MySQL client/server protocol . It contains basic, low |
|||
level network reading functionality, while all dealings with |
|||
compressed packets are handled in next function. Compression in this |
|||
function is only handled in as much to unfold the length of uncompressed |
|||
data. First blocking state of connection is saved in local bool |
|||
variable net_blocking, and field more is set 1 for detailed reporting |
|||
in mysqld_list_processes. A new thread alarm is initialized, in order |
|||
to enable read timeout handling, and if on server and a connection can |
|||
block a program, the alarm is set at a value of timeout field. Local |
|||
pointer is set to the position of the next logical packet, with its |
|||
header skipped, which is at field where_b offset from buff. Next, a |
|||
two time run code is entered. A loop is run exactly two times because |
|||
first time number of bytes to be fetched (remain) are set to the |
|||
header size, which is different when compression is used or not used |
|||
on the connection. After first fetch has been done, number of packets |
|||
that will be received in second iteration is well known, as fetched |
|||
header contains the size of packet, packet number, and in the case of |
|||
compression, the size of the uncompressed packet. Then, as long as there are |
|||
bytes to read the loop is entered with first reading data from network |
|||
connection with vio_read function, called with parameters of field |
|||
vio, current position and remaining number of bytes, which value is |
|||
hold by local variable (remain) initialized at the value of header size, |
|||
which differs if compression is used. Number of bytes read are |
|||
returned in local length variable. If error is returned local bool |
|||
variable (interrupted) is set according to the return value of the |
|||
vio_should_retry called with vio field as parameter. This bool |
|||
variable indicates whether reading was interrupted in some way or not. |
|||
|
|||
Further, error from vio_read is treated differently on Unix versus |
|||
other OS's (Win32 or OS/2). On Unix an alarm is set if one is not |
|||
in use, no bytes have been read and there has been no interruption. |
|||
Also, in that case, if connection is not in blocking mode, a sub-loop |
|||
is run as long as blocking is not set with vio_blocking function. |
|||
Within the loop another run of above vio_read is run based on return |
|||
value of vio_is_retry function, provided number of repeated writes |
|||
is less than RETRY_COUNT. If that is not the case, error field of |
|||
struct NET is set to 1 and function exits. At the exit of sub-loop |
|||
number of reruns already executed is reset to zero and another run |
|||
of above vio_read function is attempted. If the function is run on |
|||
Win32 and OS/2, and in the case that function flow was not interrupted |
|||
and thread alarm is not in use, again the main loop is continued |
|||
as long as there are bytes remaining. In the case that this function |
|||
is executed on thread safe client program, then if another run |
|||
should be made, which is decided by the output of vio_should_retry |
|||
function, in which case the loop is continued. At the end of |
|||
processing of the error from vio_read, error field of struct NET |
|||
is set, and if on server last_errno field is set to ER_NET_READ_INTERRUPTED |
|||
in the case that local bool variable (interrupted) is true or to |
|||
ER_NET_ERROR_ON_READ. In case of such an error this function exits |
|||
and returns error. In the case when there is no error, number of |
|||
remaining bytes (remain) is decreased by the number of bytes read, |
|||
which should be zero, but in case it is not the entire code is still |
|||
in while (remain > 0) loop, which will be exited immediately if it |
|||
is. This has been done to accommodate errors in the traffic level |
|||
and for the very slow connections. Current position in field buff |
|||
is also moved by the amount of bytes read by vio_read function, and |
|||
global variable bytes_received is increased by the same value in a |
|||
thread safe manner. When the loop that is run until necessary bytes |
|||
are read (remain) is finished, then if external loop is in its first |
|||
run, of the two, packet sequencing is tested for consistency by |
|||
comparing the number contained at 4th byte in header with pkt_nr |
|||
field. Header location is found at where_b offset to field_b. Usage |
|||
of where_b is obligatory due to the possible compression usage. If |
|||
there is no compression on a connection, then where_b is always 0. |
|||
If there is a discrepancy, then first byte of the header is checked |
|||
whether it is equal to 255, because when error is sent by the server, |
|||
or by a client if it is sending data (like in LOAD DATA INFILE |
|||
LOCAL...), then first byte in header is set to 255. If it is not |
|||
255, then an error on packets being out of order is printed. In any |
|||
case, on server, last_errno field is set to ER_NET_PACKETS_OUT_OF_ORDER |
|||
and the function returns with an error, that is, the value returned is |
|||
packet_error. If a check on serial number of packet is successful, |
|||
pkt_nr field is incremented in order to enable checking packet order |
|||
with next packet and if compression is used, uncompressed length |
|||
is extracted from a proper position in header and returned in the |
|||
second parameter of this function. Length of the packet is saved, |
|||
for the purpose of a proper return value from this function. Still |
|||
in the first iteration of the main loop, a check must be made if |
|||
field buff could accommodate entire package that comes, in its |
|||
compressed or uncompressed form. This is done in such a way, because |
|||
zlib's compress and uncompress functions use the same memory area |
|||
for compression and uncompression. Necessary field buff length is |
|||
equal to current offset where data are (where_b which is zero for |
|||
non-compression), plus the larger value of compressed or uncompressed |
|||
package to be read in a second run. If this value is larger than |
|||
the current length of field buff, which is read from field max_packet, |
|||
then field buff has to be reallocated. If reallocation with net_realloc |
|||
function fails, the function returns an error. Before a second |
|||
loop is started, length to be read is set to the length of expected |
|||
data and current position (pos) is set at where_b offset from field |
|||
buff. At the end of function, if alarm is set, which is the case |
|||
if it is run on server or on a client if a function is interrupted |
|||
and another run of vio_read is attempted, alarm is ended and blocking |
|||
state is restored from the saved local bool variable net_blocking. |
|||
Function returns number of bytes read or the error (packet_error). |
|||
|
|||
|
|||
Function name: my_net_read |
|||
|
|||
Parameters: struct NET * |
|||
|
|||
Return value: length of bytes read |
|||
|
|||
Function purpose: Highest level general purpose reading function |
|||
|
|||
Function description |
|||
|
|||
First, if compression is not used, my_real_read is called, with |
|||
struct NET * a first parameter, and pointer to local ulong complen |
|||
as a second parameter, but its value is not used here. Number of |
|||
bytes read is returned in local ulong variable len. read_pos field |
|||
is set to an offset of value of where_b field from field buff. |
|||
where_b field actually denotes where in field buff is the current |
|||
packet. If returned number of bytes read (local variable len) does |
|||
not signal that an error in packet transmission occurred (that is, |
|||
it is not set to packet_error), then the string contained in read_pos |
|||
is zero terminated. Simply, the end of the string starting at |
|||
read_pos, and ending at read_pos + len, is set to zero. This is |
|||
done in that way, because mysql_use_result expects a zero terminated |
|||
string, and function returns with a value local variable len. This |
|||
ends this function in the case that compression is not used and the |
|||
remaining code is executed only if compression is enabled on the |
|||
connection. |
|||
|
|||
In order to explain how a compressed packet logically is cut into |
|||
meningful packets, the full meaning of several NET fields should |
|||
be explained. First of all, fields in NET are used and not local |
|||
variables, as all values should be saved between consecutive calls |
|||
of this function. Simply, this function is called in order to return |
|||
logical packets, but this function does not need to call my_real_read |
|||
function everytime, because when a large packet is uncompressed, |
|||
it may, but not necessarily so, contain several logical packets. |
|||
Therefore, in order to preserve data on logical packets local |
|||
variables are not used. Instead fields in NET struct are used. Field |
|||
remain_in_buf denotes how many bytes of entire uncompressed packets |
|||
is still contained within buff. field buf_length saves the value |
|||
of the length of entire uncompressed packet. field save_char is |
|||
used to save the character at the position where the packet ends, |
|||
which character has to be replaced with a zero, '\0', in order to |
|||
make a logical packet zero delimited, for mysql_use_result. Field |
|||
length stores the value of the length of compressed packet. Field |
|||
read_pos as usual, points to the current reading position. This |
|||
char * pointer is used by all functions that call this function in |
|||
order to fetch their data. Field buff is not used for that purpose, |
|||
but read_pos is used instead. This change was introduced with |
|||
compression, when algorithm accommodated grouping of several packets |
|||
together. |
|||
|
|||
Now that meanings of all relevant NET fields are explained, |
|||
we can proceed with the flow of this function for the case when |
|||
compression is active. First, if there are remaining portions of |
|||
compressed packet in a field buff, saved character value is set at |
|||
the position where zero char '\0' was inserted to enable the string |
|||
to be zero delimited for mysql_use_result. Then a loop is started. |
|||
In the first part of the loop, if there are remaining bytes, local |
|||
uchar *pos variable is set at the current position in field buff |
|||
where a new packet starts. This position is an (buf_length - |
|||
remain_in_buf) offset in field buff. As it is possible that next |
|||
logical packet is not read to the full length in the remaining of |
|||
the field buf, several things had to be inspected. It should be |
|||
noted that data that is read from net_real_read contains only logical |
|||
packets containing 4 byte headers only, being 4 byte headers prepared |
|||
by my_net_write or net_write_command. But, when written, logical |
|||
packet could be so divided that only a part of header is read in. |
|||
Therefore after pointer to the start of the next packet has been |
|||
saved, a check is made whether number of remaining bytes in buffer |
|||
is less than 4, being 3 bytes for length and one byte for packet |
|||
number. If it is greater, then the length of the logical packet is |
|||
extracted and saved a length field. Then a check is made whether |
|||
entire packet is contained within a buf, that is, a check is made |
|||
that the logical packet is fully contained in the buffer. In that |
|||
case, number of bytes remaining in buffer is decreased by the full |
|||
length of logical packet (4 + length field), read_pos is moved |
|||
forward by 4 bytes to skip header and be set at a beginning of data |
|||
in logical packet, length field is saved for the value to be returned |
|||
in function and the loop is exited. In the case that the entire |
|||
logical packet is not contained within the buffer, then if length of |
|||
the entire buffer differs from remaining length of logical packet, |
|||
it (logical packet) is moved to the beginning of the field buff. |
|||
If length of the entire buffer equals the remaining length of logical |
|||
packet, where_b and buf_length fields are set to 0. This is done |
|||
so that in both cases buffer is ready to accept next part of packet. |
|||
|
|||
In order to get a next part of a packet, still within a loop, |
|||
my_real_read function is called and length of compressed packet is |
|||
returned to a local len variable, and length of compressed data is |
|||
returned in complen variable. In the case of non-compression value |
|||
of complen is zero. If packet_error is from my_real_read function, |
|||
this function returns also with packet_error. If it is not a |
|||
packet_error, my_uncompress function is called to uncompress data. |
|||
It is called with offset of where_b data from field buff, as it is |
|||
the position where compressed packet starts, and with len and complen |
|||
values, being lengths of compressed and uncompressed data. If there |
|||
is no compression, 0 is returned for uncompressed size from |
|||
my_real_read function, and my_uncompress wrapper function is made |
|||
to skip zlib uncompress in that case. If error is returned from |
|||
my_uncompress, error field is set to 1, if on server last_errno is |
|||
set to ER_NET_UNCOMPRESS_ERROR and loop is exited and function |
|||
returns with packet_error. If not, buf_length and remain_in_buf |
|||
fields are set to the uncompressed size of buffer and the loop is |
|||
continued. When the loop is exited save_char field is used to save |
|||
the char at end of a logical packet, which is an offset of field |
|||
len from position in field buff pointed by field read_pos, in order |
|||
that zero char is set at the same position, for mysql_use_result. |
|||
Function returns the length of the logical packet without its header. |
@ -1,250 +0,0 @@ |
|||
#!@PERL@ |
|||
# Copyright (C) 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; version 2 of the License. |
|||
# |
|||
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|||
# |
|||
# fill_func_tables - parse ../Docs/manual.texi |
|||
# |
|||
# Original version by Victor Vagin <vva@mysql.com> |
|||
# |
|||
|
|||
my $cat_name= ""; |
|||
my $func_name= ""; |
|||
my $text= ""; |
|||
my $example= ""; |
|||
|
|||
local $mode= ""; |
|||
|
|||
sub prepare_name |
|||
{ |
|||
my ($a)= @_; |
|||
|
|||
$a =~ s/(\@itemize \@bullet)/ /g; |
|||
$a =~ s/(\@end itemize)/ /g; |
|||
$a =~ s/(\@end multitable)/ /g; |
|||
$a =~ s/(\@end table)/ /g; |
|||
$a =~ s/(\@cindex(.*?)\n)/ /g; |
|||
$a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g; |
|||
$a =~ s/(\@node(.*?)\n)/ /g; |
|||
$a =~ s/(\@tab)/\t/g; |
|||
$a =~ s/\@item/ /g; |
|||
$a =~ s/\@code\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@strong\{(.+?)\}/$1/go; |
|||
$a =~ s/\@samp\{(.+?)\}/$1/go; |
|||
$a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go; |
|||
$a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go; |
|||
$a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go; |
|||
$a =~ s/\'/\'\'/g; |
|||
$a =~ s/\\/\\\\/g; |
|||
$a =~ s/\`/\`\`/g; |
|||
|
|||
$a =~ s/\@table \@code/ /g; |
|||
|
|||
$a =~ s/\(\)//g; |
|||
|
|||
$a =~ s/((\w|\s)+)\(([\+-=><\/%*!<>\s]+)\)/$3/gxs; #$a =~ s/((\w|\s)+)\(([\+-=><\/%*!<>\s]+)\)/$3 $1/gxs; |
|||
$a =~ s/([\+-=><\/%*!<>\s]+)\(((\w|\s)+)\)/$1/gxs;#$a =~ s/([\+-=><\/%*!<>\s]+)\(((\w|\s)+)\)/$1 $2/gxs; |
|||
$a =~ s/((\w|\s)+)\((.+)\)/$1/gxs; |
|||
|
|||
return $a; |
|||
} |
|||
|
|||
sub prepare_text |
|||
{ |
|||
my ($a)= @_; |
|||
|
|||
$a =~ s/(\@itemize \@bullet)/ /g; |
|||
$a =~ s/(\@end itemize)/ /g; |
|||
$a =~ s/(\@end multitable)/ /g; |
|||
$a =~ s/(\@end table)/ /g; |
|||
$a =~ s/(\@cindex(.*?)\n)/ /g; |
|||
$a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g; |
|||
$a =~ s/(\@node(.*?)\n)/ /g; |
|||
$a =~ s/(\@tab)/\t/g; |
|||
$a =~ s/\@itemx/ /g; |
|||
$a =~ s/\@item/ /g; |
|||
$a =~ s/\@code\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@strong\{(.+?)\}/$1/go; |
|||
$a =~ s/\@samp\{(.+?)\}/$1/go; |
|||
$a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go; |
|||
$a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go; |
|||
$a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go; |
|||
$a =~ s/\'/\'\'/g; |
|||
$a =~ s/\\/\\\\/g; |
|||
$a =~ s/\`/\`\`/g; |
|||
$a =~ s/(\n*?)$//g; |
|||
$a =~ s/\n/\\n/g; |
|||
|
|||
$a =~ s/\@table \@code/ /g; |
|||
|
|||
return $a; |
|||
} |
|||
|
|||
sub prepare_example |
|||
{ |
|||
my ($a)= @_; |
|||
|
|||
$a =~ s/\'/\'\'/g; |
|||
$a =~ s/\\/\\\\/g; |
|||
$a =~ s/\`/\`\`/g; |
|||
$a =~ s/(\n*?)$//g; |
|||
$a =~ s/\n/\\n/g; |
|||
|
|||
return $a; |
|||
} |
|||
|
|||
sub flush_all |
|||
{ |
|||
my ($mode) = @_; |
|||
|
|||
if ($mode eq ""){return;} |
|||
|
|||
$func_name= prepare_name($func_name); |
|||
$text= prepare_text($text); |
|||
$example= prepare_example($example); |
|||
|
|||
if ($func_name ne "" && $text ne "" && !($func_name =~ /[abcdefghikjlmnopqrstuvwxyz]/)){ |
|||
print "INSERT INTO function (name,description,example) VALUES ("; |
|||
print "'$func_name',"; |
|||
print "'$text',"; |
|||
print "'$example'"; |
|||
print ");\n"; |
|||
print "INSERT INTO function_category (cat_id,func_id) VALUES (\@cur_category,LAST_INSERT_ID());\n"; |
|||
} |
|||
|
|||
$func_name= ""; |
|||
$text= ""; |
|||
$example= ""; |
|||
$mode= ""; |
|||
} |
|||
|
|||
sub new_category |
|||
{ |
|||
my ($category)= @_; |
|||
|
|||
$category= prepare_text($category); |
|||
|
|||
print "INSERT INTO function_category_name (name) VALUES (\'$category\');\n"; |
|||
print "SELECT \@cur_category:=LAST_INSERT_ID();\n"; |
|||
} |
|||
|
|||
print "INSERT INTO db (Host,DB,User,Select_priv) VALUES ('%','mysql_help','','Y');\n"; |
|||
print "CREATE DATABASE mysql_help;\n"; |
|||
|
|||
print "USE mysql_help;\n"; |
|||
|
|||
print "DROP TABLE IF EXISTS function;\n"; |
|||
print "CREATE TABLE function ("; |
|||
print " func_id int unsigned not null auto_increment,"; |
|||
print " name char(64) not null,"; |
|||
print " url char(128) not null,"; |
|||
print " description text not null,"; |
|||
print " example text not null,"; |
|||
print " min_args tinyint not null,"; |
|||
print " max_args tinyint,"; |
|||
print " date_created datetime not null,"; |
|||
print " last_modified timestamp not null,"; |
|||
print " primary key (func_id)"; |
|||
print ") ENGINE=MYISAM;\n\n"; |
|||
|
|||
print "DROP TABLE IF EXISTS function_category_name;\n"; |
|||
print "CREATE TABLE function_category_name ("; |
|||
print " cat_id smallint unsigned not null auto_increment,"; |
|||
print " name char(64) not null,"; |
|||
print " url char(128) not null,"; |
|||
print " date_created datetime not null,"; |
|||
print " last_modified timestamp not null,"; |
|||
print " primary key (cat_id)"; |
|||
print ") ENGINE=MYISAM;\n\n"; |
|||
|
|||
print "DROP TABLE IF EXISTS function_category;\n"; |
|||
print "CREATE TABLE function_category ("; |
|||
print " cat_id smallint unsigned not null references function_category_name,"; |
|||
print " func_id int unsigned not null references function,"; |
|||
print " primary key (cat_id, func_id)"; |
|||
print ") ENGINE=MYISAM;\n\n"; |
|||
|
|||
print "DELETE FROM function_category_name;\n"; |
|||
print "DELETE FROM function_category;\n"; |
|||
print "DELETE FROM function;\n"; |
|||
print "SELECT \@cur_category:=null;\n\n"; |
|||
|
|||
my $in_section_6_3= 0; |
|||
|
|||
for(<>) |
|||
{ |
|||
if ($_=~/\@section Functions for Use in \@code{SELECT} and \@code{WHERE} Clauses/ && |
|||
!$in_section_6_3){ |
|||
$in_section_6_3= 1; |
|||
next; |
|||
} |
|||
|
|||
if ($_=~/\@section/ && $in_section_6_3){ |
|||
$in_section_6_3= 0; |
|||
next; |
|||
} |
|||
|
|||
if (!$in_section_6_3) { next; } |
|||
|
|||
my $c_name= ""; |
|||
|
|||
($c_name)=m|\@c for_mysql_help,(.+?)$|; |
|||
if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){ |
|||
($cat_name)= $c_name; |
|||
new_category($cat_name); |
|||
next; |
|||
} |
|||
|
|||
($c_name)=m|\@subsubsection (.+?)$|; |
|||
if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){ |
|||
($cat_name)= $c_name; |
|||
new_category($cat_name); |
|||
next; |
|||
} |
|||
|
|||
($c_name)=m|\@subsection (.+?)$|; |
|||
if (!($c_name eq "") && ! ($c_name =~ m/$cat_name/i)){ |
|||
($cat_name)= $c_name; |
|||
new_category($cat_name); |
|||
next; |
|||
} |
|||
|
|||
($f_name)=m|\@findex (.+?)$|; |
|||
if (!($f_name eq "")){ |
|||
flush_all($mode); |
|||
($func_name)= ($f_name); |
|||
$mode= "text"; |
|||
next; |
|||
} |
|||
|
|||
if ($_=~/\@example/ && ($mode eq "text")){ |
|||
$mode= "example"; |
|||
next; |
|||
} |
|||
|
|||
if ($_=~/\@end example/ && ($mode eq "example")){ |
|||
flush_all($mode); |
|||
next; |
|||
} |
|||
|
|||
if ($mode eq "text") { $text .= $_; } |
|||
if ($mode eq "example") { $example .= $_; } |
|||
} |
|||
|
|||
|
|||
print "DELETE function_category_name "; |
|||
print "FROM function_category_name "; |
|||
print "LEFT JOIN function_category ON function_category.cat_id=function_category_name.cat_id "; |
|||
print "WHERE function_category.cat_id is null;" |
|||
|
@ -1,614 +0,0 @@ |
|||
#!@PERL@ |
|||
# Copyright (C) 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; version 2 of the License. |
|||
# |
|||
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|||
|
|||
# This script generates the SQL statements required by mysql_install_db to |
|||
# fill up the tables for the server-side online function help, which can be |
|||
# invoked with "help <function>" from the MySQL client. |
|||
# |
|||
# Usage: |
|||
# fill_help_tables OPTIONS < manual.texi > fill_help_tables.sql |
|||
# |
|||
# --help display this helpscreen and exit |
|||
# --verbose print information about help completeness to STDERR |
|||
# --lexems=path path to file with lexems. it is used with verbose option. |
|||
# default value is ../sql/lex.h |
|||
# Examples: |
|||
# ./fill_help_tables --help |
|||
# ./fill_help_tables --verbose < manual.texi > fill_help_tables.sql |
|||
# ./fill_help_tables < manual.texi > fill_help_tables.sql |
|||
# |
|||
# Please note, that you first need to update Docs/manual.texi with the |
|||
# manual file from the separate "mysqldoc" BitKeeper-Tree! The manual.texi |
|||
# included in the source tree is just an empty stub file - the full manual |
|||
# is now maintained in a separate tree. |
|||
# |
|||
# extra tags in manual.texi: |
|||
# |
|||
# @c help_category <category_name>[@<parent_category_name>] |
|||
# |
|||
# @c description_for_help_topic <topic_name> <keyword1> <keyword2> |
|||
# .... |
|||
# @c end_description_for_help_topic |
|||
# |
|||
# @c example_for_help_topic <topic_name> |
|||
# @example |
|||
# .... |
|||
# @end example |
|||
# |
|||
# |
|||
# Original version by Victor Vagin <vva@mysql.com> |
|||
# |
|||
|
|||
use strict; |
|||
use Getopt::Long; |
|||
|
|||
my $insert_portion_size= 15; |
|||
my $error_prefix= "---- help parsing errors :"; |
|||
|
|||
my $path_to_lex_file= "../sql/lex.h"; |
|||
my $verbose_option= 0; |
|||
my $help_option= 0; |
|||
|
|||
my $cur_line= 0; |
|||
my $count_errors= 0; |
|||
|
|||
GetOptions( |
|||
"help",\$help_option, |
|||
"verbose",\$verbose_option, |
|||
"lexems=s",\$path_to_lex_file |
|||
); |
|||
|
|||
if ($help_option ne 0) |
|||
{ |
|||
print <<_HELP; |
|||
|
|||
This script generates the SQL statements required by mysql_install_db to |
|||
fill up the tables for the server-side online function help, which can be |
|||
invoked with "help <function>" from the MySQL client. |
|||
|
|||
Usage: |
|||
fill_help_tables OPTIONS < manual.texi > fill_help_tables.sql |
|||
|
|||
--help display this helpscreen and exit |
|||
--verbose print information about help completeness to STDERR |
|||
--lexems=path path to file with lexems. it is used with verbose option. |
|||
default value is ../sql/lex.h |
|||
|
|||
Examples: |
|||
./fill_help_tables --help |
|||
./fill_help_tables --verbose < manual.texi > fill_help_tables.sql |
|||
./fill_help_tables < manual.texi > fill_help_tables.sql |
|||
|
|||
_HELP |
|||
exit; |
|||
} |
|||
|
|||
my $current_category= ""; |
|||
my $current_parent_category= ""; |
|||
my $next_example_for_topic= ""; |
|||
|
|||
my %topics; |
|||
my %categories; |
|||
my %keywords; |
|||
|
|||
$categories{Contents}->{__parent_category__}= ""; |
|||
|
|||
sub print_error |
|||
{ |
|||
my ($text)= @_; |
|||
if ($count_errors==0) |
|||
{ |
|||
print STDERR "$error_prefix\n"; |
|||
} |
|||
print STDERR "line $cur_line : $text"; |
|||
$count_errors++; |
|||
} |
|||
|
|||
sub add_topic_to_category |
|||
{ |
|||
my ($topic_name)= @_; |
|||
|
|||
$categories{$current_category}->{$topic_name}= $topics{$topic_name}; |
|||
my $category= $categories{$current_category}; |
|||
$category->{__name__}= $current_category; |
|||
|
|||
if (exists($category->{__parent_category__})) |
|||
{ |
|||
my $old_parent= $category->{__parent_category__}; |
|||
if ($old_parent ne $current_parent_category) |
|||
{ |
|||
print_error "wrong parent for $current_category\n"; |
|||
} |
|||
} |
|||
|
|||
if ($current_parent_category ne "") |
|||
{ |
|||
$category->{__parent_category__}= $current_parent_category; |
|||
} |
|||
|
|||
if (exists($topics{$topic_name}->{category})) |
|||
{ |
|||
my $old_category= $topics{$topic_name}->{category}; |
|||
if ($old_category ne $category) |
|||
{ |
|||
print_error "wrong category for $topic_name (first one's \"$old_category->{__name__}\" second one's \"$current_category\")\n"; |
|||
} |
|||
} |
|||
|
|||
$topics{$topic_name}->{category}= $category; |
|||
} |
|||
|
|||
sub add_example |
|||
{ |
|||
my ($topic_name,$example)= @_; |
|||
|
|||
$topic_name=~ tr/a-z/A-Z/; |
|||
|
|||
if (exists($topics{$topic_name}->{example})) |
|||
{ |
|||
print_error "double example for $topic_name\n"; |
|||
} |
|||
|
|||
$topics{$topic_name}->{example}= $example; |
|||
add_topic_to_category($topic_name); |
|||
} |
|||
|
|||
sub add_description |
|||
{ |
|||
my ($topic_name,$description)= @_; |
|||
|
|||
$topic_name=~ tr/a-z/A-Z/; |
|||
|
|||
if (exists($topics{$topic_name}->{description})) |
|||
{ |
|||
print_error "double description for $topic_name\n"; |
|||
} |
|||
$topics{$topic_name}->{description}= $description; |
|||
add_topic_to_category($topic_name); |
|||
} |
|||
|
|||
sub add_keyword |
|||
{ |
|||
my ($topic_name,$keyword)= @_; |
|||
|
|||
$topic_name=~ tr/a-z/A-Z/; |
|||
$keyword=~ tr/a-z/A-Z/; |
|||
|
|||
push(@{$topics{$topic_name}->{keywords}},$keyword); |
|||
if (exists($keywords{$keyword}->{$topic_name})) |
|||
{ |
|||
print_error "double keyword $keyword for $topic_name\n"; |
|||
} |
|||
$keywords{$keyword}->{$topic_name}= $topics{$topic_name}; |
|||
} |
|||
|
|||
sub prepare_name |
|||
{ |
|||
my ($a)= @_; |
|||
|
|||
$a =~ s/(\@itemize \@bullet)/ /g; |
|||
$a =~ s/(\@end itemize)/ /g; |
|||
$a =~ s/(\@end multitable)/ /g; |
|||
$a =~ s/(\@end table)/ /g; |
|||
$a =~ s/(\@cindex(.*?)\n)/ /g; |
|||
$a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g; |
|||
$a =~ s/(\@node(.*?)\n)/ /g; |
|||
$a =~ s/(\@tab)/\t/g; |
|||
$a =~ s/\@item/ /g; |
|||
$a =~ s/\@minus\{\}/-/g; |
|||
$a =~ s/\@dots\{\}/.../g; |
|||
$a =~ s/\@var\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@command\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@code\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@strong\{(.+?)\}/$1/go; |
|||
$a =~ s/\@samp\{(.+?)\}/'$1'/go; |
|||
$a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go; |
|||
$a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go; |
|||
$a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go; |
|||
$a =~ s/\'/\'\'/g; |
|||
$a =~ s/\\/\\\\/g; |
|||
$a =~ s/\`/\`\`/g; |
|||
|
|||
$a =~ s/\@table \@code/ /g; |
|||
$a =~ s/\(\)//g; |
|||
$a =~ s/\"/\\\"/g; |
|||
|
|||
$a =~ s/((\w|\s)+)\(([\+-=><\/%*!<>\s]+)\)/$3/gxs; |
|||
$a =~ s/([\+-=><\/%*!<>\s]+)\(((\w|\s)+)\)/$1/gxs; |
|||
$a =~ s/((\w|\s)+)\((.+)\)/$1/gxs; |
|||
|
|||
$a =~ s/((\s)+)$//g; |
|||
|
|||
return $a; |
|||
} |
|||
|
|||
sub prepare_description |
|||
{ |
|||
my ($a)= @_; |
|||
|
|||
$a =~ s/(\@itemize \@bullet\n)//g; |
|||
$a =~ s/(\@c help_keyword (.*?)\n)//g; |
|||
$a =~ s/(\@end itemize\n)//g; |
|||
$a =~ s/(\@end example\n)//g; |
|||
$a =~ s/(\@example\n)//g; |
|||
$a =~ s/(\@{)/{/g; |
|||
$a =~ s/(\@})/}/g; |
|||
$a =~ s/(\@end multitable)/ /g; |
|||
$a =~ s/(\@end table)/ /g; |
|||
$a =~ s/(\@cindex(.*?)\n)//g; |
|||
$a =~ s/(\@findex(.*?)\n)//g; |
|||
$a =~ s/(\@table(.*?)\n)//g; |
|||
$a =~ s/(\@multitable \@columnfractions(.*?)\n)/ /g; |
|||
$a =~ s/(\@node(.*?)\n)/ /g; |
|||
$a =~ s/(\@tab)/\t/g; |
|||
$a =~ s/\@itemx/ /g; |
|||
$a =~ s/(\@item\n(\s*?))(\S)/ --- $3/g; |
|||
$a =~ s/(\@item)/ /g; |
|||
$a =~ s/(\@tindex\s(.*?)\n)//g; |
|||
$a =~ s/(\@c\s(.*?)\n)//g; |
|||
$a =~ s/\@minus\{\}/-/g; |
|||
$a =~ s/\@dots\{\}/.../g; |
|||
$a =~ s/\@var\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@command\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@code\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@strong\{(.+?)\}/$1/go; |
|||
$a =~ s/\@samp\{(.+?)\}/'$1'/go; |
|||
$a =~ s/\@emph\{((.|\n)+?)\}/\/$1\//go; |
|||
$a =~ s/\@xref\{((.|\n)+?)\}/See also : [$1]/go; |
|||
$a =~ s/\@ref\{((.|\n)+?)\}/[$1]/go; |
|||
$a =~ s/\@w\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@strong\{((.|\n)+?)\}/\n!!!!\n$1\n!!!!\n/go; |
|||
$a =~ s/\@file\{((.|\n)+?)\}/\*$1/go; |
|||
$a =~ s/\\/\\\\/g; |
|||
$a =~ s/\n\n$/\n/g; |
|||
$a =~ s/\n\n$/\n/g; |
|||
$a =~ s/\n\n$/\n/g; |
|||
$a =~ s/\n\n$/\n/g; |
|||
$a =~ s/\n\n$/\n/g; |
|||
$a =~ s/\n/\\n/g; |
|||
$a =~ s/\"/\\\"/g; |
|||
|
|||
$a =~ s/\@table \@code/ /g; |
|||
|
|||
return $a; |
|||
} |
|||
|
|||
sub prepare_example |
|||
{ |
|||
my ($a)= @_; |
|||
|
|||
$a =~ s/(^\@c for_help_topic(.*?)\n)//g; |
|||
|
|||
$a =~ s/\@var\{((.|\n)+?)\}/$1/go; |
|||
$a =~ s/\@dots\{\}/.../g; |
|||
$a =~ s/\\/\\\\/g; |
|||
$a =~ s/(\@{)/{/g; |
|||
$a =~ s/(\@})/}/g; |
|||
$a =~ s/(\@\@)/\@/g; |
|||
$a =~ s/(\n*?)$//g; |
|||
$a =~ s/\n/\\n/g; |
|||
$a =~ s/\"/\\\"/g; |
|||
|
|||
return $a; |
|||
} |
|||
|
|||
sub parse_example |
|||
{ |
|||
return if (!($_=~/\@example/)); |
|||
return if ($next_example_for_topic eq ""); |
|||
|
|||
my $topic_name= $next_example_for_topic; |
|||
$next_example_for_topic= ""; |
|||
my $text= ""; |
|||
|
|||
while (<>) |
|||
{ |
|||
$cur_line++; |
|||
last if ($_=~/\@end example/); |
|||
$text .= $_; |
|||
} |
|||
|
|||
$text= prepare_example($text); |
|||
$topic_name= prepare_name($topic_name); |
|||
add_example($topic_name,$text) if ($topic_name ne ""); |
|||
} |
|||
|
|||
sub parse_example_for_topic |
|||
{ |
|||
my ($for_topic)= m|\@c example_for_help_topic (.+?)$|; |
|||
return if ($for_topic eq ""); |
|||
|
|||
$next_example_for_topic= $for_topic; |
|||
} |
|||
|
|||
sub parse_description |
|||
{ |
|||
my ($topic_description)= m|\@c description_for_help_topic (.+?)$|; |
|||
return if ($topic_description eq ""); |
|||
|
|||
my ($topic_name,$topic_keywords)= split(/ /,$topic_description); |
|||
|
|||
if ($topic_name eq "" || $topic_keywords eq "") |
|||
{ |
|||
$topic_name= $topic_description; |
|||
} |
|||
else |
|||
{ |
|||
my $keyword; |
|||
foreach $keyword (split(/ /,$topic_keywords)) |
|||
{ |
|||
add_keyword($topic_name,$keyword) if ($keyword ne ""); |
|||
} |
|||
} |
|||
|
|||
my $text= ""; |
|||
|
|||
while (<>) |
|||
{ |
|||
$cur_line++; |
|||
last if ($_=~/\@c end_description_for_help_topic/); |
|||
$text .= $_; |
|||
} |
|||
|
|||
$text= prepare_description($text); |
|||
$topic_name= prepare_name($topic_name); |
|||
add_description($topic_name,$text); |
|||
} |
|||
|
|||
sub parse_category |
|||
{ |
|||
my ($c_name,$pc_name)= m|\@c help_category (.+?)\@(.+?)$|; |
|||
|
|||
if ($pc_name ne "") |
|||
{ |
|||
$current_category= prepare_name($c_name); |
|||
$current_parent_category= prepare_name($pc_name); |
|||
} |
|||
else |
|||
{ |
|||
my ($c_name)=m|\@c help_category (.+?)$|; |
|||
return if ($c_name eq ""); |
|||
|
|||
$current_category= prepare_name($c_name); |
|||
$current_parent_category= "Contents" |
|||
} |
|||
} |
|||
|
|||
# parse manual: |
|||
|
|||
while (<>) |
|||
{ |
|||
parse_example_for_topic (); |
|||
parse_example (); |
|||
parse_description (); |
|||
parse_category (); |
|||
$cur_line++; |
|||
} |
|||
|
|||
# test results of parsing: |
|||
|
|||
sub print_bad_names |
|||
{ |
|||
my($names,$prompt)= @_; |
|||
if (scalar(@{$names})) |
|||
{ |
|||
print STDERR "\n-------------- $prompt : \n\n"; |
|||
my $name; |
|||
foreach $name (@{$names}) |
|||
{ |
|||
print STDERR "$name\n"; |
|||
} |
|||
print STDERR "\n"; |
|||
} |
|||
} |
|||
|
|||
sub print_verbose_errors |
|||
{ |
|||
my($name_of_log_file)= @_; |
|||
|
|||
my @without_help; |
|||
my @description_with_at; |
|||
my @example_with_at; |
|||
my @without_description; |
|||
my @without_example; |
|||
|
|||
print STDERR "\n-------------- parameters of help completeness : \n\n"; |
|||
|
|||
my $count_lex= 0; |
|||
if (!open (TLEX,"<$path_to_lex_file")) |
|||
{ |
|||
print STDERR "Error opening lex file \"$path_to_lex_file\" $!\n"; |
|||
} |
|||
else |
|||
{ |
|||
for (<TLEX>) |
|||
{ |
|||
my ($a,$lex,$b)=m|(.+?)\"(.+?)\"(.+?)$|; |
|||
next if ($lex eq ""); |
|||
$count_lex++; |
|||
next if (exists($topics{$lex}) || exists($keywords{$lex})); |
|||
push(@without_help,$lex); |
|||
} |
|||
close(TLEX); |
|||
print STDERR "number of lexems in \"$path_to_lex_file\" - $count_lex\n"; |
|||
} |
|||
|
|||
my $name; |
|||
my @topic_names= keys(%topics); |
|||
foreach $name (@topic_names) |
|||
{ |
|||
my $topic= $topics{$name}; |
|||
push(@description_with_at,$name) if ($topic->{description}=~/\@/); |
|||
push(@example_with_at,$name) if ($topic->{example}=~/\@/); |
|||
push(@without_description,$name) if (!exists($topic->{description})); |
|||
push(@without_example,$name) if (!exists($topic->{example})); |
|||
} |
|||
|
|||
my $count_categories= scalar(keys(%categories)); |
|||
print STDERR "number of help categories - ",$count_categories,"\n"; |
|||
my $count_topics= scalar(@topic_names); |
|||
print STDERR "number of help topics - ",$count_topics,"\n"; |
|||
my $count_keywords= scalar(keys(%keywords)); |
|||
print STDERR "number of help keywords - ",$count_keywords,"\n"; |
|||
|
|||
my $count_without_help= scalar(@without_help); |
|||
my $percent_without_help= $count_lex ? |
|||
int (($count_without_help/$count_lex)*100) : |
|||
"100"; |
|||
print_bad_names(\@without_help,"lexems without help (". |
|||
$count_without_help." ~ ". |
|||
$percent_without_help."%)"); |
|||
print_bad_names(\@description_with_at, |
|||
" topics below have symbol \'@\' in their descriptions.\n". |
|||
"it's probably the litter from 'texi' tags (script needs fixing)"); |
|||
print_bad_names(\@example_with_at, |
|||
" topics below have symbol \'@\' in their examples.\n". |
|||
"it's probably the litter from 'texi' tags (script needs fixing)"); |
|||
print_bad_names(\@without_description,"topics without description"); |
|||
|
|||
my $count_without_example= scalar(@without_example); |
|||
my $percent_without_example= $count_topics ? |
|||
int (($count_without_example/$count_topics)*100) : |
|||
"100"; |
|||
print_bad_names(\@without_example,"topics without example (". |
|||
$count_without_example." ~ ". |
|||
$percent_without_example."%)"); |
|||
} |
|||
|
|||
print_verbose_errors if ($verbose_option ne 0); |
|||
|
|||
# output result |
|||
|
|||
sub print_insert_header |
|||
{ |
|||
my($count,$header)= @_; |
|||
|
|||
if ($count % $insert_portion_size ne 0) { |
|||
print ","; |
|||
} else { |
|||
print ";\n" if ($count ne 0); |
|||
print "$header"; |
|||
} |
|||
} |
|||
|
|||
print <<EOF; |
|||
-- Copyright (C) 2000-2005 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; version 2 of the License. |
|||
-- |
|||
-- 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 |
|||
|
|||
EOF |
|||
print "set sql_mode='';\n"; |
|||
print "delete from help_topic;\n"; |
|||
print "delete from help_category;\n"; |
|||
print "delete from help_keyword;\n"; |
|||
print "delete from help_relation;\n\n"; |
|||
|
|||
my @category_names= keys(%categories); |
|||
if (scalar(@category_names)) |
|||
{ |
|||
my $cat_name; |
|||
my $count= 0; |
|||
foreach $cat_name (@category_names) |
|||
{ |
|||
$categories{$cat_name}->{__id__}= $count; |
|||
$count++; |
|||
} |
|||
|
|||
my $header= "insert into help_category ". |
|||
"(help_category_id,name,parent_category_id) values "; |
|||
$count= 0; |
|||
foreach $cat_name (@category_names) |
|||
{ |
|||
print_insert_header($count,$header); |
|||
my $parent_cat_name= $categories{$cat_name}->{__parent_category__}; |
|||
my $parent_cat_id= $parent_cat_name eq "" |
|||
? "-1" : $categories{$parent_cat_name}->{__id__}; |
|||
print "($count,\"$cat_name\",$parent_cat_id)"; |
|||
$count++; |
|||
} |
|||
printf ";\n\n"; |
|||
} |
|||
|
|||
my @topic_names= keys(%topics); |
|||
if (scalar(@topic_names)) |
|||
{ |
|||
my $header= "insert into help_topic ". |
|||
"(help_topic_id,help_category_id,name,description,example) values "; |
|||
my $topic_name; |
|||
my $count= 0; |
|||
foreach $topic_name (@topic_names) |
|||
{ |
|||
print_insert_header($count,$header); |
|||
my $topic= $topics{$topic_name}; |
|||
print "($count,"; |
|||
print "$topic->{category}->{__id__},"; |
|||
print "\"$topic_name\","; |
|||
print "\"$topic->{description}\","; |
|||
print "\"$topic->{example}\")"; |
|||
$topics{$topic_name}->{__id__}= $count; |
|||
$count++; |
|||
} |
|||
printf ";\n\n"; |
|||
} |
|||
|
|||
my @keywords_names= keys(%keywords); |
|||
if (scalar(@keywords_names)) |
|||
{ |
|||
my $header= "insert into help_keyword (help_keyword_id,name) values "; |
|||
my $keyword_name; |
|||
my $count= 0; |
|||
foreach $keyword_name (@keywords_names) |
|||
{ |
|||
print_insert_header($count,$header); |
|||
print "($count,\"$keyword_name\")"; |
|||
$count++; |
|||
} |
|||
printf ";\n\n"; |
|||
|
|||
$header= "insert into help_relation ". |
|||
"(help_topic_id,help_keyword_id) values "; |
|||
$count= 0; |
|||
my $count_keyword= 0; |
|||
foreach $keyword_name (@keywords_names) |
|||
{ |
|||
my $topic_name; |
|||
foreach $topic_name (keys(%{$keywords{$keyword_name}})) |
|||
{ |
|||
print_insert_header($count,$header); |
|||
print "($topics{$topic_name}->{__id__},$count_keyword)"; |
|||
$count++; |
|||
} |
|||
$count_keyword++; |
|||
} |
|||
printf ";\n\n"; |
|||
} |
|||
|
|||
if ($count_errors) |
|||
{ |
|||
print STDERR "$count_errors errors !!!\n"; |
|||
exit 1; |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue