Merge jcole@work.mysql.com:/home/bk/mysql-4.0
into mugatu.spaceapes.com:/home/jcole/bk/mysql-4.0
This commit is contained in:
commit
54b95c7f9a
123
Docs/Makefile.am
123
Docs/Makefile.am
@ -48,24 +48,26 @@ include.texi: ../configure.in
|
|||||||
grep "MYSQL_TCP_PORT_DEFAULT=" ../configure.in | \
|
grep "MYSQL_TCP_PORT_DEFAULT=" ../configure.in | \
|
||||||
sed -e 's;MYSQL_TCP_PORT_DEFAULT=;;' >> $@
|
sed -e 's;MYSQL_TCP_PORT_DEFAULT=;;' >> $@
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# English Manual
|
||||||
|
#
|
||||||
|
|
||||||
|
# GNU Info
|
||||||
mysql.info: manual.texi include.texi
|
mysql.info: manual.texi include.texi
|
||||||
cd $(srcdir) && $(MAKEINFO) --no-split -I $(srcdir) $<
|
cd $(srcdir) && $(MAKEINFO) --no-split -I $(srcdir) $<
|
||||||
|
|
||||||
|
# Plain Text
|
||||||
manual.txt: manual.texi include.texi
|
manual.txt: manual.texi include.texi
|
||||||
cd $(srcdir) && \
|
cd $(srcdir) && \
|
||||||
$(MAKEINFO) -I $(srcdir) --no-headers --no-split --output $@ $<
|
$(MAKEINFO) -I $(srcdir) --no-headers --no-split --output $@ $<
|
||||||
|
|
||||||
|
# HTML, all in one file
|
||||||
manual.html: manual.texi include.texi $(srcdir)/Support/texi2html
|
manual.html: manual.texi include.texi $(srcdir)/Support/texi2html
|
||||||
cd $(srcdir) && @PERL@ $(srcdir)/Support/texi2html $(TEXI2HTML_FLAGS) $<
|
cd $(srcdir) && @PERL@ $(srcdir)/Support/texi2html $(TEXI2HTML_FLAGS) $<
|
||||||
|
|
||||||
manual_toc.html: manual.html
|
manual_toc.html: manual.html
|
||||||
|
|
||||||
|
# PDF, Portable Document Format
|
||||||
# Fix: add --output-comment with some interesting info?
|
|
||||||
# Fix: @image worked with a older version of pdftex.
|
|
||||||
# Note: @image will work if we first convert all images to pdf ...
|
|
||||||
# is that worth it?
|
|
||||||
# Comment: We need to run pdftex 2 times to get the cross references right.
|
|
||||||
manual.pdf: manual.texi
|
manual.pdf: manual.texi
|
||||||
cat manual.texi | sed -e 's|@image{[^}]*} *||g' > manual-tmp.texi
|
cat manual.texi | sed -e 's|@image{[^}]*} *||g' > manual-tmp.texi
|
||||||
pdftex --interaction=nonstopmode manual-tmp.texi
|
pdftex --interaction=nonstopmode manual-tmp.texi
|
||||||
@ -77,6 +79,88 @@ manual.pdf: manual.texi
|
|||||||
rm -f manual-tmp.*
|
rm -f manual-tmp.*
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
|
# XML, DocBook 4.0
|
||||||
|
mysql.xml: manual.texi include.texi
|
||||||
|
$(MAKEINFO) --force --no-ifinfo --docbook manual.texi
|
||||||
|
mv mysql.xml mysql-tmp.xml
|
||||||
|
Support/docbook-fixup.pl <mysql-tmp.xml >mysql.xml
|
||||||
|
rm -f mysql-tmp.xml
|
||||||
|
|
||||||
|
# Postscript, A4 Paper
|
||||||
|
manual_a4.ps: manual.texi include.texi
|
||||||
|
TEXINPUTS=$(srcdir):$$TEXINPUTS \
|
||||||
|
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
|
||||||
|
$(TEXI2DVI) --batch --texinfo --quiet '@afourpaper' $<
|
||||||
|
$(DVIPS) -t a4 manual.dvi -o $@
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
# Postscript, US Letter Paper
|
||||||
|
manual_letter.ps: manual.texi include.texi
|
||||||
|
TEXINPUTS=$(srcdir):$$TEXINPUTS \
|
||||||
|
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
|
||||||
|
$(TEXI2DVI) --batch $<
|
||||||
|
$(DVIPS) -t letter manual.dvi -o $@
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# German Manual
|
||||||
|
#
|
||||||
|
|
||||||
|
# GNU Info
|
||||||
|
mysql.de.info: manual.de.texi include.texi
|
||||||
|
cd $(srcdir) && $(MAKEINFO) --no-split -I $(srcdir) $<
|
||||||
|
|
||||||
|
# Plain Text
|
||||||
|
manual.de.txt: manual.de.texi include.texi
|
||||||
|
cd $(srcdir) && \
|
||||||
|
$(MAKEINFO) -I $(srcdir) --no-headers --no-split --output $@ $<
|
||||||
|
|
||||||
|
# HTML, all in one file
|
||||||
|
manual.de.html: manual.de.texi include.texi $(srcdir)/Support/texi2html
|
||||||
|
cd $(srcdir) && @PERL@ $(srcdir)/Support/texi2html $(TEXI2HTML_FLAGS) $<
|
||||||
|
manual_toc.de.html: manual.html
|
||||||
|
|
||||||
|
# PDF, Portable Document Format
|
||||||
|
manual.de.pdf: manual.de.texi
|
||||||
|
cat manual.de.texi | sed -e 's|@image{[^}]*} *||g' > manual-tmp.texi
|
||||||
|
pdftex --interaction=nonstopmode manual-tmp.texi
|
||||||
|
texindex manual-tmp.??
|
||||||
|
pdftex --interaction=nonstopmode manual-tmp.texi
|
||||||
|
texindex manual-tmp.??
|
||||||
|
pdftex --interaction=nonstopmode manual-tmp.texi
|
||||||
|
mv manual-tmp.pdf manual.de.pdf
|
||||||
|
rm -f manual-tmp.*
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
# XML, DocBook 4.0
|
||||||
|
mysql.de.xml: manual.de.texi include.texi
|
||||||
|
$(MAKEINFO) --force --no-ifinfo --docbook manual.de.texi
|
||||||
|
mv mysql.de.xml mysql-tmp.xml
|
||||||
|
Support/docbook-fixup.pl <mysql-tmp.xml >mysql.de.xml
|
||||||
|
rm -f mysql-tmp.xml
|
||||||
|
|
||||||
|
# Postscript, A4 Paper
|
||||||
|
manual_a4.de.ps: manual.de.texi include.texi
|
||||||
|
TEXINPUTS=$(srcdir):$$TEXINPUTS \
|
||||||
|
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
|
||||||
|
$(TEXI2DVI) --batch --texinfo --quiet '@afourpaper' $<
|
||||||
|
$(DVIPS) -t a4 manual.de.dvi -o $@
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
# Postscript, US Letter Paper
|
||||||
|
manual_letter.de.ps: manual.de.texi include.texi
|
||||||
|
TEXINPUTS=$(srcdir):$$TEXINPUTS \
|
||||||
|
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
|
||||||
|
$(TEXI2DVI) --batch $<
|
||||||
|
$(DVIPS) -t letter manual.de.dvi -o $@
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Miscellaneous
|
||||||
|
#
|
||||||
|
|
||||||
# Target to produce NuSphere Manual
|
# Target to produce NuSphere Manual
|
||||||
nusphere.pdf: manual.texi
|
nusphere.pdf: manual.texi
|
||||||
cat manual.texi \
|
cat manual.texi \
|
||||||
@ -94,31 +178,6 @@ nusphere.pdf: manual.texi
|
|||||||
rm -f manual-tmp.*
|
rm -f manual-tmp.*
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
# Target to produce DocBook XML
|
|
||||||
mysql.xml: manual.texi include.texi
|
|
||||||
$(MAKEINFO) --force --no-ifinfo --docbook manual.texi
|
|
||||||
mv mysql.xml mysql-tmp.xml
|
|
||||||
Support/docbook-fixup.pl <mysql-tmp.xml >mysql.xml
|
|
||||||
rm -f mysql-tmp.xml
|
|
||||||
|
|
||||||
# The texi2dvi gives a lot of harmless errors. Just ignore them unless
|
|
||||||
# you want to help with the typesetting part.
|
|
||||||
# This is the European papersize version
|
|
||||||
manual_a4.ps: manual.texi include.texi
|
|
||||||
TEXINPUTS=$(srcdir):$$TEXINPUTS \
|
|
||||||
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
|
|
||||||
$(TEXI2DVI) --batch --texinfo --quiet '@afourpaper' $<
|
|
||||||
$(DVIPS) -t a4 manual.dvi -o $@
|
|
||||||
touch $@
|
|
||||||
|
|
||||||
# This is the American papersize version
|
|
||||||
manual_letter.ps: manual.texi include.texi
|
|
||||||
TEXINPUTS=$(srcdir):$$TEXINPUTS \
|
|
||||||
MAKEINFO='$(MAKEINFO) -I $(srcdir)' \
|
|
||||||
$(TEXI2DVI) --batch $<
|
|
||||||
$(DVIPS) -t letter manual.dvi -o $@
|
|
||||||
touch $@
|
|
||||||
|
|
||||||
# Include images for the manual in the distribution
|
# Include images for the manual in the distribution
|
||||||
dist-hook:
|
dist-hook:
|
||||||
BD=`cd $(top_srcdir); pwd`; \
|
BD=`cd $(top_srcdir); pwd`; \
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
\input texinfo @c -*-texinfo-*-
|
\input texinfo @c -*-texinfo-*-
|
||||||
@c Copyright 1998 TcX AB, Detron HB and Monty Program KB
|
@c Copyright 2002 MySQL AB, TcX AB, Detron HB and Monty Program KB
|
||||||
@c
|
@c
|
||||||
@c %**start of header
|
@c %**start of header
|
||||||
@setfilename internals.info
|
@setfilename internals.info
|
||||||
|
|
||||||
@c We want the types in the same index
|
@c We want the types in the same index
|
||||||
@c @synindex tp fn cp
|
|
||||||
@synindex cp fn
|
@synindex cp fn
|
||||||
|
|
||||||
@iftex
|
@iftex
|
||||||
@c Well this is normal in Europe. Maybe this should go into the include.texi?
|
|
||||||
@afourpaper
|
@afourpaper
|
||||||
@end iftex
|
@end iftex
|
||||||
|
|
||||||
@c Get version and other info
|
@c Get version and other info
|
||||||
@include include.texi
|
@include include.texi
|
||||||
|
|
||||||
@ifclear tex-debug
|
@ifclear tex-debug
|
||||||
@c This removes the black squares in the right margin
|
@c This removes the black squares in the right margin
|
||||||
@finalout
|
@finalout
|
||||||
@end ifclear
|
@end ifclear
|
||||||
|
|
||||||
@c Set background for HTML
|
@c Set background for HTML
|
||||||
@set _body_tags BGCOLOR=#FFFFFF TEXT=#000000 LINK=#101090 VLINK=#7030B0
|
@set _body_tags BGCOLOR=#FFFFFF TEXT=#000000 LINK=#101090 VLINK=#7030B0
|
||||||
@settitle @strong{MySQL} internals Manual for version @value{mysql_version}.
|
@settitle @strong{MySQL} Internals Manual for version @value{mysql_version}.
|
||||||
@setchapternewpage off
|
@setchapternewpage odd
|
||||||
@paragraphindent 0
|
@paragraphindent 0
|
||||||
|
|
||||||
@c %**end of header
|
@c %**end of header
|
||||||
|
|
||||||
@ifinfo
|
@ifinfo
|
||||||
@ -35,67 +39,77 @@ END-INFO-DIR-ENTRY
|
|||||||
@sp 10
|
@sp 10
|
||||||
@center @titlefont{@strong{MySQL} Internals Manual}
|
@center @titlefont{@strong{MySQL} Internals Manual}
|
||||||
@sp 10
|
@sp 10
|
||||||
@center Copyright @copyright{} 1998 TcX AB, Detron HB and Monty Program KB
|
@center Copyright @copyright{} 1998-2002 MySQL AB
|
||||||
|
@page
|
||||||
@end titlepage
|
@end titlepage
|
||||||
|
|
||||||
@node Top, Introduction, (dir), (dir)
|
@node Top, caching, (dir), (dir)
|
||||||
|
|
||||||
@ifinfo
|
@ifinfo
|
||||||
This is a manual about @strong{MySQL} internals.
|
This is a manual about @strong{MySQL} internals.
|
||||||
@end ifinfo
|
@end ifinfo
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
* caching:: How MySQL Handles Caching
|
||||||
|
* flush tables:: How MySQL Handles @code{FLUSH TABLES}
|
||||||
|
* filesort:: How MySQL Does Sorting (@code{filesort})
|
||||||
|
* coding guidelines:: Coding Guidelines
|
||||||
|
* mysys functions:: Functions In The @code{mysys} Library
|
||||||
|
* DBUG:: DBUG Tags To Use
|
||||||
|
* protocol:: MySQL Client/Server Protocol
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node caching,,,
|
|
||||||
@chapter How MySQL handles caching
|
@node caching, flush tables, Top, Top
|
||||||
|
@chapter How MySQL Handles Caching
|
||||||
|
|
||||||
@strong{MySQL} has the following caches:
|
@strong{MySQL} has the following caches:
|
||||||
(Note that the some of the filename have a wrong spelling of cache. :)
|
(Note that the some of the filename have a wrong spelling of cache. :)
|
||||||
|
|
||||||
@itemize @bullet
|
@table @strong
|
||||||
|
|
||||||
@item Key cache
|
@item Key Cache
|
||||||
A shared cache for all B-tree index blocks in the different NISAM
|
A shared cache for all B-tree index blocks in the different NISAM
|
||||||
files. Uses hashing and reverse linked lists for quick caching of the
|
files. Uses hashing and reverse linked lists for quick caching of the
|
||||||
last used blocks and quick flushing of changed entries for a specific
|
last used blocks and quick flushing of changed entries for a specific
|
||||||
table. (@file{mysys/mf_keycash.c})
|
table. (@file{mysys/mf_keycash.c})
|
||||||
|
|
||||||
@item Record cache
|
@item Record Cache
|
||||||
This is used for quick scanning of all records in a table.
|
This is used for quick scanning of all records in a table.
|
||||||
(@file{mysys/mf_iocash.c} and @file{isam/_cash.c})
|
(@file{mysys/mf_iocash.c} and @file{isam/_cash.c})
|
||||||
|
|
||||||
@item Table cache
|
@item Table Cache
|
||||||
This holds the last used tables. (@file{sql/sql_base.cc})
|
This holds the last used tables. (@file{sql/sql_base.cc})
|
||||||
|
|
||||||
@item Hostname cache
|
@item Hostname Cache
|
||||||
For quick lookup (with reverse name resolving). Is a must when one has a
|
For quick lookup (with reverse name resolving). Is a must when one has a
|
||||||
slow DNS.
|
slow DNS.
|
||||||
(@file{sql/hostname.cc})
|
(@file{sql/hostname.cc})
|
||||||
|
|
||||||
@item Privilege cache
|
@item Privilege Cache
|
||||||
To allow quick change between databases the last used privileges are
|
To allow quick change between databases the last used privileges are
|
||||||
cached for each user/database combination.
|
cached for each user/database combination.
|
||||||
(@file{sql/sql_acl.cc})
|
(@file{sql/sql_acl.cc})
|
||||||
|
|
||||||
@item Heap table cache
|
@item Heap Table Cache
|
||||||
Many use of GROUP BY or DISTINCT caches all found
|
Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in
|
||||||
rows in a HEAP table (this is a very quick in-memory table with hash index)
|
a @code{HEAP} table. (This is a very quick in-memory table with hash index.)
|
||||||
|
|
||||||
@item Join row cache.
|
@item Join Row Cache
|
||||||
For every full join in a SELECT statement (a full join here means there
|
For every full join in a @code{SELECT} statement (a full join here means
|
||||||
were no keys that one could use to find the next table in a list), the
|
there were no keys that one could use to find the next table in a list),
|
||||||
found rows are cached in a join cache. One SELECT query can use many
|
the found rows are cached in a join cache. One @code{SELECT} query can
|
||||||
join caches in the worst case.
|
use many join caches in the worst case.
|
||||||
@end itemize
|
@end table
|
||||||
|
|
||||||
@node flush tables,,,
|
|
||||||
@chapter How MySQL handles flush tables
|
@node flush tables, filesort, caching, Top
|
||||||
|
@chapter How MySQL Handles @code{FLUSH TABLES}
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Flush tables is handled in @code{sql/sql_base.cc::close_cached_tables()}.
|
Flush tables is handled in @file{sql/sql_base.cc::close_cached_tables()}.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
The idea of flush tables is to force all tables to be closed. This
|
The idea of flush tables is to force all tables to be closed. This
|
||||||
@ -109,8 +123,8 @@ all tables)!
|
|||||||
When one does a @code{FLUSH TABLES}, the variable @code{refresh_version}
|
When one does a @code{FLUSH TABLES}, the variable @code{refresh_version}
|
||||||
will be incremented. Every time a thread releases a table it checks if
|
will be incremented. Every time a thread releases a table it checks if
|
||||||
the refresh version of the table (updated at open) is the same as
|
the refresh version of the table (updated at open) is the same as
|
||||||
the current refresh_version. If not it will close it and broadcast
|
the current @code{refresh_version}. If not it will close it and broadcast
|
||||||
a signal on COND_refresh (to wait any thread that is waiting for
|
a signal on @code{COND_refresh} (to wait any thread that is waiting for
|
||||||
all instanses of a table to be closed).
|
all instanses of a table to be closed).
|
||||||
|
|
||||||
@item
|
@item
|
||||||
@ -119,8 +133,8 @@ The current @code{refresh_version} is also compared to the open
|
|||||||
refresh version is different the thread will free all locks, reopen the
|
refresh version is different the thread will free all locks, reopen the
|
||||||
table and try to get the locks again; This is just to quickly get all
|
table and try to get the locks again; This is just to quickly get all
|
||||||
tables to use the newest version. This is handled by
|
tables to use the newest version. This is handled by
|
||||||
@code{sql/lock.cc::mysql_lock_tables()} and
|
@file{sql/lock.cc::mysql_lock_tables()} and
|
||||||
@code{sql/sql_base.cc::wait_for_tables()}.
|
@file{sql/sql_base.cc::wait_for_tables()}.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
When all tables has been closed @code{FLUSH TABLES} will return an ok
|
When all tables has been closed @code{FLUSH TABLES} will return an ok
|
||||||
@ -134,8 +148,8 @@ After this it will give other threads a chance to open the same tables.
|
|||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@node Filesort,,,
|
@node filesort, coding guidelines, flush tables, Top
|
||||||
@chapter How MySQL does sorting (filesort)
|
@chapter How MySQL Does Sorting (@code{filesort})
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
|
|
||||||
@ -146,7 +160,7 @@ Read all rows according to key or by table scanning.
|
|||||||
Store the sort-key in a buffer (@code{sort_buffer}).
|
Store the sort-key in a buffer (@code{sort_buffer}).
|
||||||
|
|
||||||
@item
|
@item
|
||||||
When the buffer gets full, run a qsort on it and store the result
|
When the buffer gets full, run a @code{qsort} on it and store the result
|
||||||
in a temporary file. Save a pointer to the sorted block.
|
in a temporary file. Save a pointer to the sorted block.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
@ -174,8 +188,9 @@ and then we read the rows in the sorted order into a row buffer
|
|||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@node Coding guidelines,,,
|
|
||||||
@chapter Coding guidelines
|
@node coding guidelines, mysys functions, filesort, Top
|
||||||
|
@chapter Coding Guidelines
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
|
|
||||||
@ -225,23 +240,23 @@ Don't use two commands on the same line.
|
|||||||
Do not check the same pointer for @code{NULL} more than once.
|
Do not check the same pointer for @code{NULL} more than once.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Use long function and variable names in English; This makes your code
|
Use long function and variable names in English. This makes your code
|
||||||
easier to read.
|
easier to read.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Use my_var as opposed to myVar or MyVar (@samp{_} rather than dancing SHIFT
|
Use @code{my_var} as opposed to @code{myVar} or @code{MyVar} (@samp{_}
|
||||||
to seperate words in identifiers).
|
rather than dancing SHIFT to seperate words in identifiers).
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Think assembly - make it easier for the compiler to optimize your code.
|
Think assembly - make it easier for the compiler to optimize your code.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Comment your code when you do something that someone else may think
|
Comment your code when you do something that someone else may think
|
||||||
is not ''trivial''.
|
is not ``trivial''.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Use @code{libstring} functions (in the strings directory)
|
Use @code{libstring} functions (in the @file{strings} directory)
|
||||||
instead of standard libc string functions whenever possible.
|
instead of standard @code{libc} string functions whenever possible.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Avoid using @code{malloc()} (its REAL slow); For memory allocations
|
Avoid using @code{malloc()} (its REAL slow); For memory allocations
|
||||||
@ -268,26 +283,25 @@ Any @code{#define}'s are in all-caps.
|
|||||||
Matching @samp{@{} are in the same column.
|
Matching @samp{@{} are in the same column.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Put the @samp{@{} after a 'switch' on the same line
|
Put the @samp{@{} after a @code{switch} on the same line, as this gives
|
||||||
|
better overall indentation for the switch statement:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
switch (arg) {
|
switch (arg) {
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Because this gives better overall indentation for the switch statement.
|
@item
|
||||||
|
In all other cases, @samp{@{} and @samp{@}} should be on their own line, except
|
||||||
|
if there is nothing inside @samp{@{} and @samp{@}}.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
In all other cases, @{ and @} should be on their own line, except
|
Have a space after @code{if}
|
||||||
if there is nothing inside @{ @}.
|
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Have a space after 'if'
|
Put a space after @samp{,} for function arguments
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Put a space after ',' for function arguments
|
Functions return @samp{0} on success, and non-zero on error, so you can do:
|
||||||
|
|
||||||
@item
|
|
||||||
Functions return 0 on success, and non-zero on error, so you can do:
|
|
||||||
|
|
||||||
@example
|
@example
|
||||||
if(a() || b() || c()) { error("something went wrong"); }
|
if(a() || b() || c()) { error("something went wrong"); }
|
||||||
@ -335,113 +349,110 @@ Suggested mode in emacs:
|
|||||||
(setq c-default-style "MY")
|
(setq c-default-style "MY")
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@node mysys functions,,,
|
|
||||||
@chapter mysys functions
|
|
||||||
|
|
||||||
Functions i mysys: (For flags se my_sys.h)
|
@node mysys functions, DBUG, coding guidelines, Top
|
||||||
|
@chapter Functions In The @code{mysys} Library
|
||||||
|
|
||||||
int my_copy _A((const char *from,const char *to,myf MyFlags));
|
Functions in @code{mysys}: (For flags see @file{my_sys.h})
|
||||||
- Copy file
|
|
||||||
|
|
||||||
int my_delete _A((const char *name,myf MyFlags));
|
@table @code
|
||||||
- Delete file
|
@item int my_copy _A((const char *from, const char *to, myf MyFlags));
|
||||||
|
Copy file from @code{from} to @code{to}.
|
||||||
|
|
||||||
int my_getwd _A((string buf,uint size,myf MyFlags));
|
@item int my_delete _A((const char *name, myf MyFlags));
|
||||||
int my_setwd _A((const char *dir,myf MyFlags));
|
Delete file @code{name}.
|
||||||
- Get and set working directory
|
|
||||||
|
|
||||||
string my_tempnam _A((const char *pfx,myf MyFlags));
|
@item int my_getwd _A((string buf, uint size, myf MyFlags));
|
||||||
- Make a uniq temp file name by using dir and adding something after
|
@item int my_setwd _A((const char *dir, myf MyFlags));
|
||||||
pfx to make name uniq. Name is made by adding a uniq 6 length-string
|
Get and set working directory.
|
||||||
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));
|
@item string my_tempnam _A((const char *pfx, myf MyFlags));
|
||||||
File my_create _A((const char *FileName,int CreateFlags,
|
Make a unique temporary file name by using dir and adding something after
|
||||||
int AccsesFlags, myf MyFlags));
|
@code{pfx} to make name unique. The file name is made by adding a unique
|
||||||
int my_close _A((File Filedes,myf MyFlags));
|
six character string and @code{TMP_EXT} after @code{pfx}.
|
||||||
uint my_read _A((File Filedes,byte *Buffer,uint Count,myf MyFlags));
|
Returns pointer to @code{malloc()}'ed area for filename. Should be freed by
|
||||||
uint my_write _A((File Filedes,const byte *Buffer,uint Count,
|
@code{free()}.
|
||||||
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));
|
@item File my_open _A((const char *FileName,int Flags,myf MyFlags));
|
||||||
- Rename file
|
@item File my_create _A((const char *FileName, int CreateFlags, int AccsesFlags, myf MyFlags));
|
||||||
|
@item int my_close _A((File Filedes, myf MyFlags));
|
||||||
|
@item uint my_read _A((File Filedes, byte *Buffer, uint Count, myf MyFlags));
|
||||||
|
@item uint my_write _A((File Filedes, const byte *Buffer, uint Count, myf MyFlags));
|
||||||
|
@item ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags));
|
||||||
|
@item 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 @code{MYF_WME}) and only have
|
||||||
|
to test for != 0 if error (flag @code{MY_NABP}).
|
||||||
|
|
||||||
FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags));
|
@item int my_rename _A((const char *from, const char *to, myf MyFlags));
|
||||||
FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags));
|
Rename file from @code{from} to @code{to}.
|
||||||
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,
|
@item FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags));
|
||||||
uint uLine, myf MyFlag));
|
@item FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags));
|
||||||
gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile,
|
@item int my_fclose _A((FILE *fd,myf MyFlags));
|
||||||
uint uLine, myf MyFlag));
|
@item uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags));
|
||||||
void _myfree _A((gptr pPtr,const char *sFile,uint uLine));
|
@item uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count, myf MyFlags));
|
||||||
int _sanity _A((const char *sFile,unsigned int uLine));
|
@item ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags));
|
||||||
gptr _myget_copy_of_memory _A((const byte *from,uint length,
|
@item ulong my_ftell _A((FILE *stream,myf MyFlags));
|
||||||
const char *sFile, uint uLine,
|
Same read-interface for streams as for files.
|
||||||
myf MyFlag));
|
|
||||||
- malloc(size,myflag) is mapped to this functions if not compiled
|
|
||||||
with -DSAFEMALLOC
|
|
||||||
|
|
||||||
void TERMINATE _A((void));
|
@item gptr _mymalloc _A((uint uSize,const char *sFile,uint uLine, myf MyFlag));
|
||||||
- Writes malloc-info on stdout if compiled with -DSAFEMALLOC.
|
@item gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile,uint uLine, myf MyFlag));
|
||||||
|
@item void _myfree _A((gptr pPtr,const char *sFile,uint uLine));
|
||||||
|
@item int _sanity _A((const char *sFile,unsigned int uLine));
|
||||||
|
@item gptr _myget_copy_of_memory _A((const byte *from,uint length,const char *sFile, uint uLine,myf MyFlag));
|
||||||
|
@code{malloc(size,myflag)} is mapped to these functions if not compiled
|
||||||
|
with @code{-DSAFEMALLOC}.
|
||||||
|
|
||||||
int my_chsize _A((File fd,ulong newlength,myf MyFlags));
|
@item void TERMINATE _A((void));
|
||||||
- Change size of file
|
Writes @code{malloc()} info on @code{stdout} if compiled with
|
||||||
|
@code{-DSAFEMALLOC}.
|
||||||
|
|
||||||
void my_error _D((int nr,myf MyFlags, ...));
|
@item int my_chsize _A((File fd, ulong newlength, myf MyFlags));
|
||||||
- Writes message using error number (se mysys/errors.h) on
|
Change size of file @code{fd} to @code{newlength}.
|
||||||
stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
|
|
||||||
|
|
||||||
void my_message _A((const char *str,myf MyFlags));
|
@item void my_error _D((int nr, myf MyFlags, ...));
|
||||||
- Writes message-string on
|
Writes message using error number (see @file{mysys/errors.h}) on @code{stdout},
|
||||||
stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
|
or using curses, if @code{MYSYS_PROGRAM_USES_CURSES()} has been called.
|
||||||
|
|
||||||
void my_init _A((void ));
|
@item void my_message _A((const char *str, myf MyFlags));
|
||||||
- Start each program (in main) with this.
|
Writes @code{str} on @code{stdout}, or using curses, if
|
||||||
void my_end _A((int infoflag));
|
@code{MYSYS_PROGRAM_USES_CURSES()} has been called.
|
||||||
- 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));
|
@item void my_init _A((void ));
|
||||||
- Delete from before rename of to to from. Copyes state from old
|
Start each program (in @code{main()}) with this.
|
||||||
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));
|
@item void my_end _A((int infoflag));
|
||||||
- Copye state from old file to new file.
|
Gives info about program.
|
||||||
If MY_COPY_TIME is set sets copy also time.
|
If @code{infoflag & MY_CHECK_ERROR}, prints if some files are left open.
|
||||||
|
If @code{infoflag & MY_GIVE_INFO}, prints timing info and malloc info
|
||||||
|
about program.
|
||||||
|
|
||||||
string my_filename _A((File fd));
|
@item int my_redel _A((const char *from, const char *to, int MyFlags));
|
||||||
- Give filename of open file.
|
Delete @code{from} before rename of @code{to} to @code{from}. Copies state
|
||||||
|
from old file to new file. If @code{MY_COPY_TIME} is set, sets old time.
|
||||||
|
|
||||||
int dirname _A((string to,const char *name));
|
@item int my_copystat _A((const char *from, const char *to, int MyFlags));
|
||||||
- Copy name of directory from filename.
|
Copy state from old file to new file. If @code{MY_COPY_TIME} is set,
|
||||||
|
sets old time.
|
||||||
|
|
||||||
int test_if_hard_path _A((const char *dir_name));
|
@item string my_filename _A((File fd));
|
||||||
- Test if dirname is a hard path (Starts from root)
|
Returns filename of open file.
|
||||||
|
|
||||||
void convert_dirname _A((string name));
|
@item int dirname _A((string to, const char *name));
|
||||||
- Convert dirname acording to system.
|
Copy name of directory from filename.
|
||||||
- In MSDOS changes all caracters to capitals and changes '/' to
|
|
||||||
'\'
|
@item int test_if_hard_path _A((const char *dir_name));
|
||||||
string fn_ext _A((const char *name));
|
Test if @code{dir_name} is a hard path (starts from root).
|
||||||
- Returns pointer to extension in filename
|
|
||||||
string fn_format _A((string to,const char *name,const char *dsk,
|
@item void convert_dirname _A((string name));
|
||||||
const char *form,int flag));
|
Convert dirname according to system.
|
||||||
|
In MSDOS, changes all characters to capitals and changes @samp{/} to @samp{\}.
|
||||||
|
|
||||||
|
@item string fn_ext _A((const char *name));
|
||||||
|
Returns pointer to extension in filename.
|
||||||
|
|
||||||
|
@item 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
|
format a filename with replace of library and extension and
|
||||||
converts between different systems.
|
converts between different systems.
|
||||||
params to and name may be identicall
|
params to and name may be identicall
|
||||||
@ -455,60 +466,93 @@ Functions i mysys: (For flags se my_sys.h)
|
|||||||
"open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and
|
"open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and
|
||||||
convert filename to system-form.
|
convert filename to system-form.
|
||||||
|
|
||||||
string fn_same _A((string toname,const char *name,int flag));
|
@item string fn_same _A((string toname, const char *name, int flag));
|
||||||
- Copys directory and extension from name to toname if neaded.
|
Copys directory and extension from @code{name} to @code{toname} if neaded.
|
||||||
copy can be forced by same flags that in fn_format.
|
Copying can be forced by same flags used in @code{fn_format()}.
|
||||||
|
|
||||||
int wild_compare _A((const char *str,const char *wildstr));
|
@item int wild_compare _A((const char *str, const char *wildstr));
|
||||||
- Compare if str matches wildstr. Wildstr can contain "*" and "?"
|
Compare if @code{str} matches @code{wildstr}. @code{wildstr} can contain
|
||||||
as match-characters.
|
@samp{*} and @samp{?} as wildcard characters.
|
||||||
Returns 0 if match.
|
Returns 0 if @code{str} and @code{wildstr} match.
|
||||||
|
|
||||||
void get_date _A((string to,int timeflag));
|
@item void get_date _A((string to, int timeflag));
|
||||||
- Get current date in a form ready for printing.
|
Get current date in a form ready for printing.
|
||||||
|
|
||||||
void soundex _A((string out_pntr, string in_pntr))
|
@item void soundex _A((string out_pntr, string in_pntr))
|
||||||
- Makes in_pntr to a 5 chars long string. All words that sounds
|
Makes @code{in_pntr} to a 5 char long string. All words that sound
|
||||||
alike have the same string.
|
alike have the same string.
|
||||||
|
|
||||||
int init_key_cache _A((ulong use_mem,ulong leave_this_much_mem));
|
@item int init_key_cache _A((ulong use_mem, ulong leave_this_much_mem));
|
||||||
- Use cacheing of keys in MISAM, PISAM, and ISAM.
|
Use caching of keys in MISAM, PISAM, and ISAM.
|
||||||
KEY_CACHE_SIZE is a good size.
|
@code{KEY_CACHE_SIZE} is a good size.
|
||||||
- Remember to lock databases for optimal cacheing
|
Remember to lock databases for optimal caching.
|
||||||
|
|
||||||
void end_key_cache _A((void));
|
@item void end_key_cache _A((void));
|
||||||
- End key-cacheing.
|
End key caching.
|
||||||
|
|
||||||
@node DBUG,,,
|
|
||||||
@chapter The DBUG tags to use:
|
@node DBUG, protocol, mysys functions, Top
|
||||||
|
@chapter DBUG Tags To Use
|
||||||
|
|
||||||
Here is some of the tags we now use:
|
Here is some of the tags we now use:
|
||||||
(We should probably add a couple of new ones)
|
(We should probably add a couple of new ones)
|
||||||
|
|
||||||
"enter" Arguments to the function.
|
@table @code
|
||||||
"exit" Results from the function.
|
@item enter
|
||||||
"info" is something that may be interesting.
|
Arguments to the function.
|
||||||
"warning" is when something doesn't go the usual route or may be wrong.
|
|
||||||
"error" when something went wrong.
|
@item exit
|
||||||
"loop" write in a loop, that is probably only useful when debugging
|
Results from the function.
|
||||||
the loop. These should normally be deleted when on is
|
|
||||||
satisfied with the code and it has been in real use for a while.
|
@item info
|
||||||
|
Something that may be interesting.
|
||||||
|
|
||||||
|
@item warning
|
||||||
|
When something doesn't go the usual route or may be wrong.
|
||||||
|
|
||||||
|
@item error
|
||||||
|
When something went wrong.
|
||||||
|
|
||||||
|
@item loop
|
||||||
|
Write in a loop, that is probably only useful when debugging
|
||||||
|
the loop. These should normally be deleted when one is
|
||||||
|
satisfied with the code and it has been in real use for a while.
|
||||||
|
@end table
|
||||||
|
|
||||||
Some specific to mysqld, because we want to watch these carefully:
|
Some specific to mysqld, because we want to watch these carefully:
|
||||||
|
|
||||||
"trans" Starting/stopping transactions.
|
@table @code
|
||||||
"quit" 'info' when mysqld is preparing to die.
|
@item trans
|
||||||
"query" Print query
|
Starting/stopping transactions.
|
||||||
|
|
||||||
@node protocol,,,
|
@item quit
|
||||||
@chapter MySQL client/server protocol
|
@code{info} when mysqld is preparing to die.
|
||||||
|
|
||||||
Raw packet without compression
|
@item query
|
||||||
==============================
|
Print query.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@node protocol, , DBUG, Top
|
||||||
|
@chapter MySQL Client/Server Protocol
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* raw packet without compression::
|
||||||
|
* raw packet with compression::
|
||||||
|
* basic packets::
|
||||||
|
* communication::
|
||||||
|
* fieldtype codes::
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node raw packet without compression, raw packet with compression, protocol, protocol
|
||||||
|
@section Raw Packet Without Compression
|
||||||
|
|
||||||
|
@example
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
| Packet Length | Packet no | Data |
|
| Packet Length | Packet no | Data |
|
||||||
| 3 Bytes | 1 Byte | n Bytes |
|
| 3 Bytes | 1 Byte | n Bytes |
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
@end example
|
||||||
|
|
||||||
3 Byte packet length
|
3 Byte packet length
|
||||||
The length is calculated with int3store
|
The length is calculated with int3store
|
||||||
@ -526,12 +570,15 @@ n Byte data
|
|||||||
The packet length can be recalculated with:
|
The packet length can be recalculated with:
|
||||||
length = byte1 + (256 * byte2) + (256 * 256 * byte3)
|
length = byte1 + (256 * byte2) + (256 * 256 * byte3)
|
||||||
|
|
||||||
Raw packet with compression
|
@node raw packet with compression, basic packets, raw packet without compression, protocol
|
||||||
===========================
|
@section Raw Packet With Compression
|
||||||
|
|
||||||
|
@example
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
| Packet Length | Packet no | Uncomp. Packet Length |
|
| Packet Length | Packet no | Uncomp. Packet Length |
|
||||||
| 3 Bytes | 1 Byte | 3 Bytes |
|
| 3 Bytes | 1 Byte | 3 Bytes |
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
|
@end example
|
||||||
|
|
||||||
3 Byte packet length
|
3 Byte packet length
|
||||||
The length is calculated with int3store
|
The length is calculated with int3store
|
||||||
@ -540,14 +587,23 @@ Raw packet with compression
|
|||||||
1 Byte packet no
|
1 Byte packet no
|
||||||
3 Byte uncompressed packet length
|
3 Byte uncompressed packet length
|
||||||
|
|
||||||
If compression is used the first 7 bytes of each paket
|
If compression is used the first 7 bytes of each packet
|
||||||
is the header of the paket.
|
is the header of the packet.
|
||||||
|
|
||||||
|
@node basic packets, communication, raw packet with compression, protocol
|
||||||
|
@section Basic Packets
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* ok packet::
|
||||||
|
* error packet::
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node ok packet, error packet, basic packets, basic packets
|
||||||
|
@subsection OK Packet
|
||||||
|
|
||||||
Basic packets
|
|
||||||
==============
|
|
||||||
OK-packet
|
|
||||||
For details see sql/net_pkg.cc
|
For details see sql/net_pkg.cc
|
||||||
function send_ok
|
function send_ok
|
||||||
|
@example
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
| Header | No of Rows | Affected Rows |
|
| Header | No of Rows | Affected Rows |
|
||||||
| | 1 Byte | 1-8 Byte |
|
| | 1 Byte | 1-8 Byte |
|
||||||
@ -558,6 +614,7 @@ OK-packet
|
|||||||
| Messagetext |
|
| Messagetext |
|
||||||
| n Byte |
|
| n Byte |
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
@end example
|
||||||
|
|
||||||
Header
|
Header
|
||||||
1 byte number of rows ? (always 0 ?)
|
1 byte number of rows ? (always 0 ?)
|
||||||
@ -568,7 +625,11 @@ OK-packet
|
|||||||
1-8 bytes length of message
|
1-8 bytes length of message
|
||||||
n bytes messagetext
|
n bytes messagetext
|
||||||
|
|
||||||
Error-packet
|
|
||||||
|
@node error packet, , ok packet, basic packets
|
||||||
|
@subsection Error Packet
|
||||||
|
|
||||||
|
@example
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
| Header | Statuscode | Error no |
|
| Header | Statuscode | Error no |
|
||||||
| | 1 Byte | 2 Byte |
|
| | 1 Byte | 2 Byte |
|
||||||
@ -576,6 +637,7 @@ Error-packet
|
|||||||
| Messagetext | 0x00 |
|
| Messagetext | 0x00 |
|
||||||
| n Byte | 1 Byte |
|
| n Byte | 1 Byte |
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
@end example
|
||||||
|
|
||||||
Header
|
Header
|
||||||
1 byte status code (0xFF = ERROR)
|
1 byte status code (0xFF = ERROR)
|
||||||
@ -584,9 +646,8 @@ Error-packet
|
|||||||
1 byte 0x00
|
1 byte 0x00
|
||||||
|
|
||||||
|
|
||||||
|
@node communication, fieldtype codes, basic packets, protocol
|
||||||
The communication
|
@section Communication
|
||||||
=================
|
|
||||||
|
|
||||||
> Packet from server to client
|
> Packet from server to client
|
||||||
< Paket from client tor server
|
< Paket from client tor server
|
||||||
@ -677,9 +738,10 @@ The communication
|
|||||||
n data
|
n data
|
||||||
|
|
||||||
|
|
||||||
Fieldtype Codes:
|
@node fieldtype codes, , communication, protocol
|
||||||
================
|
@section Fieldtype Codes
|
||||||
|
|
||||||
|
@example
|
||||||
display_length |enum_field_type |flags
|
display_length |enum_field_type |flags
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
Blob 03 FF FF 00 |01 FC |03 90 00 00
|
Blob 03 FF FF 00 |01 FC |03 90 00 00
|
||||||
@ -698,7 +760,7 @@ Datetime 03 13 00 00 |01 0C |03 00 00 00
|
|||||||
Timestamp 03 0E 00 00 |01 07 |03 61 04 00
|
Timestamp 03 0E 00 00 |01 07 |03 61 04 00
|
||||||
Time 03 08 00 00 |01 0B |03 00 00 00
|
Time 03 08 00 00 |01 0B |03 00 00 00
|
||||||
Date 03 0A 00 00 |01 0A |03 00 00 00
|
Date 03 0A 00 00 |01 0A |03 00 00 00
|
||||||
|
@end example
|
||||||
|
|
||||||
@c The Index was empty, and ugly, so I removed it. (jcole, Sep 7, 2000)
|
@c The Index was empty, and ugly, so I removed it. (jcole, Sep 7, 2000)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
@\input texinfo @c -*-texinfo-*-
|
\input texinfo @c -*-texinfo-*-
|
||||||
@c Copyright 1997-2001 TcX AB, Detron HB und MySQL Finland AB
|
@c Copyright 1997-2001 TcX AB, Detron HB und MySQL Finland AB
|
||||||
@c
|
@c
|
||||||
@c *********************************************************
|
@c *********************************************************
|
||||||
|
Loading…
x
Reference in New Issue
Block a user