1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-21 21:22:27 +03:00

resolving conflicts

This commit is contained in:
hf@deer.mysql.r18.ru
2003-01-15 13:15:35 +04:00
560 changed files with 19634 additions and 8529 deletions

View File

@ -580,3 +580,5 @@ vio/test-sslclient
vio/test-sslserver vio/test-sslserver
vio/viotest-ssl vio/viotest-ssl
libmysqld/protocol.cc libmysqld/protocol.cc
test_xml
extra/mysql_waitpid

View File

@ -48,7 +48,7 @@ fast_cflags="-O3 -fno-omit-frame-pointer"
# this is one is for someone who thinks 1% speedup is worth not being # this is one is for someone who thinks 1% speedup is worth not being
# able to backtrace # able to backtrace
reckless_cflags="-O3 -fomit-frame-pointer " reckless_cflags="-O3 -fomit-frame-pointer "
debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX -O1" debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX -O1 -Wuninitialized"
base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti" base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti"

View File

@ -26,6 +26,7 @@ hf@bisonxp.(none)
hf@deer.mysql.r18.ru hf@deer.mysql.r18.ru
hf@genie.(none) hf@genie.(none)
jani@dsl-jkl1657.dial.inet.fi jani@dsl-jkl1657.dial.inet.fi
jani@dsl-kpogw4gb5.dial.inet.fi
jani@hynda.(none) jani@hynda.(none)
jani@hynda.mysql.fi jani@hynda.mysql.fi
jani@janikt.pp.saunalahti.fi jani@janikt.pp.saunalahti.fi
@ -69,7 +70,9 @@ peter@mysql.com
ram@gw.udmsearch.izhnet.ru ram@gw.udmsearch.izhnet.ru
ram@mysql.r18.ru ram@mysql.r18.ru
ram@ram.(none) ram@ram.(none)
ranger@regul.home.lan
root@x3.internalnet root@x3.internalnet
salle@banica.(none)
salle@geopard.(none) salle@geopard.(none)
salle@geopard.online.bg salle@geopard.online.bg
sasha@mysql.sashanet.com sasha@mysql.sashanet.com
@ -95,6 +98,7 @@ venu@myvenu.com
venu@work.mysql.com venu@work.mysql.com
vva@eagle.mysql.r18.ru vva@eagle.mysql.r18.ru
vva@genie.(none) vva@genie.(none)
walrus@kishkin.ru
walrus@mysql.com walrus@mysql.com
wax@mysql.com wax@mysql.com
worm@altair.is.lan worm@altair.is.lan

View File

@ -8,7 +8,7 @@ use Getopt::Long;
$opt_distribution=$opt_user=$opt_config_env=""; $opt_distribution=$opt_user=$opt_config_env="";
$opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_suffix=""; $opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_suffix="";
$opt_tmp=$opt_version_suffix=""; $opt_tmp=$opt_version_suffix="";
$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_debug=0; $opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=0;
$opt_innodb=$opt_bdb=$opt_raid=$opt_libwrap=0; $opt_innodb=$opt_bdb=$opt_raid=$opt_libwrap=0;
GetOptions( GetOptions(
@ -30,7 +30,9 @@ GetOptions(
"no-crash-me", "no-crash-me",
"no-perl", "no-perl",
"no-strip", "no-strip",
"no-test|no-mysqltest", "no-test",
"no-mysqltest",
"no-benchmark",
"perl-files=s", "perl-files=s",
"perl-options=s", "perl-options=s",
"raid", "raid",
@ -133,6 +135,7 @@ $ENV{'MYSQL_UNIX_PORT'}=$mysql_unix_port="$opt_tmp/mysql$opt_suffix.build";
$ENV{"PERL5LIB"}="$pwd/$host/perl5:$pwd/$host/perl5/site_perl"; $ENV{"PERL5LIB"}="$pwd/$host/perl5:$pwd/$host/perl5/site_perl";
$slave_port=$mysql_tcp_port+16; $slave_port=$mysql_tcp_port+16;
$manager_port=$mysql_tcp_port+1; $manager_port=$mysql_tcp_port+1;
$mysqladmin_args="--no-defaults -u root --connect_timeout=5 --shutdown_timeout=20";
if ($opt_stage == 0) if ($opt_stage == 0)
{ {
@ -148,19 +151,26 @@ select STDOUT;
$|=1; $|=1;
info("Compiling MySQL$opt_version_suffix at $host$opt_suffix, stage: $opt_stage\n"); info("Compiling MySQL$opt_version_suffix at $host$opt_suffix, stage: $opt_stage\n");
log_timestamp();
if (-x "$host/bin/mysqladmin") if (-x "$host/bin/mysqladmin")
{ {
log_system("$host/bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown"); log_system("$host/bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -s shutdown");
log_system("$host/bin/mysqladmin --no-defaults -u root -P $mysql_tcp_port -h $host -s shutdown"); log_system("$host/bin/mysqladmin $mysqladmin_args -P $mysql_tcp_port -h $host -s shutdown");
log_system("$host/bin/mysqladmin --no-defaults -u root -P $slave_port -h $host -s shutdown"); log_system("$host/bin/mysqladmin $mysqladmin_args -P $slave_port -h $host -s shutdown");
log_system("$host/bin/mysqladmin --no-defaults -u root -P 9306 -h $host -s shutdown"); log_system("$host/bin/mysqladmin $mysqladmin_args -P 9306 -h $host -s shutdown");
log_system("$host/bin/mysqladmin --no-defaults -u root -P 9307 -h $host -s shutdown"); log_system("$host/bin/mysqladmin $mysqladmin_args -P 9307 -h $host -s shutdown");
} }
kill_all("mysqlmanager"); kill_all("mysqlmanager");
#
# Kill all old processes that are in the build directories
# This is to find any old mysqld servers left from previous builds
kill_all("$pwd/host/mysql");
kill_all("$pwd/host/test");
if ($opt_stage == 0) if ($opt_stage == 0)
{ {
log_timestamp();
print "$host: Removing old distribution\n" if ($opt_debug); print "$host: Removing old distribution\n" if ($opt_debug);
if (!$opt_use_old_distribution) if (!$opt_use_old_distribution)
{ {
@ -209,6 +219,7 @@ safe_cd("$pwd/$host/$ver");
if ($opt_stage <= 1) if ($opt_stage <= 1)
{ {
# Fix files if this is in another timezone than the build host # Fix files if this is in another timezone than the build host
log_timestamp();
unlink("config.cache"); unlink("config.cache");
unlink("bdb/build_unix/config.cache"); unlink("bdb/build_unix/config.cache");
unlink("innobase/config.cache"); unlink("innobase/config.cache");
@ -252,6 +263,7 @@ if ($opt_stage <= 1)
if ($opt_stage <= 2) if ($opt_stage <= 2)
{ {
my ($command); my ($command);
log_timestamp();
unlink($opt_distribution) if ($opt_delete && !$opt_use_old_distribution); unlink($opt_distribution) if ($opt_delete && !$opt_use_old_distribution);
$command=$make; $command=$make;
$command.= " $opt_make_options" if (defined($opt_make_options) && $opt_make_options ne ""); $command.= " $opt_make_options" if (defined($opt_make_options) && $opt_make_options ne "");
@ -264,6 +276,7 @@ if ($opt_stage <= 2)
if ($opt_stage <= 3) if ($opt_stage <= 3)
{ {
my $flags= ""; my $flags= "";
log_timestamp();
log_system("rm -fr mysql-3* mysql-4* $pwd/$host/*.tar.gz"); log_system("rm -fr mysql-3* mysql-4* $pwd/$host/*.tar.gz");
log_system("nm -n sql/mysqld | gzip -9 -v 2>&1 > sql/mysqld.sym.gz | cat"); log_system("nm -n sql/mysqld | gzip -9 -v 2>&1 > sql/mysqld.sym.gz | cat");
@ -292,6 +305,7 @@ if (!defined($tar_file))
# #
if ($opt_stage <= 4 && !$opt_no_test) if ($opt_stage <= 4 && !$opt_no_test)
{ {
log_timestamp();
rm_all(<$pwd/$host/test/*>); rm_all(<$pwd/$host/test/*>);
safe_cd("$pwd/$host/test"); safe_cd("$pwd/$host/test");
safe_system("gunzip < $tar_file | $tar xf -"); safe_system("gunzip < $tar_file | $tar xf -");
@ -300,13 +314,15 @@ if ($opt_stage <= 4 && !$opt_no_test)
$tar_file =~ /(mysql[^\/]*)\.tar/; $tar_file =~ /(mysql[^\/]*)\.tar/;
$ver=$1; $ver=$1;
$test_dir="$pwd/$host/test/$ver"; $test_dir="$pwd/$host/test/$ver";
$ENV{"LD_LIBRARY_PATH"}= "$test_dir/lib:" . $ENV{"LD_LIBRARY_PATH"}; $ENV{"LD_LIBRARY_PATH"}= ("$test_dir/lib" .
(defined($ENV{"LD_LIBRARY_PATH"}) ?
":" . $ENV{"LD_LIBRARY_PATH"} : ""));
# #
# Run the test suite # Run the test suite
# #
if ($opt_stage <= 5 && !$opt_no_test) if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest)
{ {
log_timestamp();
system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir); system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir);
safe_cd("${test_dir}/mysql-test"); safe_cd("${test_dir}/mysql-test");
check_system("./mysql-test-run --warnings --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful"); check_system("./mysql-test-run --warnings --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful");
@ -315,11 +331,11 @@ if ($opt_stage <= 5 && !$opt_no_test)
# #
# Start the server if we are going to run any of the benchmarks # Start the server if we are going to run any of the benchmarks
# #
if (!$opt_no_test) if (!$opt_no_test && !$opt_no_benchmark)
{ {
my $extra; my $extra;
safe_cd($test_dir); safe_cd($test_dir);
log_system("./bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown") || info("There was no mysqld running\n"); log_system("./bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -s shutdown") || info("There was no mysqld running\n");
sleep(2); sleep(2);
log_system("rm -f ./data/mysql/*"); log_system("rm -f ./data/mysql/*");
check_system("scripts/mysql_install_db --no-defaults --skip-locking","https://order"); check_system("scripts/mysql_install_db --no-defaults --skip-locking","https://order");
@ -339,8 +355,10 @@ if (!$opt_no_test)
# #
# Compile and install the required Perl modules # Compile and install the required Perl modules
# #
if ($opt_stage <= 7 && $opt_perl_files && !$opt_no_perl && !$opt_no_test) if ($opt_stage <= 7 && $opt_perl_files && !$opt_no_perl && !$opt_no_test &&
!$opt_no_benchmark)
{ {
log_timestamp();
safe_cd($test_dir); safe_cd($test_dir);
rm_all("perl"); rm_all("perl");
safe_system("mkdir perl"); safe_system("mkdir perl");
@ -376,6 +394,7 @@ if ($opt_stage <= 7 && $opt_perl_files && !$opt_no_perl && !$opt_no_test)
# #
if ($opt_stage <= 8 && !$opt_no_test && !$opt_no_crash_me) if ($opt_stage <= 8 && !$opt_no_test && !$opt_no_crash_me)
{ {
log_timestamp();
safe_cd("$test_dir/sql-bench"); safe_cd("$test_dir/sql-bench");
log_system("rm -f limits/mysql.cfg"); log_system("rm -f limits/mysql.cfg");
safe_system("perl ./crash-me --force --batch-mode $connect_option"); safe_system("perl ./crash-me --force --batch-mode $connect_option");
@ -384,8 +403,9 @@ if ($opt_stage <= 8 && !$opt_no_test && !$opt_no_crash_me)
# #
# Run sql-bench Benchmarks # Run sql-bench Benchmarks
# #
if ($opt_stage <= 9 && !$opt_no_test) if ($opt_stage <= 9 && !$opt_no_test && !$opt_no_benchmark)
{ {
log_timestamp();
safe_cd("$test_dir/sql-bench"); safe_cd("$test_dir/sql-bench");
log_system("rm -f output/*"); log_system("rm -f output/*");
$tmp= $opt_fast_benchmark ? "--fast --user root --small-test" : ""; $tmp= $opt_fast_benchmark ? "--fast --user root --small-test" : "";
@ -405,7 +425,7 @@ if ($opt_stage <= 9 && !$opt_no_test)
rm_all($bench_tmpdir); rm_all($bench_tmpdir);
rm_all("$opt_tmp") if ($new_opt_tmp); rm_all("$opt_tmp") if ($new_opt_tmp);
log_system("$pwd/$host/bin/mysqladmin --no-defaults -S $mysql_unix_port -u root shutdown"); log_system("$pwd/$host/bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -u root shutdown");
print LOG "ok\n"; print LOG "ok\n";
close LOG; close LOG;
print "$host: ok\n"; print "$host: ok\n";
@ -416,7 +436,7 @@ exit 0;
sub usage sub usage
{ {
print <<EOF; print <<EOF;
$0 version 1.4 $0 version 1.5
$0 takes the following options: $0 takes the following options:
@ -469,7 +489,13 @@ Do not run the "crash-me" test
Do not strip the binaries included in the binary distribution Do not strip the binaries included in the binary distribution
--no-test --no-test
Do not run any tests Do not run any tests.
--no-benchmark
Do not run the benchmark test (written in perl)
--no-mysqltest
Do not run the the mysql-test-run test (Same as 'make test')
--perl-files=list of files --perl-files=list of files
Compile and install the given perl modules. Compile and install the given perl modules.
@ -532,6 +558,7 @@ sub abort
my($mail_header_file); my($mail_header_file);
print LOG "\n$message\n"; print LOG "\n$message\n";
print "$host: $message\n" if ($opt_debug); print "$host: $message\n" if ($opt_debug);
print LOG "Aborting\n";
close LOG; close LOG;
if ($opt_user) if ($opt_user)
@ -547,7 +574,6 @@ sub abort
unlink($mail_header_file); unlink($mail_header_file);
unlink("$log.mail"); unlink("$log.mail");
} }
print LOG "Aborting\n";
exit 1; exit 1;
} }
@ -689,9 +715,10 @@ sub rm_all
sub kill_all sub kill_all
{ {
my ($pattern) = @_; my ($pattern) = @_;
my ($USER,$BSD,$LINUX, $pscmd, $user, $pid); my ($USER,$BSD,$LINUX, $pscmd, $user, $os, $pid);
$user=$ENV{'USER'}; $user=$ENV{'USER'};
$BSD = -f '/vmunix' || $ENV{"OS"} eq "SunOS4" || $^O eq 'darwin'; $os=defined($ENV{'OS'}) ? $ENV{'OS'} : "unknown";
$BSD = -f '/vmunix' || $os eq "SunOS4" || $^O eq 'darwin';
$LINUX = $^O eq 'linux'; $LINUX = $^O eq 'linux';
$pscmd = $BSD ? "/bin/ps -auxww" : $LINUX ? "/bin/ps axuw" : "/bin/ps -ef"; $pscmd = $BSD ? "/bin/ps -auxww" : $LINUX ? "/bin/ps axuw" : "/bin/ps -ef";
@ -707,7 +734,7 @@ sub kill_all
{ {
chop($cand); chop($cand);
($pid_user, $pid) = split(' ', $cand); ($pid_user, $pid) = split(' ', $cand);
next if $pid == $$; next if $pid eq $$;
next process if (! ($cand =~ $pattern) || $pid_user ne $user); next process if (! ($cand =~ $pattern) || $pid_user ne $user);
print LOG "Killing $_\n"; print LOG "Killing $_\n";
&killpid($pid); &killpid($pid);
@ -730,3 +757,14 @@ sub killpid
} }
print LOG "$pid will not die!\n"; print LOG "$pid will not die!\n";
} }
#
# return the current date as a string (YYYY-MM-DD HH:MM:SS)
#
sub log_timestamp
{
my @ta=localtime(time());
print LOG sprintf("%4d-%02d-%02d %02d:%02d:%02d\n",
$ta[5]+1900, $ta[4]+1, $ta[3], $ta[2], $ta[1], $ta[0]);
}

861
Docs/gis.txt Normal file
View File

@ -0,0 +1,861 @@
OpenGIS <http://www.opengis.org> support in MySQL
------------------------------------------------------------------------
Note: Blue colored lines among the text is features not implemented yet.
They are:
* Spatial Reference Systems and their IDs (SRIDs) related things:
o Functions like Length() and Area() assume planar coordinate
system.
o All objects are currently considered to be in the same
planar coordinate system.
* Function Length() on LineString and MultiLineString currently
should be called as GLength().
* No binary constructors like GeomFromWKB().
We also have to add "PostGIS compatibility" sections.
1 Introduction
MySQL implements a subset of *SQL2 with Geometry Types* environment
proposed by OpenGIS consortium's *Simple Features Specification For
SQL*. In this environment a geometry-valued column is implemented as a
column whose SQL type is drawn from the set of Geometry Types. SQL
server supports both textual and binary access to geometry.
2 OpenGIS Geometry Model in MySQL
MySQL supports the Open GIS Geometry Model based hierarcy of spatial
objects classes, which consists of:
* Geometry
o *Point*
o Curve
+ *LineString*
o Surface
+ *Polygon*
o *GeometryCollection*
+ *MultiPoint*
+ MultiCurve
# *MultiLineString*
+ MultiSurface
# *MultiPolygon*
The base *Geometry* class has subclasses for Point, Curve, Surface and
GeometryCollection.
Geometry, Curve, Surface, MultiCurve and MultiSurface are defined to be
non-instantiable classes, it is not possible to create an object of
these classes.
Point, LineString, Polygon, GeometryCollection, MultiPoint,
MultiLineString, MultiPolygon are instantiable classes (bolded on the
hierarcy tree). MySQL provides a number of functions to construct
instances of these classes.
TODO: Each spatial object is associated with a Spatial Reference System,
which describes the coordinate space in which the geometric object is
defined.
2.1 Geometry
Geometry is the root class of the hierarchy. Geometry is an abstract
(non-instantiable) class. The instantiable subclasses of Geometry
defined in this specification are restricted to 0, 1 and two-dimensional
geometric objects that exist in two-dimensional coordinate space. All
instantiable geometry classes are defined so that valid instances of a
geometry class are topologically closed (i.e. all defined geometries
include their boundary).
2.2 Point
A *Point* is a 0-dimensional geometry and represents a single location
in coordinate space. A Point in the case of 2D has a x-coordinate value
and a y-coordinate value. In the case of more dimensions, a Point has a
coordinate value for each dimension. The boundary of a Point is the
empty set.
2.3 Curve
A *Curve* is a one-dimensional geometric object usually stored as a
sequence of points, with the subclass of Curve specifying the form of
the interpolation between points. MySQL implementation defines only one
subclass of Curve, LineString, which uses linear interpolation between
points.
A Curve is simple if it does not pass through the same point twice. A
Curve is closed if its start point is equal to its end point. The
boundary of a closed Curve is empty. A Curve that is simple and closed
is a Ring. The boundary of a non-closed Curve consists of its two end
points. A Curve is defined as topologically closed.
2.4 LineString, Line, LinearRing
A LineString is a Curve with linear interpolation between points. Each
consecutive pair of points defines a line segment. A Line is a
LineString with exactly 2 points. A LinearRing is a LineString that is
both closed and simple.
2.5 Surface
A *Surface* is a two-dimensional geometric object. The OpenGIS Abstract
Specification defines a simple Surface as consisting of a single 'patch'
that is associated with one 'exterior boundary' and 0 or more 'interior'
boundaries. Simple surfaces in three-dimensional space are isomorphic to
planar surfaces. Polyhedral surfaces are formed by 'stitching' together
simple surfaces along their boundaries, polyhedral surfaces in
three-dimensional space may not be planar as a whole.
The boundary of a simple Surface is the set of closed curves
corresponding to its exterior and interior boundaries.
The only instantiable subclass of Surface defined in this specification,
Polygon, is a simple Surface that is planar.
2.6 Polygon
A Polygon is a planar Surface, defined by 1 exterior boundary and 0 or
more interior boundaries. Each interior boundary defines a hole in the
Polygon. The assertions for polygons (the rules that define valid
polygons) are:
* Polygons are topologically closed.
* The boundary of a Polygon consists of a set of LinearRings (i.e.
LineStrings which are both simple and closed) that make up its
exterior and interior boundaries.
* No two rings in the boundary cross, the rings in the boundary of a
Polygon may intersect at a Point but only as a tangent.
* A Polygon may not have cut lines, spikes or punctures.
* The Interior of every Polygon is a connected point set.
* The Exterior of a Polygon with 1 or more holes is not connected.
Each hole defines a connected component of the Exterior.
In the above assertions, Interior, Closure and Exterior have the
standard topological definitions. The combination of 1 and 3 make a
Polygon a Regular Closed point set. Polygons are simple geometries.
2.6 GeometryCollection
A *GeometryCollection* is a geometry that is a collection of 1 or more
geometries of any class. All the elements in a GeometryCollection must
be in the same Spatial Reference (i.e. in the same coordinate system).
GeometryCollection places no other constraints on its elements. However
subclasses of GeometryCollection described below may restrict membership
based on dimension and may also place other constraints on the degree of
spatial overlap between elements.
2.7 MultiPoint
A *MultiPoint* is a 0 dimensional geometric collection. The elements of
a MultiPoint are restricted to Points. The points are not connected or
ordered. A MultiPoint is simple if no two Points in the MultiPoint are
equal (have identical coordinate values). The boundary of a MultiPoint
is the empty set.
2.8 MultiCurve
A MultiCurve is a one-dimensional geometry collection whose elements are
Curves. MultiCurve is a non-instantiable class, it defines a set of
methods for its subclasses and is included for reasons of extensibility.
A MultiCurve is simple if and only if all of its elements are simple,
the only intersections between any two elements occur at points that are
on the boundaries of both elements.
The boundary of a MultiCurve is obtained by applying the "mod 2 union
rule": A point is in the boundary of a MultiCurve if it is in the
boundaries of an odd number of elements of the MultiCurve.
A MultiCurve is closed if all of its elements are closed. The boundary
of a closed MultiCurve is always empty. A MultiCurve is defined as
topologically closed.
2.9 MultiLineString
A *MultiLineString* is a MultiCurve whose elements are LineStrings.
2.10 MultiSurface
A MultiSurface is a two-dimensional geometric collection whose elements
are surfaces. The interiors of any two surfaces in a MultiSurface may
not intersect. The boundaries of any two elements in a MultiSurface may
intersect at most at a finite number of points.
MultiSurface is a non-instantiable class in this specification, it
defines a set of methods for its subclasses and is included for reasons
of extensibility. The instantiable subclass of MultiSurface is
MultiPolygon, corresponding to a collection of Polygons.
2.11 MultiPolygon
A MultiPolygon is a MultiSurface whose elements are Polygons.
The assertions for MultiPolygons are :
* The interiors of 2 Polygons that are elements of a MultiPolygon
may not intersect.
* The Boundaries of any 2 Polygons that are elements of a
MultiPolygon may not cross and may touch at only a finite number
of points. (Note that crossing is prevented by assertion 1 above).
* A MultiPolygon is defined as topologically closed.
* A MultiPolygon may not have cut lines, spikes or punctures, a
MultiPolygon is a Regular, Closed point set.
* The interior of a MultiPolygon with more than 1 Polygon is not
connected, the number of connected components of the interior of a
MultiPolygon is equal to the number of Polygons in the MultiPolygon.
The boundary of a MultiPolygon is a set of closed curves (LineStrings)
corresponding to the boundaries of its element Polygons. Each Curve in
the boundary of the MultiPolygon is in the boundary of exactly 1 element
Polygon, and every Curve in the boundary of an element Polygon is in the
boundary of the MultiPolygon.
3 Exchange of spatial data
MySQL provides binary and textual mechanismes to exchange spatial data.
Exchange is provided via so called Well Known Binary (WKB) and Well
Known Textual (WKT) representations of spatial data proposed by OpenGIS
specifications.
3.1 Well-known Text representation (WKT)
The Well-known Text (WKT) representation of Geometry is designed to
exchange geometry data in textual format.
WKT is defined below in Bechus-Naur forms:
* the notation {}* denotes 0 or more repetitions of the tokens
within the braces;
* the braces do not appear in the output token list.
The text representation of the implemented instantiable geometric types
conforms to this grammar:
<Geometry Tagged Text> :=
<Point Tagged Text>
| <LineString Tagged Text>
| <Polygon Tagged Text>
| <MultiPoint Tagged Text>
| <MultiLineString Tagged Text>
| <MultiPolygon Tagged Text>
| <GeometryCollection Tagged Text>
<Point Tagged Text> :=
POINT <Point Text>
<LineString Tagged Text> :=
LINESTRING <LineString Text>
<Polygon Tagged Text> :=
POLYGON <Polygon Text>
<MultiPoint Tagged Text> :=
MULTIPOINT <Multipoint Text>
<MultiLineString Tagged Text> :=
MULTILINESTRING <MultiLineString Text>
<MultiPolygon Tagged Text> :=
MULTIPOLYGON <MultiPolygon Text>
<GeometryCollection Tagged Text> :=
GEOMETRYCOLLECTION <GeometryCollection Text>
<Point Text> := EMPTY | ( <Point> )
<Point> := <x> <y>
<x> := double precision literal
<y> := double precision literal
<LineString Text> := EMPTY
| ( <Point > {, <Point > }* )
<Polygon Text> := EMPTY
| ( <LineString Text > {, < LineString Text > }*)
<Multipoint Text> := EMPTY
| ( <Point Text > {, <Point Text > }* )
<MultiLineString Text> := EMPTY
| ( <LineString Text > {, < LineString Text > }* )
<MultiPolygon Text> := EMPTY
| ( < Polygon Text > {, < Polygon Text > }* )
<GeometryCollection Text> := EMPTY
| ( <Geometry Tagged Text> {, <Geometry Tagged Text> }* )
WKT examples
Examples of textual representations of Geometry objects are shown below:
* |POINT(10 10)| - a Point
* |LINESTRING( 10 10, 20 20, 30 40)| - a LineString with three points
* |POLYGON((10 10, 10 20, 20 20,20 15, 10 10))| - a Polygon with one
exterior ring and 0 interior rings
* |MULTIPOINT(10 10, 20 20)| - a MultiPoint with two Points
* |MULTILINESTRING((10 10, 20 20), (15 15, 30 15))| - a
MultiLineString with two LineStrings
* |MULTIPOLYGON(((10 10, 10 20, 20 20, 20 15, 10 10)), ((60 60, 70
70, 80 60, 60 60 ) ))| - a MultiPolygon with two Polygons
* |GEOMETRYCOLLECTION( POINT (10 10),POINT (30 30), LINESTRING (15
15, 20 20))| - a GeometryCollection consisting of two Points and
one LineString
3.2 Well-known Binary representation (WKB)
Well Known Binary Representations is proposed by OpenGIS specifications
to exchange geometry data in binary format. This is WKB description:
// Basic Type definitions
// byte : 1 byte
// uint32 : 32 bit unsigned integer (4 bytes)
// double : double precision number (8 bytes)
// Building Blocks : Point, LinearRing
Point {
double [numDimentions];
};
LinearRing {
uint32 numPoints;
Point points[numPoints];
}
enum wkbGeometryType {
wkbPoint = 1,
wkbLineString = 2,
wkbPolygon = 3,
wkbMultiPoint = 4,
wkbMultiLineString = 5,
wkbMultiPolygon = 6,
wkbGeometryCollection = 7
};
enum wkbByteOrder {
wkbXDR = 0, // Big Endian
wkbNDR = 1 // Little Endian
};
WKBPoint {
byte byteOrder;
uint32 wkbType; // 1
Point point;
}
WKBLineString {
byte byteOrder;
uint32 wkbType; // 2
uint32 numPoints;
Point points[numPoints];
}
WKBPolygon {
byte byteOrder;
uint32 wkbType; // 3
uint32 numRings;
LinearRing rings[numRings];
}
WKBMultiPoint {
byte byteOrder;
uint32 wkbType; // 4
uint32 num_wkbPoints;
WKBPoint WKBPoints[num_wkbPoints];
}
WKBMultiLineString {
byte byteOrder;
uint32 wkbType; // 5
uint32 num_wkbLineStrings;
WKBLineString WKBLineStrings[num_wkbLineStrings];
}
wkbMultiPolygon {
byte byteOrder;
uint32 wkbType; // 6
uint32 num_wkbPolygons;
WKBPolygon wkbPolygons[num_wkbPolygons];
}
WKBGeometry {
union {
WKBPoint point;
WKBLineString linestring;
WKBPolygon polygon;
WKBGeometryCollection collection;
WKBMultiPoint mpoint;
WKBMultiLineString mlinestring;
WKBMultiPolygon mpolygon;
}
};
WKBGeometryCollection {
byte byte_order;
uint32 wkbType; // 7
uint32 num_wkbGeometries;
WKBGeometry wkbGeometries[num_wkbGeometries];
}
3.3 MySQL data types for spatial objects
MySQL implementation of OpenGIS provides the *GEOMETRY* data type to be
used in CREATE TABLE statements. For example, this statement creates a
table *geom* with spatial field *g*:
CREATE TABLE geom (
g Geometry;
);
A field of *GEOMETRY* type can store a spatial objects of any OpenGIS
geometry class described above.
3.4 Internal spatial data representation
Internally (in *.MYD* files) spatial objects are stored in *WKB*,
combined with object's *SRID* (a numeric ID of Spatial Reference System
object associated with). During spatial analysis, for example,
calculating the fact that one object crosses another one, only those
with the same *SRID* are accepted.
*SRID* may affect a way in which various spatial characteristics are
calculated. For example, in different coordinate systems distance
between two objects may differ even objects have the same coordinates,
like distance on plane coordinate system and distance on geocentric
(coordinates on Earth surface) systems are different things.
There is a plan to provide a number of commonly used coordinate systems
in MySQL OpenGIS implementation.
3.5 INSERTing spatial objects
Spatial data can be INSERTed using a spatial constructor. The term
*spatial constructor* is used in this manual to refer to any function
which can construct a value of GEOMETRY type, i.e. an internal MySQL
representation of spatial data.
3.5.1 Textual spatial constructors
Textual spatial constructors take a gemometry description in WKT and
built GEOMETRY value.
* |*GeomFromText(geometryTaggedText String [, SRID
Integer]):Geometry *| - constructs a Geometry value from its
well-known textual representation.
|*GeomFromText()*| function accepts a WKT of any Geometry class as
it's first argument.
For construction of Geometry values restricted to a particular
subclass, an implementation also provides a class-specific
construction function for each instantiable subtype as described
in the list below:
* |*PointFromText(pointTaggedText String [,SRID Integer]):Point *| -
constructs a Point
* |*LineFromText(lineStringTaggedText String [,SRID
Integer]):LineString *| - constructs a LineString
* |*PolyFromText(polygonTaggedText String [,SRID Integer]):Polygon
*|- constructs a Polygon
* |*MPointFromText(multiPointTaggedText String [,SRID
Integer]):MultiPoint *| - constructs a MultiPoint
* |*MLineFromText(multiLineStringTaggedText String [,SRID
Integer]):MultiLineString *| - constructs a MultiLineString
* |*MPolyFromText(multiPolygonTaggedText String [,SRID
Integer]):MultiPolygon *| - constructs a MultiPolygon
* |*GeomCollFromText(geometryCollectionTaggedText String [,SRID
Integer]):GeomCollection *| - constructs a GeometryCollection
Usage examples:
INSERT INTO geom VALUES (GeomFromText('POINT(1 1)'))
INSERT INTO geom VALUES (GeomFromText('LINESTRING(0 0,1 1,2 2)'))
INSERT INTO geom VALUES (GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))'))
INSERT INTO geom VALUES (GeomFromText('GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))'))
The second argument of spatial constructirs, described above, is
currently ignored, It will be used to specify SRID in the future.
Nowdays, it is added for reasons of compatibility with OpenGIS
specifications and PostGIS implementation.
As an optional feature, an implementation may also support building of
Polygon or MultiPolygon values given an arbitrary collection of possibly
intersecting rings or closed LineString values. Implementations that
support this feature should include the following functions:
* |*BdPolyFromText(multiLineStringTaggedText String, SRID
Integer):Polygon *| - constructs a Polygon given an arbitrary
collection of closed linestrings as a MultiLineString text
representation.
* |*BdMPolyFromText(multiLineStringTaggedText String, SRID
Integer):MultiPolygon *| - constructs a MultiPolygon given an
arbitrary collection of closed linestrings as a MultiLineString
text representation.
3.5.2 Binary spatial constructors
* |*GeomFromWKB(WKBGeometry Binary, SRID Integer):Geometry *| -
constructs a Geometry value given its well-known binary
representation.
|*GeomFromWKB()*| function can accept in it's first argument a WKB
of Geometry of any class. For construction of Geometry values
restricted to a particular subclass, an implementation also
provides a class-specific construction function for each
instantiable subclass as described in the list below:
* |*PointFromWKB(WKBPoint Binary, SRID Integer):Point - *|constructs
a Point
* |* LineFromWKB(WKBLineString Binary, SRID Integer):LineString *| -
constructs a LineString
* |* PolyFromWKB(WKBPolygon Binary, SRID Integer):Polygon *| -
constructs a Polygon
* |* MPointFromWKB(WKBMultiPoint Binary, SRID Integer):MultiPoint *|
- constructs a MultiPoint
* |* MLineFromWKB(WKBMultiLineString Binary, SRID
Integer):MultiLineString *| - constructs a MultiLineString
* |* MPolyFromWKB(WKBMultiPolygon Binary, SRID Integer):
MultiPolygon *| - constructs a MultiPolygon
* |* GeomCollFromWKB(WKBGeometryCollection Binary, SRID Integer):
GeomCollection *| - constructs a GeometryCollection
As an optional feature, an implementation may also support the uilding'
of Polygon or MultiPolygon values given an arbitrary collection of
possibly intersecting rings or closed LineString values. Implementations
that support this feature should include the following functions:
* |* BdPolyFromWKB (WKBMultiLineString Binary,SRID Integer): Polygon
*| - constructs a Polygon given an arbitrary collection of closed
linestrings as a MultiLineString binary representation.
* |*BdMPolyFromWKB(WKBMultiLineString Binary, SRID
Integer):MultiPolygon *| - constructs a MultiPolygon given an
arbitrary collection of closed linestrings as a MultiLineString
binary representation.
Inserting in *WKB* assumes that |GeomFromWKB()| function argument
contains a buffer with a correctly formed spatial object in WKB. In ODBC
applications it can be done using binding of argument. One also can
insert object in *WKB* using |mysql_escape_string()| in |libmysqlclient|
applications.
For example:
INSERT INTO geom VALUES (GeomFromWKB(buf,SRID));
where |buf| is a binary buffer with a spatial object in *WKB*
representation.
3.5 SELECTing spatial objects
Spatial objects are selected either in *WKT* or *WKB* representation by
use of AsText() and AsBinary() functions correspondently.
mysql> select AsText(g) as g from geom;
+-------------------------+
| g |
+-------------------------+
| POINT(1 1) |
| LINESTRING(0 0,1 1,2 2) |
+-------------------------+
2 rows in set (0.00 sec)
mysql>
The query:
SELECT AsBinary(g) FROM geom
returns a BLOB which contains *WKB* representation of object.
4 Functions for spatial analysis
4.1 Basic functions on Geometry
* |*AsText(g:Geometry):String*| - Exports this Geometry to a
specific well-known text representation of Geometry.
* |*AsBinary(g:Geometry):Binary*| - Exports this Geometry to a
specific well-known binary representation of Geometry.
* |*GeometryType(g:Geometry):String*| - Returns the name of the
instantiable subtype of Geometry of which this Geometry instance
is a member. The name of the instantiable subtype of Geometry is
returned as a string.
* |*Dimension(g:Geometry):Integer*| - The inherent dimension of this
Geometry object, which must be less than or equal to the
coordinate dimension. This specification is restricted to
geometries in two-dimensional coordinate space.
* |*IsEmpty(g:Geometry):Integer*| - Returns 1 (TRUE) if this
Geometry is the empty geometry . If true, then this Geometry
represents the empty point set, , for the coordinate space.
* |*IsSimple(g:Geometry):Integer *| - Returns 1 (TRUE) if this
Geometry has no anomalous geometric points, such as self
intersection or self tangency. The description of each
instantiable geometric class includes the specific conditions that
cause an instance of that class to be classified as not simple.
* |*SRID(g:Geometry):Integer*| - Returns the Spatial Reference
System ID for this Geometry.
* |*Distance(g1:Geometry,g2:Geometry):Double*| - the shortest
distance between any two points in the two geometries.
4.2 Functions for specific geometry type
GeometryCollection functions
* *NumGeometries(g:GeometryCollection ):Integer * -Returns the
number of geometries in this GeometryCollection.
* *GeometryN(g:GeometryCollection,N:integer):Geometry * -Returns the
Nth geometry in this GeometryCollection.
Point functions
* *X(p:Point):Double* -The x-coordinate value for this Point.
* *Y(p:Point):Double* -The y-coordinate value for this Point.
LineString functions
* *StartPoint(l:LineString):Point* The start point of this LineString.
* *EndPoint(l:LineString):Point* The end point of this LineString.
* *PointN(l:LineString,N:Integer):Point* Returns the specified point
N in this Linestring.
* *Length(l:LineString):Double* The length of this LineString in its
associated spatial reference.
* *IsRing(l:LineString):Integer* Returns 1 (TRUE) if this LineString
is closed (StartPoint ( ) = EndPoint ( )) and this LineString is
simple (does not pass through the same point more than once).
* *IsClosed(l:LineString):Integer* Returns 1 (TRUE) if this
LineString is closed (StartPoint ( ) = EndPoint ( )).
* *NumPoints(l:LineString):Integer* The number of points in this
LineString.
MultiLineString functions
* *Length(m:MultiLineString):Double* The Length of this
MultiLineString which is equal to the sum of the lengths of the
elements.
* *IsClosed(m:MultiLineString):Integer* Returns 1 (TRUE) if this
MultiLineString is closed (StartPoint() = EndPoint() for each
LineString in this MultiLineString)
Polygon functions
* *Area(p:Polygon):Double* The area of this Polygon, as measured in
the spatial reference system of this Polygon.
* *Centroid(p:Polygon):Point* The mathematical centroid for this
Polygon as a Point. The result is not guaranteed to be on this
Polygon.
* *PointOnSurface(p:Polygon):Point* A point guaranteed to be on this
Polygon.
* *NumInteriorRing(p:Polygon):Integer* Returns the number of
interior rings in this Polygon.
* *ExteriorRing(p:Polygon):LineString* Returns the exterior ring of
this Polygon as a LineString.
* *InteriorRingN(p:Polygon,N:Integer):LineString* Returns the Nth
interior ring for this Polygon as a LineString.
MultiPolygon functions
* *Area(m:MultuSurface):Double* The area of this MultiPolygon, as
measured in the spatial reference system of this MultiPolygon.
* *Centroid(m:MultyPolygon):Point* The mathematical centroid for
this MultiPolygon as a Point. The result is not guaranteed to be
on this MultiPolygon.
* *PointOnSurface(m:MultuPolygon):Point* A Point guaranteed to be on
this MultiPolygon.
Notes: /functions for specific geometry type retrun NULL if passed
object type is incorrect. For example Area() returns NULL if object type
is neither Polygon nor MultiPolygon/
4.3 Spatial operations (compound spatial constructors)
* |*Envelope(g:Geometry):Geometry*|The minimum bounding box for this
Geometry, returned as a Geometry. The polygon is defined by the
corner points of the bounding box
|POLYGON((MINX,MINY),(MAXX,MINY),(MAXX,MAXY),(MINX,MAXY),(MINX,MINY))|.
* |*Boundary(g:Geometry):Geometry*| - returns the closure of the
combinatorial boundary of this Geometry.
* |*Intersection(g1,g2:Geometry):Geometry*| - a geometry that
represents the point set intersection of g1 with g2.
* |*Union(g1,g2:Geometry):Geometry*| - a geometry that represents
the point set union of g1 with g2.
* |*Difference(g1,g2:Geometry):Geometry*| - a geometry that
represents the point set difference of g1 with g2.
* |*SymDifference(g1,g2:Geometry):Geometry*| - a geometry that
represents the point set symmetric difference of g1 with g2.
* |*Buffer(g:Geometry,distance:Double):Geometry*| - a geometry that
represents all points whose distance from g is less than or equal
to distance.
* |*ConvexHull(g:Geometry):Geometry*| - a geometry that represents
the convex hull of g.
4.4 Functions for testing Spatial Relations between geometric objects
* |*Equals(g1,g2)*| - Returns 1 if g1 is spatially equal to g2.
* |*Disjoint(g1,g2)*| - Returns 1 if g1 is spatially disjoint from g2.
* |*Intersects(g1,g2)*| - Returns 1 if g1 spatially intersects g2.
* |*Touches(g1,g2)*| - Returns 1 if g1 spatially touches g2.
* |*Crosses(g1,g2)*| - Returns 1 if g1 spatially crosses g2.
* |*Within(g1,g2)*| - Returns 1 if g1 is spatially within g2.
* |*Contains(g1,g2)*| - Returns 1 if g1 spatially contains g2.
* |*Overlaps(g1,g2)*| - Returns 1 if g1 spatially overlaps g2.
5 Optimizing spatial analysis
5.1 MBR
MBR is a minimal bounding rectangle (box) for spatial object. It can be
represented as a set of min and max values of each dimension.
For example:
(Xmin,Xmax,Ymin,Ymax)
5.2 Using SPATIAL indexes
To optimize spatial object relationships analysis it is possible to
create a spatial index on geometry field using R-tree algorythm. R-tree
based spatial indexes store MBRs of spatial objects as a key values.
CREATE SPATIAL INDEX gind ON geom (g);
Or together with table definition:
CREATE TABLE geom (
g GEOMETRY,
SPATIAL INDEX(g)
);
Optimizer attaches R-tree based SPATIAL index when a query with spatial
objects relationship functions is executed in WHERE clause.
For example:
SELECT geom.name FROM geom
WHERE Within(geom.g,GeomFromText('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))',SRID));
8 OpenGIS extensions implemented in MySQL
MySQL provides it's own constructors to build geometry objects:
* |*Point(double,double,SRID)*| - constructs a geometry of Point
class using it's coordinates and SRID.
* |*MultiPoint(Point,Point,...,Point)*| - constructs a MultiPoint
using Points. When any argument is not a geometry of Point class
the return value is NULL.
* |*LineString(Point,Point,...,Point)*| - constructs a LineString
from a number of Points. When any argument is not a geometry of
Point class the return value is NULL. When the number of Points is
less than two the return value is NULL.
* |*MultiLineString(LineString,LineString,...,LineString)*| -
constructs a MultiLineString using using LineStrings. When any
argument is not a geometry of LineStringClass return value is NULL.
* |*Polygon(LineString,LineString,...,LineString)*| - constructs a
Polygon from a number of LineStrings. When any argument is not a
LinearRing (i.e. not closed and simple geometry of class
LineString) the return value is NULL.
* |*MultiPolygon(Polygon,Polygon,...,Polygon)*| - constructs a
MultiPolygon from a set of Polygons. When any argument is not a
Polygon, the rerurn value is NULL.
* |*GeometryCollection(Geometry,Geometry,..,Geometry)*| - constucts
a GeometryCollection. When any argument is not a valid geometry
object of any instantiable class, the return value is NULL.
The above functions (except Point()) return NULL if arguments are not in
the same spatial reference system (i.e. have different SRIDs).
Examples:
INSERT INTO geom SELECT Point(x,y,SRID) FROM coords;
SELECT AsText(g) FROM geom WHERE
Contains(Polygon(LineString(Point(0,0),Point(0,1),Point(1,1),Point(1,0),Point(0,0)),SRID),geom.g);
9 Things that differ in MySQL implemention and OpenGIS specifications
9.1 Single GEOMETRY type
Besides a GEOMETRY type, OpenGIS consortium specifications suggest the
implementation of several spatial field types correspondent to every
instansiable object subclass. For example a *Point* type is proposed to
restrict data stored in a field of this type to only Point OpenGIS
subclass. MySQL provides an implementation of single GEOMETRY type which
doesn't restrict objects to certain OpenGIS subclass.
9.2 No additional Metadata Views
OpenGIS specifications propose several additional metadata views. For
example, a system view named GEOMETRY_COLUMNS contains a description of
geometry columns, one row for each geometry column in the database.
9.3 No functions to add/drop spatial columns
OpenGIS assumes that columns can be added/dropped using
AddGeometryColumn() and DropGeometryColumn() functions correspondently.
In MySQL implementation one should use ALTER TABLE instead.

View File

@ -96,13 +96,84 @@ cached for each user/database combination.
Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in
a @code{HEAP} table. (This is a very quick in-memory table with hash index.) a @code{HEAP} table. (This is a very quick in-memory table with hash index.)
@item Join Row Cache @item Join buffer Cache
For every full join in a @code{SELECT} statement (a full join here means For every full join in a @code{SELECT} statement (a full join here means
there were no keys that one could use to find the next table in a list), there were no keys that one could use to find the next table in a list),
the found rows are cached in a join cache. One @code{SELECT} query can the found rows are cached in a join cache. One @code{SELECT} query can
use many join caches in the worst case. use many join caches in the worst case.
@end table @end table
@node join_buffer_size, flush tables, caching, Top
@subchapter How MySQL uses the join_buffer cache
Basic information about @code{join_buffer_size}:
@itemize @bullet
@item
It's only used in the case when join type is of type @code{ALL} or
@code{index}; In other words: no possible keys can be used.
@item
A join buffer is never allocated for the first not-const table,
even it it would be of type @code{ALL}/@code{index}.
@item
The buffer is allocated when we need to do a each full join between two
tables and freed after the query is done.
@item
Accepted row combinations of tables before the @code{ALL}/@code{index}
able is stored in the cache and is used to compare against each read
row in the @code{ALL} table.
@item
We only store the used fields in the join_buffer cache, not the
whole rows.
@end itemize
Assume you have the following join:
@example
Table name Type
t1 range
t2 ref
t3 @code{ALL}
@end example
The join is then done as follows:
@example
- While rows in t1 matching range
- Read through all rows in t2 according to reference key
- Store used fields form t1,t2 in cache
- If cache is full
- Read through all rows in t3
- Compare t3 row against all t1,t2 combination in cache
- If rows satisfying join condition, send it to client
- Empty cache
- Read through all rows in t3
- Compare t3 row against all stored t1,t2 combinations in cache
- If rows satisfying join condition, send it to client
@end example
The above means that table t3 is scanned
@example
(size-of-stored-row(t1,t2) * accepted-row-cominations(t1,t2))/
join_buffer_size+1
@end example
times.
Some conclusions:
@itemize @bullet
@item
The larger the join_buff_size, the fewer scans of t3.
If @code{join_buff_size} is already large enough to hold all previous row
combinations then there is no speed to gain by making it bigger.
@item
If there is several tables of @code{ALL}/@code{index} then the we
allocate one @code{join_buffer_size buffer} for each of them and use the
same algorithm described above to handle it. (In other words, we store
the same row combination several times into different buffers)
@end itemize
@node flush tables, filesort, caching, Top @node flush tables, filesort, caching, Top
@chapter How MySQL Handles @code{FLUSH TABLES} @chapter How MySQL Handles @code{FLUSH TABLES}
@ -1585,7 +1656,7 @@ fe 00 . .
@node 4.1 protocol changes,,, @node 4.1 protocol changes,,,
@section Changes to 4.0 protocol in 4.1 @section Changes to 4.0 protocol in 4.1
All basic package handling is identical to 4.0. When communication All basic packet handling is identical to 4.0. When communication
with an old 4.0 or 3.x client we will use the old protocol. with an old 4.0 or 3.x client we will use the old protocol.
The new things that we support with 4.1 are: The new things that we support with 4.1 are:
@ -1596,7 +1667,7 @@ Warnings
@item @item
Prepared statements Prepared statements
@item @item
Binary protocol (will be much faster than the current protocol that Binary protocol (will be faster than the current protocol that
converts everything to strings) converts everything to strings)
@end itemize @end itemize
@ -1617,15 +1688,15 @@ results will sent as binary (low-byte-first).
@end itemize @end itemize
@node 4.1 field package,,, @node 4.1 field packet,,,
@section 4.1 field description package @section 4.1 field description packet
The field description package is sent as a response to a query that The field description packet is sent as a response to a query that
contains a result set. It can be distinguished from a ok package by contains a result set. It can be distinguished from a ok packet by
the fact that the first byte can't be 0 for a field package. the fact that the first byte can't be 0 for a field packet.
@xref {4.1 ok package}. @xref {4.1 ok packet}.
The header package has the following structure: The header packet has the following structure:
@multitable @columnfractions .10 .90 @multitable @columnfractions .10 .90
@item Size @tab Comment @item Size @tab Comment
@ -1634,7 +1705,7 @@ The header package has the following structure:
uses this to send the number of rows in the table) uses this to send the number of rows in the table)
@end multitable @end multitable
This package is always followed by a field description set. This packet is always followed by a field description set.
@xref{4.1 field desc}. @xref{4.1 field desc}.
@node 4.1 field desc,,, @node 4.1 field desc,,,
@ -1655,17 +1726,17 @@ The field description result set contains the meta info for a result set.
@end multitable @end multitable
@node 4.1 ok package,,, @node 4.1 ok packet,,,
@section 4.1 ok package @section 4.1 ok packet
The ok package is the first that is sent as an response for a query The ok packet is the first that is sent as an response for a query
that didn't return a result set. that didn't return a result set.
The ok package has the following structure: The ok packet has the following structure:
@multitable @columnfractions .10 .90 @multitable @columnfractions .10 .90
@item Size @tab Comment @item Size @tab Comment
@item 1 @tab 0 ; Marker for ok package @item 1 @tab 0 ; Marker for ok packet
@item 1-9 @tab Affected rows @item 1-9 @tab Affected rows
@item 1-9 @tab Last insert id (0 if one wasn't used) @item 1-9 @tab Last insert id (0 if one wasn't used)
@item 2 @tab Server status; Can be used by client to check if we are inside an transaction @item 2 @tab Server status; Can be used by client to check if we are inside an transaction
@ -1681,10 +1752,10 @@ The message is optional. For example for multi line INSERT it
contains a string for how many rows was inserted / deleted. contains a string for how many rows was inserted / deleted.
@node 4.1 end package,,, @node 4.1 end packet,,,
@section 4.1 end package @section 4.1 end packet
The end package is sent as the last package for The end packet is sent as the last packet for
@itemize @bullet @itemize @bullet
@item @item
@ -1695,41 +1766,42 @@ End of parameter type information
End of result set End of result set
@end itemize @end itemize
The end package has the following structure: The end packet has the following structure:
@multitable @columnfractions .10 .90 @multitable @columnfractions .10 .90
@item Size @tab Comment @item Size @tab Comment
@item 1 @tab 254 ; Marker for EOF package @item 1 @tab 254 ; Marker for EOF packet
@item 2 @tab Warning count @item 2 @tab Warning count
@item 2 @tab Status flags (For flags like SERVER_STATUS_MORE_RESULTS) @item 2 @tab Status flags (For flags like SERVER_STATUS_MORE_RESULTS)
@end multitable @end multitable
Note that a normal package may start with byte 254, which means Note that a normal packet may start with byte 254, which means
'length stored in 9 bytes'. One can different between these cases 'length stored in 9 bytes'. One can different between these cases
by checking the packet length < 9 bytes (in which case it's and end by checking the packet length < 9 bytes (in which case it's and end
packet). packet).
@node 4.1 error package @node 4.1 error packet
@section 4.1 error package. @section 4.1 error packet.
The error package is sent when something goes wrong. The error packet is sent when something goes wrong.
The error package has the following structure: The error packet has the following structure:
@multitable @columnfractions .10 .90 @multitable @columnfractions .10 .90
@item Size @tab Comment @item Size @tab Comment
@item 1 @tab 255 Error package marker @item 1 @tab 255 Error packet marker
@item 2 @tab Error code
@item 1-255 @tab Null terminated error message @item 1-255 @tab Null terminated error message
@end multitable @end multitable
The client/server protocol is designed in such a way that a package The client/server protocol is designed in such a way that a packet
can only start with 255 if it's an error package. can only start with 255 if it's an error packet.
@node 4.1 prep init,,, @node 4.1 prep init,,,
@section 4.1 prepared statement init package @section 4.1 prepared statement init packet
This is the return package when one sends a query with the COM_PREPARE This is the return packet when one sends a query with the COM_PREPARE
command. command.
@multitable @columnfractions .10 .90 @multitable @columnfractions .10 .90
@ -1755,8 +1827,8 @@ Note that the above is not yet in 4.1 but will be added this month.
As MySQL can have a parameter 'anywhere' it will in many cases not be As MySQL can have a parameter 'anywhere' it will in many cases not be
able to provide the optimal information for all parameters. able to provide the optimal information for all parameters.
If number of columns, in the header package, is not 0 then the If number of columns, in the header packet, is not 0 then the
prepared statement will contain a result set. In this case the package prepared statement will contain a result set. In this case the packet
is followed by a field description result set. @xref{4.1 field descr}. is followed by a field description result set. @xref{4.1 field descr}.
@ -1768,22 +1840,22 @@ value. One can call mysql_send_long_data() multiple times for the
same parameter; The server will concatenate the results to a one big same parameter; The server will concatenate the results to a one big
string. string.
The server will not require an end package for the string. The server will not require an end packet for the string.
mysql_send_long_data() is responsible updating a flag that all data mysql_send_long_data() is responsible updating a flag that all data
has been sent. (Ie; That the last call to mysql_send_long_data() has has been sent. (Ie; That the last call to mysql_send_long_data() has
the 'last_data' flag set). the 'last_data' flag set).
This package is sent from client -> server: This packet is sent from client -> server:
@multitable @columnfractions .10 .90 @multitable @columnfractions .10 .90
@item Size @tab Comment @item Size @tab Comment
@item 4 @tab Statement handler @item 4 @tab Statement handler
@item 2 @tab Parameter number @item 2 @tab Parameter number
@item 2 @tab Type of parameter (not used at this point) @item 2 @tab Type of parameter (not used at this point)
@item # @tab data (Rest of package) @item # @tab data (Rest of packet)
@end itemize @end itemize
The server will NOT send an @code{ok} or @code{error} package in The server will NOT send an @code{ok} or @code{error} packet in
responce for this. If there is any errors (like to big string), one responce for this. If there is any errors (like to big string), one
will get the error when calling execute. will get the error when calling execute.
@ -1791,13 +1863,13 @@ will get the error when calling execute.
@section 4.1 execute @section 4.1 execute
On execute we send all parameters to the server in a COM_EXECUTE On execute we send all parameters to the server in a COM_EXECUTE
package. packet.
The package contains the following information: The packet contains the following information:
@multitable @columnfractions .30 .70 @multitable @columnfractions .30 .70
@item Size @tab Comment @item Size @tab Comment
@item (param_count+7)/8 @tab Null bit map @item (param_count+9)/8 @tab Null bit map (2 bits reserved for protocol)
@item 1 @tab new_parameter_bound flag. Is set to 1 for first @item 1 @tab new_parameter_bound flag. Is set to 1 for first
execute or if one has rebound the parameters. execute or if one has rebound the parameters.
@item 2*param_count @tab Type of parameters (only given if new_parameter_bound flag is 1) @item 2*param_count @tab Type of parameters (only given if new_parameter_bound flag is 1)
@ -1813,7 +1885,7 @@ The parameters are stored the following ways:
@multitable @columnfractions .20 .10 .70 @multitable @columnfractions .20 .10 .70
@item Type @tab Size @tab Comment @item Type @tab Size @tab Comment
@item tynyint @tab 1 @tab One byte integer @item tinyint @tab 1 @tab One byte integer
@item short @tab 2 @tab @item short @tab 2 @tab
@item int @tab 4 @tab @item int @tab 4 @tab
@item longlong @tab 8 @tab @item longlong @tab 8 @tab
@ -1822,7 +1894,7 @@ The parameters are stored the following ways:
@item string @tab 1-9 + # @tab Packed string length + string @item string @tab 1-9 + # @tab Packed string length + string
@end multitable @end multitable
The result for this will be either an ok package or a binary result The result for this will be either an ok packet or a binary result
set. set.
@node 4.1 binary result,,, @node 4.1 binary result,,,
@ -1836,11 +1908,11 @@ For each result row:
@item @item
null bit map with first two bits set to 01 (bit 0,1 value 1) null bit map with first two bits set to 01 (bit 0,1 value 1)
@item @item
parameter data, repeated for each not null parameter. parameter data, repeated for each not null result column.
@end itemize @end itemize
The idea with the reserving two bits in the null map is that we can The idea with the reserving two bits in the null map is that we can
use standard error (first byte 255) and ok packages (first byte 0) use standard error (first byte 255) and ok packets (first byte 0)
to end a result sets. to end a result sets.
Except that the null-bit-map is shifted two steps, the server is Except that the null-bit-map is shifted two steps, the server is
@ -1849,6 +1921,18 @@ bound parameters to the client. The server is always sending the data
as type given for 'column type' for respective column. It's up to the as type given for 'column type' for respective column. It's up to the
client to convert the parameter to the requested type. client to convert the parameter to the requested type.
DATETIME, DATE and TIME are sent to the server in a binary format as follows:
@multitable @columnfractions .20 .10 .70
@item Type @tab Size @tab Comment
@item date @tab 1 + 0-11 @tab Length + 2 byte year, 1 byte MMDDHHMMSS, 4 byte billionth of a second
@item datetime @tab 1 + 0-11 @tab Length + 2 byte year, 1 byte MMDDHHMMSS, 4 byte billionth of a second
@item time @tab 1 + 0-14 @tab Length + sign (0 = pos, 1= neg), 4 byte days, 1 byte HHMMDD, 4 byte billionth of a second
@end multitable
The first byte is a length byte and then comes all parameters that are
not 0. (Always counted from the beginning).
@node Fulltext Search, , protocol, Top @node Fulltext Search, , protocol, Top
@chapter Fulltext Search in MySQL @chapter Fulltext Search in MySQL

View File

@ -300,7 +300,7 @@
#define ER_NOT_ALLOWED_COMMAND 1148 #define ER_NOT_ALLOWED_COMMAND 1148
"The used command is not allowed with this MySQL version", "The used command is not allowed with this MySQL version",
#define ER_SYNTAX_ERROR 1149 #define ER_SYNTAX_ERROR 1149
"You have an error in your SQL syntax", "You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use",
#define ER_DELAYED_CANT_CHANGE_LOCK 1150 #define ER_DELAYED_CANT_CHANGE_LOCK 1150
"Delayed insert thread couldn't get requested lock for table %-.64s", "Delayed insert thread couldn't get requested lock for table %-.64s",
#define ER_TOO_MANY_DELAYED_THREADS 1151 #define ER_TOO_MANY_DELAYED_THREADS 1151
@ -358,7 +358,7 @@
#define ER_CHECK_NO_SUCH_TABLE 1177 #define ER_CHECK_NO_SUCH_TABLE 1177
"Can't open table", "Can't open table",
#define ER_CHECK_NOT_IMPLEMENTED 1178 #define ER_CHECK_NOT_IMPLEMENTED 1178
"The handler for the table doesn't support check/repair", "The handler for the table doesn't support %s",
#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 #define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179
"You are not allowed to execute this command in a transaction", "You are not allowed to execute this command in a transaction",
#define ER_ERROR_DURING_COMMIT 1180 #define ER_ERROR_DURING_COMMIT 1180
@ -454,4 +454,24 @@
#define ER_DUP_ARGUMENT 1225 #define ER_DUP_ARGUMENT 1225
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
#define ER_USER_LIMIT_REACHED 1226 #define ER_USER_LIMIT_REACHED 1226
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
#define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227
"Access denied. You need the %-.128s privilege for this operation",
#define ER_LOCAL_VARIABLE 1228
"Variable '%-.64s' is a LOCAL variable and can't be used with SET GLOBAL",
#define ER_GLOBAL_VARIABLE 1229
"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
#define ER_NO_DEFAULT 1230
"Variable '%-.64s' doesn't have a default value",
#define ER_WRONG_VALUE_FOR_VAR 1231
"Variable '%-.64s' can't be set to the value of '%-.64s'",
#define ER_WRONG_TYPE_FOR_VAR 1232
"Wrong argument type to variable '%-.64s'",
#define ER_VAR_CANT_BE_READ 1233
"Variable '%-.64s' can only be set, not read",
#define ER_CANT_USE_OPTION_HERE 1234
"Wrong usage/placement of '%s'",
#define 1235
"This version of MySQL doesn't yet support '%s'",
#define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236
"Got fatal error %d: '%-.128s' from master when reading data from binary log",

1422
Docs/prepare.texi Executable file

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,8 @@ RSC=rc.exe
# PROP Intermediate_Dir "debug" # PROP Intermediate_Dir "debug"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /YX /FD /c # ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /G6 /MTd /W3 /GX /Z7 /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c # ADD CPP /nologo /G6 /MTd /W3 /GX /Z7 /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "__NT__" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD BASE RSC /l 0x416 /d "NDEBUG"
# ADD RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -66,7 +67,8 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "release" # PROP Intermediate_Dir "release"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c # ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c
# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c # ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD BASE RSC /l 0x416 /d "NDEBUG"
# ADD RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -89,7 +91,8 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "innobase___Win32_nt" # PROP Intermediate_Dir "innobase___Win32_nt"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c # ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c
# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c # ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD BASE RSC /l 0x416 /d "NDEBUG"
# ADD RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -112,7 +115,8 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "innobase___Win32_Max_nt" # PROP Intermediate_Dir "innobase___Win32_Max_nt"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c # ADD BASE CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c
# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /YX /FD /c # ADD CPP /nologo /G6 /MT /W3 /GX /O2 /I "../innobase/include" /I "../include" /D "NDEBUG" /D "_LIB" /D "_WIN32" /D "WIN32" /D "_MBCS" /D "MYSQL_SERVER" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD BASE RSC /l 0x416 /d "NDEBUG"
# ADD RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe

View File

@ -122,6 +122,10 @@ SOURCE=.\myrg_queue.c
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\myrg_range.c
# End Source File
# Begin Source File
SOURCE=.\myrg_rfirst.c SOURCE=.\myrg_rfirst.c
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -42,7 +42,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../" /I "../client" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c # ADD CPP /nologo /G6 /MT /W3 /O2 /I "../include" /I "../" /I "../sql" /D "NDEBUG" /D "DBUG_OFF" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -67,7 +67,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0 # PROP Ignore_Export_Lib 0
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../" /I "../client" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c # ADD CPP /nologo /G6 /MTd /W3 /Gm /ZI /Od /I "../include" /I "../" /I "../sql" /D "_DEBUG" /D "SAFEMALLOC" /D "SAFE_MUTEX" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "MYSQL_SERVER" /FD /c
# ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -88,7 +88,7 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File # Begin Source File
SOURCE=.\mysqlbinlog.cpp SOURCE=..\client\mysqlbinlog.cpp
# End Source File # End Source File
# End Group # End Group
# Begin Group "Header Files" # Begin Group "Header Files"

View File

@ -41,7 +41,8 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release" # PROP Intermediate_Dir "Release"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /YX /FD /c # ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "__WIN__" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD BASE RSC /l 0x416 /d "NDEBUG"
# ADD RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -64,7 +65,8 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "Debug" # PROP Intermediate_Dir "Debug"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /Zi /Od /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /D "__WIN__" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /Zi /Od /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "MYSQL_SERVER" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /D "__WIN__" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x416 /d "_DEBUG" # ADD BASE RSC /l 0x416 /d "_DEBUG"
# ADD RSC /l 0x416 /d "_DEBUG" # ADD RSC /l 0x416 /d "_DEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe

View File

@ -41,7 +41,7 @@ RSC=rc.exe
# PROP Intermediate_Dir "Release" # PROP Intermediate_Dir "Release"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /D "MYSQL_SERVER" /D "__WIN__" /YX /FD /c # ADD CPP /nologo /MT /W3 /O2 /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_BERKELEY_DB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "DBUG_OFF" /D "USE_TLS" /YX /FD /c
# ADD BASE RSC /l 0x416 /d "NDEBUG" # ADD BASE RSC /l 0x416 /d "NDEBUG"
# ADD RSC /l 0x416 /d "NDEBUG" # ADD RSC /l 0x416 /d "NDEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -64,7 +64,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir "Debug" # PROP Intermediate_Dir "Debug"
# PROP Target_Dir "" # PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /Zi /Od /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /Zi /Od /I "../include" /I "../regex" /I "../sql" /I "../bdb/build_win32" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "HAVE_BERKELEY_DB" /D "USE_SYMDIR" /D "SIGNAL_WITH_VIO_CLOSE" /D "HAVE_DLOPEN" /D "EMBEDDED_LIBRARY" /D "HAVE_INNOBASE_DB" /D "USE_TLS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x416 /d "_DEBUG" # ADD BASE RSC /l 0x416 /d "_DEBUG"
# ADD RSC /l 0x416 /d "_DEBUG" # ADD RSC /l 0x416 /d "_DEBUG"
BSC32=bscmake.exe BSC32=bscmake.exe
@ -80,13 +80,5 @@ LIB32=link.exe -lib
# Name "mysqlserver - Win32 Release" # Name "mysqlserver - Win32 Release"
# Name "mysqlserver - Win32 Debug" # Name "mysqlserver - Win32 Debug"
# Begin Source File
SOURCE=..\sql\set_var.cpp
# End Source File
# Begin Source File
SOURCE=..\sql\sql_load.cpp
# End Source File
# End Target # End Target
# End Project # End Project

View File

@ -218,7 +218,7 @@ SOURCE=.\derror.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\client\errmsg.c SOURCE=..\libmysql\errmsg.c
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -623,7 +623,7 @@ main()
FILE *file=fopen("conftestval", "w"); FILE *file=fopen("conftestval", "w");
f = (float) ll; f = (float) ll;
fprintf(file,"%g\n",f); fprintf(file,"%g\n",f);
close(file); fclose(file);
exit (0); exit (0);
}], ac_cv_conv_longlong_to_float=`cat conftestval`, ac_cv_conv_longlong_to_float=0, ifelse([$2], , , ac_cv_conv_longlong_to_float=$2))])dnl }], ac_cv_conv_longlong_to_float=`cat conftestval`, ac_cv_conv_longlong_to_float=0, ifelse([$2], , , ac_cv_conv_longlong_to_float=$2))])dnl
if test "$ac_cv_conv_longlong_to_float" = "1" -o "$ac_cv_conv_longlong_to_float" = "yes" if test "$ac_cv_conv_longlong_to_float" = "1" -o "$ac_cv_conv_longlong_to_float" = "yes"
@ -1215,7 +1215,9 @@ changequote(, )dnl
hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*) hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
changequote([, ])dnl changequote([, ])dnl
if test "$GCC" = yes; then if test "$GCC" = yes; then
ac_cv_sys_largefile_CFLAGS=-D__STDC_EXT__ case `$CC --version 2>/dev/null` in
2.95.*) ac_cv_sys_largefile_CFLAGS=-D__STDC_EXT__ ;;
esac
fi fi
;; ;;
# IRIX 6.2 and later require cc -n32. # IRIX 6.2 and later require cc -n32.
@ -1330,7 +1332,7 @@ AC_DEFUN(MYSQL_SYS_LARGEFILE,
# Local version of _AC_PROG_CXX_EXIT_DECLARATION that does not # Local version of _AC_PROG_CXX_EXIT_DECLARATION that does not
# include #stdlib.h as this breaks things on Solaris # include #stdlib.h as default as this breaks things on Solaris
# (Conflicts with pthreads and big file handling) # (Conflicts with pthreads and big file handling)
m4_define([_AC_PROG_CXX_EXIT_DECLARATION], m4_define([_AC_PROG_CXX_EXIT_DECLARATION],
@ -1340,7 +1342,8 @@ m4_define([_AC_PROG_CXX_EXIT_DECLARATION],
'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \
'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int) throw ();' \
'extern "C" void exit (int);' \ 'extern "C" void exit (int);' \
'void exit (int);' 'void exit (int);' \
'#include <stdlib.h>'
do do
_AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include <stdlib.h> _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include <stdlib.h>
$ac_declaration], $ac_declaration],

View File

@ -536,11 +536,9 @@ swap_retry:
* and even a checksum error isn't a reason to panic the environment. * and even a checksum error isn't a reason to panic the environment.
*/ */
if ((ret = __db_chk_meta(dbenv, dbp, meta, do_metachk)) != 0) { if ((ret = __db_chk_meta(dbenv, dbp, meta, do_metachk)) != 0) {
if (ret == -1) { if (ret == -1)
__db_err(dbenv, __db_err(dbenv,
"%s: metadata page checksum error", name); "%s: metadata page checksum error", name);
ret = EINVAL;
}
goto bad_format; goto bad_format;
} }
@ -577,7 +575,7 @@ swap_retry:
bad_format: bad_format:
__db_err(dbenv, "%s: unexpected file type or format", name); __db_err(dbenv, "%s: unexpected file type or format", name);
return (ret); return (ret == 0 ? EINVAL : ret);
} }
/* /*

View File

@ -268,6 +268,8 @@ __log_txn_lsn(dbenv, lsnp, mbytesp, bytesp)
if (mbytesp != NULL) { if (mbytesp != NULL) {
*mbytesp = lp->stat.st_wc_mbytes; *mbytesp = lp->stat.st_wc_mbytes;
*bytesp = (u_int32_t)(lp->stat.st_wc_bytes + lp->b_off); *bytesp = (u_int32_t)(lp->stat.st_wc_bytes + lp->b_off);
lp->stat.st_wc_mbytes = lp->stat.st_wc_bytes = 0;
} }
R_UNLOCK(dbenv, &dblp->reginfo); R_UNLOCK(dbenv, &dblp->reginfo);

View File

@ -344,6 +344,23 @@ __memp_fopen_int(dbmfp, mfp, path, flags, mode, pagesize)
goto err; goto err;
} }
/*
* Figure out the file's size.
*
* !!!
* We can't use off_t's here, or in any code in the mainline library
* for that matter. (We have to use them in the os stubs, of course,
* as there are system calls that take them as arguments.) The reason
* is some customers build in environments where an off_t is 32-bits,
* but still run where offsets are 64-bits, and they pay us a lot of
* money.
*/
if ((ret = __os_ioinfo(
dbenv, rpath, dbmfp->fhp, &mbytes, &bytes, NULL)) != 0) {
__db_err(dbenv, "%s: %s", rpath, db_strerror(ret));
goto err;
}
/* /*
* Get the file id if we weren't given one. Generated file id's * Get the file id if we weren't given one. Generated file id's
* don't use timestamps, otherwise there'd be no chance of any * don't use timestamps, otherwise there'd be no chance of any
@ -470,6 +487,7 @@ alloc: /* Allocate and initialize a new MPOOLFILE. */
F_SET(mfp, MP_DIRECT); F_SET(mfp, MP_DIRECT);
if (LF_ISSET(DB_EXTENT)) if (LF_ISSET(DB_EXTENT))
F_SET(mfp, MP_EXTENT); F_SET(mfp, MP_EXTENT);
F_SET(mfp, MP_CAN_MMAP);
if (path == NULL) if (path == NULL)
F_SET(mfp, MP_TEMP); F_SET(mfp, MP_TEMP);
@ -479,21 +497,6 @@ alloc: /* Allocate and initialize a new MPOOLFILE. */
* and find the number of the last page in the file, all the * and find the number of the last page in the file, all the
* time being careful not to overflow 32 bits. * time being careful not to overflow 32 bits.
* *
* !!!
* We can't use off_t's here, or in any code in the mainline
* library for that matter. (We have to use them in the os
* stubs, of course, as there are system calls that take them
* as arguments.) The reason is that some customers build in
* environments where an off_t is 32-bits, but still run where
* offsets are 64-bits, and they pay us a lot of money.
*/
if ((ret = __os_ioinfo(
dbenv, rpath, dbmfp->fhp, &mbytes, &bytes, NULL)) != 0) {
__db_err(dbenv, "%s: %s", rpath, db_strerror(ret));
goto err;
}
/*
* During verify or recovery, we might have to cope with a * During verify or recovery, we might have to cope with a
* truncated file; if the file size is not a multiple of the * truncated file; if the file size is not a multiple of the
* page size, round down to a page, we'll take care of the * page size, round down to a page, we'll take care of the
@ -582,7 +585,7 @@ check_map:
* compiler will perpetrate, doing the comparison in a portable way is * compiler will perpetrate, doing the comparison in a portable way is
* flatly impossible. Hope that mmap fails if the file is too large. * flatly impossible. Hope that mmap fails if the file is too large.
*/ */
#define DB_MAXMMAPSIZE (10 * 1024 * 1024) /* 10 Mb. */ #define DB_MAXMMAPSIZE (10 * 1024 * 1024) /* 10 MB. */
if (F_ISSET(mfp, MP_CAN_MMAP)) { if (F_ISSET(mfp, MP_CAN_MMAP)) {
if (path == NULL) if (path == NULL)
F_CLR(mfp, MP_CAN_MMAP); F_CLR(mfp, MP_CAN_MMAP);

View File

@ -1198,6 +1198,9 @@ gap_check: lp->wait_recs = 0;
* replica get flushed now and again. * replica get flushed now and again.
*/ */
ret = dbenv->log_flush(dbenv, &ckp_lsn); ret = dbenv->log_flush(dbenv, &ckp_lsn);
/* Update the last_ckp in the txn region. */
if (ret == 0)
__txn_updateckp(dbenv, &rp->lsn);
break; break;
case DB___txn_regop: case DB___txn_regop:
if (!F_ISSET(dbenv, DB_ENV_REP_LOGSONLY)) if (!F_ISSET(dbenv, DB_ENV_REP_LOGSONLY))

View File

@ -1209,18 +1209,7 @@ do_ckp: /* Look through the active transactions for the lowest begin LSN. */
return (ret); return (ret);
} }
/* __txn_updateckp(dbenv, &ckp_lsn);
* We want to make sure last_ckp only moves forward; since
* we drop locks above and in log_put, it's possible
* for two calls to __txn_ckp_log to finish in a different
* order from how they were called.
*/
R_LOCK(dbenv, &mgr->reginfo);
if (log_compare(&region->last_ckp, &ckp_lsn) < 0) {
region->last_ckp = ckp_lsn;
(void)time(&region->time_ckp);
}
R_UNLOCK(dbenv, &mgr->reginfo);
} }
return (0); return (0);
} }
@ -1404,3 +1393,36 @@ __txn_reset(dbenv)
return (__txn_recycle_log(dbenv, return (__txn_recycle_log(dbenv,
NULL, &scrap, 0, TXN_MINIMUM, TXN_MAXIMUM)); NULL, &scrap, 0, TXN_MINIMUM, TXN_MAXIMUM));
} }
/*
* __txn_updateckp --
* Update the last_ckp field in the transaction region. This happens
* at the end of a normal checkpoint and also when a replication client
* receives a checkpoint record.
*
* PUBLIC: void __txn_updateckp __P((DB_ENV *, DB_LSN *));
*/
void
__txn_updateckp(dbenv, lsnp)
DB_ENV *dbenv;
DB_LSN *lsnp;
{
DB_TXNMGR *mgr;
DB_TXNREGION *region;
mgr = dbenv->tx_handle;
region = mgr->reginfo.primary;
/*
* We want to make sure last_ckp only moves forward; since
* we drop locks above and in log_put, it's possible
* for two calls to __txn_ckp_log to finish in a different
* order from how they were called.
*/
R_LOCK(dbenv, &mgr->reginfo);
if (log_compare(&region->last_ckp, lsnp) < 0) {
region->last_ckp = *lsnp;
(void)time(&region->time_ckp);
}
R_UNLOCK(dbenv, &mgr->reginfo);
}

View File

@ -40,7 +40,7 @@
#include <signal.h> #include <signal.h>
#include <violite.h> #include <violite.h>
const char *VER= "13.1"; const char *VER= "13.3";
/* Don't try to make a nice table if the data is too big */ /* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024 #define MAX_COLUMN_LENGTH 1024
@ -195,7 +195,7 @@ static void end_pager();
static int init_tee(char *); static int init_tee(char *);
static void end_tee(); static void end_tee();
static const char* construct_prompt(); static const char* construct_prompt();
static char *get_arg(char *line); static char *get_arg(char *line, my_bool get_next_arg);
static void init_username(); static void init_username();
static void add_int_to_prompt(int toadd); static void add_int_to_prompt(int toadd);
@ -280,7 +280,8 @@ static void initialize_readline (char *name);
#endif #endif
static COMMANDS *find_command (char *name,char cmd_name); static COMMANDS *find_command (char *name,char cmd_name);
static bool add_line(String &buffer,char *line,char *in_string); static bool add_line(String &buffer,char *line,char *in_string,
bool *ml_comment);
static void remove_cntrl(String &buffer); static void remove_cntrl(String &buffer);
static void print_table_data(MYSQL_RES *result); static void print_table_data(MYSQL_RES *result);
static void print_table_data_html(MYSQL_RES *result); static void print_table_data_html(MYSQL_RES *result);
@ -388,9 +389,11 @@ int main(int argc,char *argv[])
} }
} }
#endif #endif
sprintf(buff, "%s%s", sprintf(buff, "%s",
"Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n", "Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n");
#ifdef NOT_YET
"Type 'help [[%]function name[%]]' to get help on usage of function.\n"); "Type 'help [[%]function name[%]]' to get help on usage of function.\n");
#endif
put_info(buff,INFO_INFO); put_info(buff,INFO_INFO);
status.exit_status=read_lines(1); // read lines and execute them status.exit_status=read_lines(1); // read lines and execute them
if (opt_outfile) if (opt_outfile)
@ -662,7 +665,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_nopager= 1; opt_nopager= 1;
case OPT_MYSQL_PROTOCOL: case OPT_MYSQL_PROTOCOL:
{ {
if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) == ~(ulong) 0) if ((opt_protocol = find_type(argument, &sql_protocol_typelib,0)) ==
~(ulong) 0)
{ {
fprintf(stderr, "Unknown option to protocol: %s\n", argument); fprintf(stderr, "Unknown option to protocol: %s\n", argument);
exit(1); exit(1);
@ -805,6 +809,7 @@ static int read_lines(bool execute_commands)
char *line; char *line;
char in_string=0; char in_string=0;
ulong line_number=0; ulong line_number=0;
bool ml_comment= 0;
COMMANDS *com; COMMANDS *com;
status.exit_status=1; status.exit_status=1;
@ -873,7 +878,7 @@ static int read_lines(bool execute_commands)
#endif #endif
continue; continue;
} }
if (add_line(glob_buffer,line,&in_string)) if (add_line(glob_buffer,line,&in_string,&ml_comment))
break; break;
} }
/* if in batch mode, send last query even if it doesn't end with \g or go */ /* if in batch mode, send last query even if it doesn't end with \g or go */
@ -934,7 +939,8 @@ static COMMANDS *find_command (char *name,char cmd_char)
} }
static bool add_line(String &buffer,char *line,char *in_string) static bool add_line(String &buffer,char *line,char *in_string,
bool *ml_comment)
{ {
uchar inchar; uchar inchar;
char buff[80],*pos,*out; char buff[80],*pos,*out;
@ -965,7 +971,7 @@ static bool add_line(String &buffer,char *line,char *in_string)
continue; continue;
} }
#endif #endif
if (inchar == '\\') if (!*ml_comment && inchar == '\\')
{ // mSQL or postgreSQL style command ? { // mSQL or postgreSQL style command ?
if (!(inchar = (uchar) *++pos)) if (!(inchar = (uchar) *++pos))
break; // readline adds one '\' break; // readline adds one '\'
@ -999,7 +1005,7 @@ static bool add_line(String &buffer,char *line,char *in_string)
continue; continue;
} }
} }
else if (inchar == ';' && !*in_string) else if (!*ml_comment && inchar == ';' && !*in_string)
{ // ';' is end of command { // ';' is end of command
if (out != line) if (out != line)
buffer.append(line,(uint) (out-line)); // Add this line buffer.append(line,(uint) (out-line)); // Add this line
@ -1019,16 +1025,32 @@ static bool add_line(String &buffer,char *line,char *in_string)
buffer.length(0); buffer.length(0);
out=line; out=line;
} }
else if (!*in_string && (inchar == '#' || else if (!*ml_comment && (!*in_string && (inchar == '#' ||
inchar == '-' && pos[1] == '-' && inchar == '-' && pos[1] == '-' &&
my_isspace(system_charset_info,pos[2]))) my_isspace(system_charset_info,pos[2]))))
break; // comment to end of line break; // comment to end of line
else if (!*in_string && inchar == '/' && *(pos+1) == '*')
{
pos++;
*ml_comment= 1;
if (out != line)
{
buffer.append(line,(uint) (out-line));
out=line;
}
}
else if (*ml_comment && !*in_string && inchar == '*' && *(pos+1) == '/')
{
pos++;
*ml_comment= 0;
}
else else
{ // Add found char to buffer { // Add found char to buffer
if (inchar == *in_string) if (inchar == *in_string)
*in_string=0; *in_string=0;
else if (!*in_string && (inchar == '\'' || inchar == '"')) else if (!*in_string && (inchar == '\'' || inchar == '"'))
*in_string=(char) inchar; *in_string=(char) inchar;
if (!(*ml_comment))
*out++ = (char) inchar; *out++ = (char) inchar;
} }
} }
@ -1038,7 +1060,7 @@ static bool add_line(String &buffer,char *line,char *in_string)
uint length=(uint) (out-line); uint length=(uint) (out-line);
if (buffer.length() + length >= buffer.alloced_length()) if (buffer.length() + length >= buffer.alloced_length())
buffer.realloc(buffer.length()+length+IO_SIZE); buffer.realloc(buffer.length()+length+IO_SIZE);
if (buffer.append(line,length)) if (!(*ml_comment) && buffer.append(line,length))
return 1; return 1;
} }
return 0; return 0;
@ -1388,18 +1410,15 @@ static int com_server_help(String *buffer __attribute__((unused)),
MYSQL_ROW cur; MYSQL_ROW cur;
const char *server_cmd= buffer->ptr(); const char *server_cmd= buffer->ptr();
char cmd_buf[100]; char cmd_buf[100];
MYSQL_RES *result;
int error;
if (help_arg[0] != '\'') if (help_arg[0] != '\'')
{ {
(void*)sprintf(cmd_buf,"help \'%s\';",help_arg); (void) strxnmov(cmd_buf, sizeof(cmd_buf), "help '", help_arg, "'", NullS);
server_cmd= cmd_buf; server_cmd= cmd_buf;
} }
char buff[16], time_buf[32];
MYSQL_RES *result;
ulong timer;
uint error= 0;
if (!status.batch) if (!status.batch)
{ {
old_buffer= *buffer; old_buffer= *buffer;
@ -1409,14 +1428,9 @@ static int com_server_help(String *buffer __attribute__((unused)),
if (!connected && reconnect()) if (!connected && reconnect())
return 1; return 1;
timer= start_timer(); if ((error= mysql_real_query_for_lazy(server_cmd,strlen(server_cmd))))
error= mysql_real_query_for_lazy(server_cmd,strlen(server_cmd));
if (error)
return error; return error;
if ((error= mysql_store_result_for_lazy(&result)))
error= mysql_store_result_for_lazy(&result);
if (error)
return error; return error;
if (result) if (result)
@ -1425,7 +1439,10 @@ static int com_server_help(String *buffer __attribute__((unused)),
if (num_rows == 1) if (num_rows == 1)
{ {
if (!(cur= mysql_fetch_row(result))) if (!(cur= mysql_fetch_row(result)))
return -1; {
error= -1;
goto err;
}
init_pager(); init_pager();
if (cur[1][0] == 'Y') if (cur[1][0] == 'Y')
@ -1449,8 +1466,10 @@ static int com_server_help(String *buffer __attribute__((unused)),
init_pager(); init_pager();
char last_char= '_'; char last_char= '_';
while ((cur= mysql_fetch_row(result))){ while ((cur= mysql_fetch_row(result)))
if (cur[1][0]!=last_char){ {
if (cur[1][0]!=last_char)
{
put_info("-------------------------------------------", INFO_INFO); put_info("-------------------------------------------", INFO_INFO);
put_info(cur[1][0] == 'Y' ? put_info(cur[1][0] == 'Y' ?
"categories:" : "functions:", INFO_INFO); "categories:" : "functions:", INFO_INFO);
@ -1468,6 +1487,7 @@ static int com_server_help(String *buffer __attribute__((unused)),
} }
} }
err:
mysql_free_result(result); mysql_free_result(result);
return error; return error;
} }
@ -2216,19 +2236,17 @@ com_connect(String *buffer, char *line)
bool save_rehash= rehash; bool save_rehash= rehash;
int error; int error;
bzero(buff, sizeof(buff));
if (buffer) if (buffer)
{ {
while (my_isspace(system_charset_info,*line)) strmov(buff, line);
line++; tmp= get_arg(buff, 0);
strnmov(buff,line,sizeof(buff)-1); // Don't destroy history if (tmp && *tmp)
if (buff[0] == '\\') // Short command
buff[1]=' ';
tmp=(char *) strtok(buff," \t"); // Skip connect command
if (tmp && (tmp=(char *) strtok(NullS," \t;")))
{ {
my_free(current_db, MYF(MY_ALLOW_ZERO_PTR)); my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
current_db= my_strdup(tmp, MYF(MY_WME)); current_db= my_strdup(tmp, MYF(MY_WME));
if ((tmp=(char *) strtok(NullS," \t;"))) tmp= get_arg(buff, 1);
if (tmp)
{ {
my_free(current_host,MYF(MY_ALLOW_ZERO_PTR)); my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
current_host=my_strdup(tmp,MYF(MY_WME)); current_host=my_strdup(tmp,MYF(MY_WME));
@ -2314,8 +2332,9 @@ com_use(String *buffer __attribute__((unused)), char *line)
char *tmp; char *tmp;
char buff[256]; char buff[256];
bzero(buff, sizeof(buff));
strmov(buff, line); strmov(buff, line);
tmp= get_arg(buff); tmp= get_arg(buff, 0);
if (!tmp || !*tmp) if (!tmp || !*tmp)
{ {
put_info("USE must be followed by a database name", INFO_ERROR); put_info("USE must be followed by a database name", INFO_ERROR);
@ -2357,9 +2376,20 @@ com_use(String *buffer __attribute__((unused)), char *line)
} }
/*
Gets argument from a command on the command line. If get_next_arg is
not defined, skips the command and returns the first argument. The
line is modified by adding zero to the end of the argument. If
get_next_arg is defined, then the function searches for end of string
first, after found, returns the next argument and adds zero to the
end. If you ever wish to use this feature, remember to initialize all
items in the array to zero first.
*/
enum quote_type { NO_QUOTE, SQUOTE, DQUOTE, BTICK }; enum quote_type { NO_QUOTE, SQUOTE, DQUOTE, BTICK };
char *get_arg(char *line) char *get_arg(char *line, my_bool get_next_arg)
{ {
char *ptr; char *ptr;
my_bool quoted= 0, valid_arg= 0; my_bool quoted= 0, valid_arg= 0;
@ -2367,6 +2397,14 @@ char *get_arg(char *line)
enum quote_type qtype= NO_QUOTE; enum quote_type qtype= NO_QUOTE;
ptr= line; ptr= line;
if (get_next_arg)
{
for (; ptr && *ptr; ptr++);
if ((ptr + 1) && *(ptr + 1))
ptr++;
}
else
{
/* skip leading white spaces */ /* skip leading white spaces */
while (my_isspace(system_charset_info, *ptr)) while (my_isspace(system_charset_info, *ptr))
ptr++; ptr++;
@ -2374,6 +2412,7 @@ char *get_arg(char *line)
ptr+= 2; ptr+= 2;
while (!my_isspace(system_charset_info, *ptr)) // skip command while (!my_isspace(system_charset_info, *ptr)) // skip command
ptr++; ptr++;
}
while (my_isspace(system_charset_info, *ptr)) while (my_isspace(system_charset_info, *ptr))
ptr++; ptr++;
if ((*ptr == '\'' && (qtype= SQUOTE)) || if ((*ptr == '\'' && (qtype= SQUOTE)) ||
@ -2396,9 +2435,8 @@ char *get_arg(char *line)
ptr= line; ptr= line;
ptr+= count; ptr+= count;
} }
else if (!quoted && *ptr == ' ') else if ((!quoted && *ptr == ' ') ||
*(ptr + 1) = 0; (*ptr == '\'' && qtype == SQUOTE) ||
else if ((*ptr == '\'' && qtype == SQUOTE) ||
(*ptr == '\"' && qtype == DQUOTE) || (*ptr == '\"' && qtype == DQUOTE) ||
(*ptr == '`' && qtype == BTICK)) (*ptr == '`' && qtype == BTICK))
{ {

View File

@ -25,7 +25,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <mysql.h> #include <mysql.h>
#define ADMIN_VERSION "8.38" #define ADMIN_VERSION "8.39"
#define MAX_MYSQL_VAR 128 #define MAX_MYSQL_VAR 128
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */ #define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
#define MAX_TRUNC_LENGTH 3 #define MAX_TRUNC_LENGTH 3
@ -76,7 +76,7 @@ static void print_relative_header();
static void print_relative_line(); static void print_relative_line();
static void truncate_names(); static void truncate_names();
static my_bool get_pidfile(MYSQL *mysql, char *pidfile); static my_bool get_pidfile(MYSQL *mysql, char *pidfile);
static void wait_pidfile(char *pidfile, time_t last_modified, static my_bool wait_pidfile(char *pidfile, time_t last_modified,
struct stat *pidfile_status); struct stat *pidfile_status);
static void store_values(MYSQL_RES *result); static void store_values(MYSQL_RES *result);
@ -513,7 +513,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
printf("Shutdown signal sent to server; Waiting for pid file to disappear\n"); printf("Shutdown signal sent to server; Waiting for pid file to disappear\n");
/* Wait until pid file is gone */ /* Wait until pid file is gone */
wait_pidfile(pidfile, last_modified, &pidfile_status); if (wait_pidfile(pidfile, last_modified, &pidfile_status))
return -1;
} }
break; break;
} }
@ -1150,34 +1151,51 @@ static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
return 1; /* Error */ return 1; /* Error */
} }
/*
Return 1 if pid file didn't disappear or change
*/
static void wait_pidfile(char *pidfile, time_t last_modified, static my_bool wait_pidfile(char *pidfile, time_t last_modified,
struct stat *pidfile_status) struct stat *pidfile_status)
{ {
char buff[FN_REFLEN]; char buff[FN_REFLEN];
int fd = -1; int error= 1;
uint count= 0; uint count= 0;
DBUG_ENTER("wait_pidfile");
system_filename(buff, pidfile); system_filename(buff, pidfile);
while (count++ <= opt_shutdown_timeout && !interrupted && do
(!last_modified || (last_modified == pidfile_status->st_mtime)) &&
(fd= my_open(buff, O_RDONLY, MYF(0))) >= 0)
{ {
if (!my_close(fd,MYF(0))) int fd;
fd= -1; if ((fd= my_open(buff, O_RDONLY, MYF(0))) < 0)
sleep(1); {
if (last_modified && stat(pidfile, pidfile_status)) error= 0;
last_modified= 0; break;
} }
if (opt_verbose && last_modified && (void) my_close(fd,MYF(0));
last_modified != pidfile_status->st_mtime) if (last_modified && !stat(pidfile, pidfile_status))
printf("Warning; pid file '%s' changed while waiting for it to disappear!\n",
buff);
if (fd >= 0)
{ {
my_close(fd,MYF(0)); if (last_modified != pidfile_status->st_mtime)
{
/* File changed; Let's assume that mysqld did restart */
if (opt_verbose)
printf("pid file '%s' changed while waiting for it to disappear!\nmysqld did probably restart\n",
buff);
error= 0;
break;
}
}
if (count++ == opt_shutdown_timeout)
break;
sleep(1);
} while (!interrupted);
if (error)
{
DBUG_PRINT("warning",("Pid file didn't disappear"));
fprintf(stderr, fprintf(stderr,
"Warning; Aborted waiting on pid file: '%s' after %d seconds\n", "Warning; Aborted waiting on pid file: '%s' after %d seconds\n",
buff, count-1); buff, count-1);
} }
DBUG_RETURN(error);
} }

View File

@ -42,7 +42,7 @@
**********************************************************************/ **********************************************************************/
#define MTEST_VERSION "1.25" #define MTEST_VERSION "1.26"
#include <my_global.h> #include <my_global.h>
#include <mysql_embed.h> #include <mysql_embed.h>
@ -166,7 +166,8 @@ typedef struct
VAR var_reg[10]; VAR var_reg[10];
/*Perl/shell-like variable registers */ /*Perl/shell-like variable registers */
HASH var_hash; HASH var_hash;
int disable_query_log=0, disable_result_log=0; my_bool disable_query_log=0, disable_result_log=0, disable_warnings=0;
my_bool disable_info= 1; /* By default off */
struct connection cons[MAX_CONS]; struct connection cons[MAX_CONS];
struct connection* cur_con, *next_con, *cons_end; struct connection* cur_con, *next_con, *cons_end;
@ -195,6 +196,8 @@ Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER, Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER,
Q_WAIT_FOR_SLAVE_TO_STOP, Q_WAIT_FOR_SLAVE_TO_STOP,
Q_REQUIRE_VERSION, Q_REQUIRE_VERSION,
Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
Q_ENABLE_INFO, Q_DISABLE_INFO,
Q_UNKNOWN, /* Unknown command. */ Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */ Q_COMMENT, /* Comments, ignored. */
Q_COMMENT_WITH_COMMAND Q_COMMENT_WITH_COMMAND
@ -253,6 +256,10 @@ const char *command_names[]=
"require_manager", "require_manager",
"wait_for_slave_to_stop", "wait_for_slave_to_stop",
"require_version", "require_version",
"enable_warnings",
"disable_warnings",
"enable_info",
"diable_info",
0 0
}; };
@ -1803,10 +1810,8 @@ int read_query(struct st_query** q_ptr)
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
#ifndef DBUG_OFF
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'", {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"basedir", 'b', "Basedir for tests", (gptr*) &opt_basedir, {"basedir", 'b', "Basedir for tests", (gptr*) &opt_basedir,
@ -1899,7 +1904,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
{ {
switch(optid) { switch(optid) {
case '#': case '#':
#ifndef DBUG_OFF
DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace"); DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace");
#endif
break; break;
case 'r': case 'r':
record = 1; record = 1;
@ -1977,7 +1984,7 @@ int parse_args(int argc, char **argv)
default_argv= argv; default_argv= argv;
if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
exit(ho_error); exit(1);
if (argc > 1) if (argc > 1)
{ {
@ -2191,7 +2198,9 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
goto end; goto end;
} }
if (!disable_result_log && res) if (!disable_result_log)
{
if (res)
{ {
int num_fields= mysql_num_fields(res); int num_fields= mysql_num_fields(res);
MYSQL_FIELD *fields= mysql_fetch_fields(res); MYSQL_FIELD *fields= mysql_fetch_fields(res);
@ -2206,12 +2215,17 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
} }
/* Add all warnings to the result */ /* Add all warnings to the result */
if (!disable_result_log && mysql_warning_count(mysql)) if (!disable_warnings && mysql_warning_count(mysql))
{ {
MYSQL_RES *warn_res= mysql_warnings(mysql); MYSQL_RES *warn_res=0;
uint count= mysql_warning_count(mysql);
if (!mysql_real_query(mysql, "SHOW WARNINGS", 13))
{
warn_res=mysql_store_result(mysql);
}
if (!warn_res) if (!warn_res)
verbose_msg("Warning count is %d but didn't get any warnings\n", verbose_msg("Warning count is %u but didn't get any warnings\n",
mysql_warning_count(mysql)); count);
else else
{ {
dynstr_append_mem(ds, "Warnings:\n", 10); dynstr_append_mem(ds, "Warnings:\n", 10);
@ -2219,6 +2233,14 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
mysql_free_result(warn_res); mysql_free_result(warn_res);
} }
} }
if (!disable_info && mysql_info(mysql))
{
dynstr_append(ds, "info: ");
dynstr_append(ds, mysql_info(mysql));
dynstr_append_mem(ds, "\n", 1);
}
}
if (glob_replace) if (glob_replace)
free_replace(); free_replace();
@ -2427,6 +2449,10 @@ int main(int argc, char** argv)
case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; case Q_DISABLE_QUERY_LOG: disable_query_log=1; break;
case Q_ENABLE_RESULT_LOG: disable_result_log=0; break; case Q_ENABLE_RESULT_LOG: disable_result_log=0; break;
case Q_DISABLE_RESULT_LOG: disable_result_log=1; break; case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
case Q_ENABLE_WARNINGS: disable_warnings=0; break;
case Q_DISABLE_WARNINGS: disable_warnings=1; break;
case Q_ENABLE_INFO: disable_info=0; break;
case Q_DISABLE_INFO: disable_info=1; break;
case Q_SOURCE: do_source(q); break; case Q_SOURCE: do_source(q); break;
case Q_SLEEP: do_sleep(q, 0); break; case Q_SLEEP: do_sleep(q, 0); break;
case Q_REAL_SLEEP: do_sleep(q, 1); break; case Q_REAL_SLEEP: do_sleep(q, 1); break;

View File

@ -10,7 +10,7 @@ AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10 PROTOCOL_VERSION=10
DOT_FRM_VERSION=6 DOT_FRM_VERSION=6
# See the libtool docs for information on how to do shared lib versions. # See the libtool docs for information on how to do shared lib versions.
SHARED_LIB_VERSION=12:0:0 SHARED_LIB_VERSION=14:0:0
# Set all version vars based on $VERSION. How do we do this more elegant ? # Set all version vars based on $VERSION. How do we do this more elegant ?
# Remember that regexps needs to quote [ and ] since this is run through m4 # Remember that regexps needs to quote [ and ] since this is run through m4
@ -130,18 +130,24 @@ AC_PROG_CXX
AC_PROG_CPP AC_PROG_CPP
# Print version of CC and CXX compiler (if they support --version) # Print version of CC and CXX compiler (if they support --version)
CC_VERSION=`$CC --version` CC_VERSION=`$CC --version | sed 1q`
if test $? -eq "0" if test $? -eq "0"
then then
AC_MSG_CHECKING("C Compiler version"); AC_MSG_CHECKING("C Compiler version");
AC_MSG_RESULT("$CC $CC_VERSION") AC_MSG_RESULT("$CC $CC_VERSION")
else
CC_VERSION=""
fi fi
CXX_VERSION=`$CXX --version` CXX_VERSION=`$CXX --version | sed 1q`
if test $? -eq "0" if test $? -eq "0"
then then
AC_MSG_CHECKING("C++ compiler version"); AC_MSG_CHECKING("C++ compiler version");
AC_MSG_RESULT("$CXX $CXX_VERSION") AC_MSG_RESULT("$CXX $CXX_VERSION")
else
CXX_VERSION=""
fi fi
AC_SUBST(CXX_VERSION)
AC_SUBST(CC_VERSION)
# Fix for sgi gcc / sgiCC which tries to emulate gcc # Fix for sgi gcc / sgiCC which tries to emulate gcc
if test "$CC" = "sgicc" if test "$CC" = "sgicc"
@ -876,6 +882,7 @@ int main()
# #
MAX_C_OPTIMIZE="-O3" MAX_C_OPTIMIZE="-O3"
MAX_CXX_OPTIMIZE="-O3"
case $SYSTEM_TYPE in case $SYSTEM_TYPE in
*solaris2.7*) *solaris2.7*)
@ -943,6 +950,8 @@ case $SYSTEM_TYPE in
then then
CFLAGS="$CFLAGS +DD64 -DHAVE_BROKEN_INLINE" CFLAGS="$CFLAGS +DD64 -DHAVE_BROKEN_INLINE"
CXXFLAGS="$CXXFLAGS +DD64 +O2" CXXFLAGS="$CXXFLAGS +DD64 +O2"
MAX_C_OPTIMIZE=""
MAX_CXX_OPTIMIZE=""
fi fi
;; ;;
*rhapsody*) *rhapsody*)
@ -960,8 +969,8 @@ case $SYSTEM_TYPE in
*darwin5*) *darwin5*)
if test "$ac_cv_prog_gcc" = "yes" if test "$ac_cv_prog_gcc" = "yes"
then then
CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH" CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE"
CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ" CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DFN_NO_CASE_SENCE"
MAX_C_OPTIMIZE="-O" MAX_C_OPTIMIZE="-O"
with_named_curses="" with_named_curses=""
fi fi
@ -969,8 +978,8 @@ case $SYSTEM_TYPE in
*darwin6*) *darwin6*)
if test "$ac_cv_prog_gcc" = "yes" if test "$ac_cv_prog_gcc" = "yes"
then then
CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH" CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE"
CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ" CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DFN_NO_CASE_SENCE"
MAX_C_OPTIMIZE="-O" MAX_C_OPTIMIZE="-O"
fi fi
;; ;;
@ -1231,7 +1240,7 @@ then
# CC="$CC -Kthread -DOpenUNIX8"; # CC="$CC -Kthread -DOpenUNIX8";
# CXX="$CXX -Kthread -DOpenUNIX8"; # CXX="$CXX -Kthread -DOpenUNIX8";
CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK";
CXX="$CXX -Kthread -DUNIXWARE_7"; CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"
fi fi
AC_MSG_RESULT("yes") AC_MSG_RESULT("yes")
else else
@ -1401,7 +1410,7 @@ if test "$ac_cv_prog_cxx_g" = "yes"
then then
DEBUG_CXXFLAGS="-g" DEBUG_CXXFLAGS="-g"
DEBUG_OPTIMIZE_CXX="-O" DEBUG_OPTIMIZE_CXX="-O"
OPTIMIZE_CXXFLAGS="-O3" OPTIMIZE_CXXFLAGS="$MAX_CXX_OPTIMIZE"
else else
DEBUG_CXXFLAGS="-g" DEBUG_CXXFLAGS="-g"
DEBUG_OPTIMIZE_CXX="" DEBUG_OPTIMIZE_CXX=""

View File

@ -18,7 +18,7 @@ INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \ LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a ../dbug/libdbug.a ../strings/libmystrings.a
bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \ bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \
resolve_stack_dump mysql_install resolve_stack_dump mysql_install mysql_waitpid
# Don't update the files from bitkeeper # Don't update the files from bitkeeper
%::SCCS/s.% %::SCCS/s.%

86
extra/mysql_waitpid.c Normal file
View File

@ -0,0 +1,86 @@
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <my_global.h>
#include <my_getopt.h>
static const char *VER= "1.1";
static char *progname;
static my_bool verbose;
void usage(void);
static struct my_option my_long_options[] =
{
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
0, 0, 0, 0, 0},
{"help", 'I', "Synonym for -?.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
0, 0, 0, 0, 0},
{"verbose", 'v',
"Be more verbose. Give a warning, if kill can't handle signal 0.",
(gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Print version information and exit.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument __attribute__((unused)))
{
switch(optid) {
case 'V':
printf("%s version %s by Jani Tolonen\n", progname, VER);
exit(-1);
case 'I':
case '?':
usage();
}
return 0;
}
int main(int argc, char *argv[])
{
int pid= 0, t= 0, sig= 0;
progname= argv[0];
if (handle_options(&argc, &argv, my_long_options, get_one_option))
exit(-1);
if (!argv[0] || !argv[1] || (pid= atoi(argv[0])) <= 0 ||
(t= atoi(argv[1])) <= 0)
usage();
for (; t > 0; t--)
{
if (kill((pid_t) pid, sig))
{
if (errno == EINVAL)
{
if (verbose)
printf("WARNING: kill couldn't handle signal 0, using signal 1.\n");
sig= 1;
t++;
continue;
}
return 0;
}
sleep(1);
}
return 1;
}
void usage(void)
{
printf("%s version %s by Jani Tolonen\n\n", progname, VER);
printf("usage: %s [options] #pid #time\n\n", progname);
printf("Description: Waits for a program, which program id is #pid, to\n");
printf("terminate within #time seconds. If the program terminates within\n");
printf("this time, or if the #pid no longer exists, value 0 is returned.\n");
printf("Otherwise 1 is returned. Both #pid and #time must be positive\n");
printf("integer arguments.\n\n");
printf("Options:\n");
my_print_help(my_long_options);
exit(-1);
}

View File

@ -80,6 +80,7 @@ static HA_ERRORS ha_errlist[]=
{ 147,"Lock table is full; Restart program with a larger locktable"}, { 147,"Lock table is full; Restart program with a larger locktable"},
{ 148,"Updates are not allowed under a read only transactions"}, { 148,"Updates are not allowed under a read only transactions"},
{ 149,"Lock deadlock; Retry transaction"}, { 149,"Lock deadlock; Retry transaction"},
{ 150,"Foreign key constraint is incorrectly formed"},
{ -30999, "DB_INCOMPLETE: Sync didn't finish"}, { -30999, "DB_INCOMPLETE: Sync didn't finish"},
{ -30998, "DB_KEYEMPTY: Key/data deleted or never created"}, { -30998, "DB_KEYEMPTY: Key/data deleted or never created"},
{ -30997, "DB_KEYEXIST: The key/data pair already exists"}, { -30997, "DB_KEYEXIST: The key/data pair already exists"},

View File

@ -16,7 +16,7 @@
# MA 02111-1307, USA # MA 02111-1307, USA
BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h
pkginclude_HEADERS = dbug.h m_string.h my_sys.h my_list.h \ pkginclude_HEADERS = dbug.h m_string.h my_sys.h my_list.h my_xml.h \
mysql.h mysql_com.h mysqld_error.h mysql_embed.h \ mysql.h mysql_com.h mysqld_error.h mysql_embed.h \
my_semaphore.h my_pthread.h my_no_pthread.h raid.h \ my_semaphore.h my_pthread.h my_no_pthread.h raid.h \
errmsg.h my_global.h my_net.h my_alloc.h \ errmsg.h my_global.h my_net.h my_alloc.h \

View File

@ -27,6 +27,13 @@ extern "C" {
#endif #endif
#define MY_CS_NAME_SIZE 32
#define MY_CS_CTYPE_TABLE_SIZE 257
#define MY_CS_TO_LOWER_TABLE_SIZE 256
#define MY_CS_TO_UPPER_TABLE_SIZE 256
#define MY_CS_SORT_ORDER_TABLE_SIZE 256
#define MY_CS_TO_UNI_TABLE_SIZE 256
#define CHARSET_DIR "charsets/" #define CHARSET_DIR "charsets/"
#define my_wc_t ulong #define my_wc_t ulong
@ -49,6 +56,7 @@ typedef struct unicase_info_st {
#define MY_CS_INDEX 4 /* sets listed in the Index file */ #define MY_CS_INDEX 4 /* sets listed in the Index file */
#define MY_CS_LOADED 8 /* sets that are currently loaded */ #define MY_CS_LOADED 8 /* sets that are currently loaded */
#define MY_CS_BINSORT 16 /* if binary sort order */ #define MY_CS_BINSORT 16 /* if binary sort order */
#define MY_CS_PRIMARY 32 /* if primary collation */
#define MY_CHARSET_UNDEFINED 0 #define MY_CHARSET_UNDEFINED 0
#define MY_CHARSET_CURRENT (default_charset_info->number) #define MY_CHARSET_CURRENT (default_charset_info->number)
@ -65,6 +73,7 @@ typedef struct charset_info_st
{ {
uint number; uint number;
uint state; uint state;
const char *csname;
const char *name; const char *name;
const char *comment; const char *comment;
uchar *ctype; uchar *ctype;
@ -127,11 +136,12 @@ typedef struct charset_info_st
int (*l10tostr)(struct charset_info_st *, char *to, uint n, int radix, long int val); int (*l10tostr)(struct charset_info_st *, char *to, uint n, int radix, long int val);
int (*ll10tostr)(struct charset_info_st *, char *to, uint n, int radix, longlong val); int (*ll10tostr)(struct charset_info_st *, char *to, uint n, int radix, longlong val);
/* String-to-number convertion routines */
long (*strntol)(struct charset_info_st *, const char *s, uint l,char **e, int base); long (*strntol)(struct charset_info_st *, const char *s, uint l,char **e, int base);
ulong (*strntoul)(struct charset_info_st *, const char *s, uint l, char **e, int base); ulong (*strntoul)(struct charset_info_st *, const char *s, uint l, char **e, int base);
longlong (*strntoll)(struct charset_info_st *, const char *s, uint l, char **e, int base); longlong (*strntoll)(struct charset_info_st *, const char *s, uint l, char **e, int base);
ulonglong (*strntoull)(struct charset_info_st *, const char *s, uint l, char **e, int base); ulonglong (*strntoull)(struct charset_info_st *, const char *s, uint l, char **e, int base);
double (*strntod)(struct charset_info_st *, const char *s, uint l, char **e); double (*strntod)(struct charset_info_st *, char *s, uint l, char **e);
} CHARSET_INFO; } CHARSET_INFO;
@ -142,7 +152,8 @@ extern CHARSET_INFO *default_charset_info;
extern CHARSET_INFO *system_charset_info; extern CHARSET_INFO *system_charset_info;
extern CHARSET_INFO *all_charsets[256]; extern CHARSET_INFO *all_charsets[256];
extern my_bool init_compiled_charsets(myf flags); extern my_bool init_compiled_charsets(myf flags);
extern my_bool my_parse_charset_xml(const char *bug, uint len,
int (*add)(CHARSET_INFO *cs));
/* declarations for simple charsets */ /* declarations for simple charsets */
extern int my_strnxfrm_simple(CHARSET_INFO *, uchar *, uint, const uchar *, uint); extern int my_strnxfrm_simple(CHARSET_INFO *, uchar *, uint, const uchar *, uint);
@ -175,7 +186,7 @@ long my_strntol_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int
ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base);
longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base);
ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base); ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, uint l,char **e, int base);
double my_strntod_8bit(CHARSET_INFO *, const char *s, uint l,char **e); double my_strntod_8bit(CHARSET_INFO *, char *s, uint l,char **e);
int my_l10tostr_8bit(CHARSET_INFO *, char *to, uint l, int radix, long int val); int my_l10tostr_8bit(CHARSET_INFO *, char *to, uint l, int radix, long int val);
int my_ll10tostr_8bit(CHARSET_INFO *, char *to, uint l, int radix, longlong val); int my_ll10tostr_8bit(CHARSET_INFO *, char *to, uint l, int radix, longlong val);

View File

@ -31,6 +31,9 @@
#include <string.h> #include <string.h>
#endif #endif
/* need by my_vsnprintf */
#include <stdarg.h>
/* Correct some things for UNIXWARE7 */ /* Correct some things for UNIXWARE7 */
#ifdef HAVE_UNIXWARE7_THREADS #ifdef HAVE_UNIXWARE7_THREADS
#undef HAVE_STRINGS_H #undef HAVE_STRINGS_H
@ -238,6 +241,12 @@ extern ulonglong strtoull(const char *str, char **ptr, int base);
#endif #endif
#endif #endif
/* my_vsnprintf.c */
extern int my_vsnprintf( char *str, size_t n,
const char *format, va_list ap );
extern int my_snprintf(char* to, size_t n, const char* fmt, ...);
#if defined(__cplusplus) && !defined(OS2) #if defined(__cplusplus) && !defined(OS2)
} }
#endif #endif

View File

@ -107,9 +107,6 @@ enum ha_extra_function {
HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/ HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/
HA_EXTRA_NO_IGNORE_DUP_KEY, HA_EXTRA_NO_IGNORE_DUP_KEY,
HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE, /* Cursor will not be used for update */ HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE, /* Cursor will not be used for update */
HA_EXTRA_BULK_INSERT_BEGIN,
HA_EXTRA_BULK_INSERT_FLUSH, /* Flush one index */
HA_EXTRA_BULK_INSERT_END,
HA_EXTRA_PREPARE_FOR_DELETE, HA_EXTRA_PREPARE_FOR_DELETE,
HA_EXTRA_PREPARE_FOR_UPDATE /* Remove read cache if problems */ HA_EXTRA_PREPARE_FOR_UPDATE /* Remove read cache if problems */
}; };
@ -267,6 +264,7 @@ enum ha_base_keytype {
#define MBR_EQUAL 8192 #define MBR_EQUAL 8192
#define MBR_DATA 16384 #define MBR_DATA 16384
#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */ #define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
#define SEARCH_NULL_ARE_NOT_EQUAL 65536 /* NULL in keys are not equal */
/* bits in opt_flag */ /* bits in opt_flag */
#define QUICK_USED 1 #define QUICK_USED 1

View File

@ -206,6 +206,7 @@ extern const char *get_charset_name(uint cs_number);
extern CHARSET_INFO *get_charset(uint cs_number, myf flags); extern CHARSET_INFO *get_charset(uint cs_number, myf flags);
extern my_bool set_default_charset(uint cs, myf flags); extern my_bool set_default_charset(uint cs, myf flags);
extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags);
extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, myf flags);
extern my_bool set_default_charset_by_name(const char *cs_name, myf flags); extern my_bool set_default_charset_by_name(const char *cs_name, myf flags);
extern void free_charsets(void); extern void free_charsets(void);
extern char *list_charsets(myf want_flags); /* my_free() this string... */ extern char *list_charsets(myf want_flags); /* my_free() this string... */
@ -505,6 +506,8 @@ extern int my_setwd(const char *dir,myf MyFlags);
extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags); extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags);
extern gptr my_once_alloc(uint Size,myf MyFlags); extern gptr my_once_alloc(uint Size,myf MyFlags);
extern void my_once_free(void); extern void my_once_free(void);
extern char *my_once_strdup(const char *src,myf myflags);
extern char *my_once_memdup(const char *src, uint len, myf myflags);
extern my_string my_tempnam(const char *dir,const char *pfx,myf MyFlags); extern my_string my_tempnam(const char *dir,const char *pfx,myf MyFlags);
extern File my_open(const char *FileName,int Flags,myf MyFlags); extern File my_open(const char *FileName,int Flags,myf MyFlags);
extern File my_register_filename(File fd, const char *FileName, extern File my_register_filename(File fd, const char *FileName,
@ -566,9 +569,6 @@ extern int my_error _VARARGS((int nr,myf MyFlags, ...));
extern int my_printf_error _VARARGS((uint my_err, const char *format, extern int my_printf_error _VARARGS((uint my_err, const char *format,
myf MyFlags, ...) myf MyFlags, ...)
__attribute__ ((format (printf, 2, 4)))); __attribute__ ((format (printf, 2, 4))));
extern int my_vsnprintf( char *str, size_t n,
const char *format, va_list ap );
extern int my_snprintf(char* to, size_t n, const char* fmt, ...);
extern int my_message(uint my_err, const char *str,myf MyFlags); extern int my_message(uint my_err, const char *str,myf MyFlags);
extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags);
extern int my_message_curses(uint my_err, const char *str,myf MyFlags); extern int my_message_curses(uint my_err, const char *str,myf MyFlags);

61
include/my_xml.h Normal file
View File

@ -0,0 +1,61 @@
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _my_xml_h
#define _my_xml_h
#ifdef __cplusplus
extern "C" {
#endif
#define MY_XML_OK 0
#define MY_XML_ERROR 1
typedef struct xml_stack_st
{
char errstr[128];
char attr[128];
char *attrend;
const char *beg;
const char *cur;
const char *end;
void *user_data;
int (*enter)(struct xml_stack_st *st,const char *val, uint len);
int (*value)(struct xml_stack_st *st,const char *val, uint len);
int (*leave)(struct xml_stack_st *st,const char *val, uint len);
} MY_XML_PARSER;
void my_xml_parser_create(MY_XML_PARSER *st);
void my_xml_parser_free(MY_XML_PARSER *st);
int my_xml_parse(MY_XML_PARSER *st,const char *str, uint len);
void my_xml_set_value_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, uint len));
void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, uint len));
void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, const char *, uint len));
void my_xml_set_user_data(MY_XML_PARSER *st, void *);
uint my_xml_error_pos(MY_XML_PARSER *st);
uint my_xml_error_lineno(MY_XML_PARSER *st);
const char *my_xml_error_string(MY_XML_PARSER *st);
#ifdef __cplusplus
}
#endif
#endif /* _my_xml_h */

View File

@ -397,6 +397,10 @@ void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, ulonglong key_map, my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, ulonglong key_map,
my_bool force); my_bool force);
int mi_init_bulk_insert(MI_INFO *info, ulong cache_size, ha_rows rows);
void mi_flush_bulk_insert(MI_INFO *info, uint inx);
void mi_end_bulk_insert(MI_INFO *info);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -51,6 +51,7 @@ typedef struct st_mymerge_info /* Struct from h_info */
uint reclength; /* Recordlength */ uint reclength; /* Recordlength */
int errkey; /* With key was dupplicated on err */ int errkey; /* With key was dupplicated on err */
uint options; /* HA_OPTION_... used */ uint options; /* HA_OPTION_... used */
ulong *rec_per_key; /* for sql optimizing */
} MYMERGE_INFO; } MYMERGE_INFO;
typedef struct st_myrg_table_info typedef struct st_myrg_table_info
@ -71,6 +72,7 @@ typedef struct st_myrg_info
my_bool cache_in_use; my_bool cache_in_use;
LIST open_list; LIST open_list;
QUEUE by_key; QUEUE by_key;
ulong *rec_per_key_part; /* for sql optimizing */
} MYRG_INFO; } MYRG_INFO;

View File

@ -130,6 +130,7 @@ struct st_mysql_options {
char *ssl_ca; /* PEM CA file */ char *ssl_ca; /* PEM CA file */
char *ssl_capath; /* PEM directory of CA-s? */ char *ssl_capath; /* PEM directory of CA-s? */
char *ssl_cipher; /* cipher to use */ char *ssl_cipher; /* cipher to use */
unsigned long max_allowed_packet;
my_bool use_ssl; /* if to use SSL or not */ my_bool use_ssl; /* if to use SSL or not */
my_bool compress,named_pipe; my_bool compress,named_pipe;
/* /*
@ -415,7 +416,6 @@ MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table,
MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql); MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql);
MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql);
MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql);
MYSQL_RES * STDCALL mysql_warnings(MYSQL *mysql);
int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option,
const char *arg); const char *arg);
void STDCALL mysql_free_result(MYSQL_RES *result); void STDCALL mysql_free_result(MYSQL_RES *result);
@ -473,13 +473,12 @@ typedef struct st_mysql_bind
{ {
long *length; /* output length pointer */ long *length; /* output length pointer */
gptr buffer; /* buffer */ gptr buffer; /* buffer */
unsigned long buffer_length; /* buffer length */
enum enum_field_types buffer_type; /* buffer type */ enum enum_field_types buffer_type; /* buffer type */
enum enum_field_types field_type; /* field type */
my_bool is_null; /* NULL indicator */ my_bool is_null; /* NULL indicator */
my_bool is_long_data; /* long data indicator */ my_bool is_long_data; /* long data indicator */
/* The following are for internal use. Set by mysql_bind_param */ /* The following are for internal use. Set by mysql_bind_param */
unsigned long buffer_length; /* buffer length */
long bind_length; /* Default length of data */ long bind_length; /* Default length of data */
my_bool long_ended; /* All data supplied for long */ my_bool long_ended; /* All data supplied for long */
unsigned int param_number; /* For null count and error messages */ unsigned int param_number; /* For null count and error messages */
@ -536,15 +535,16 @@ int STDCALL mysql_multi_query(MYSQL *mysql,const char *query,
unsigned long len); unsigned long len);
MYSQL_RES *STDCALL mysql_next_result(MYSQL *mysql); MYSQL_RES *STDCALL mysql_next_result(MYSQL *mysql);
MYSQL_RES *STDCALL mysql_prepare_result(MYSQL_STMT *stmt); MYSQL_RES *STDCALL mysql_prepare_result(MYSQL_STMT *stmt);
my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt);
/* new status messages */ /* new status messages */
#define MYSQL_SUCCESS 0 #define MYSQL_SUCCESS 0
#define MYSQL_WARNING 1 #define MYSQL_STATUS_ERROR 1
#define MYSQL_STATUS_ERROR 2
#define MYSQL_NO_DATA 100 #define MYSQL_NO_DATA 100
#define MYSQL_NEED_DATA 99 #define MYSQL_NEED_DATA 99
#define MYSQL_LONG_DATA_END 0xFF #define MYSQL_NULL_DATA (-1)
#define MYSQL_LONG_DATA (-2)
#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)

View File

@ -42,7 +42,8 @@ enum enum_server_command
COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING,
COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP,
COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE,
COM_PREPARE, COM_EXECUTE, COM_LONG_DATA, COM_CLOSE_STMT COM_PREPARE, COM_EXECUTE, COM_LONG_DATA, COM_CLOSE_STMT,
COM_END /* Must be last */
}; };
@ -297,11 +298,11 @@ int get_password_length(my_bool force_old_scramble);
char get_password_version(const char* password); char get_password_version(const char* password);
void create_random_string(int length,struct rand_struct *rand_st,char* target); void create_random_string(int length,struct rand_struct *rand_st,char* target);
my_bool validate_password(const char* password, const char* message, my_bool validate_password(const char* password, const char* message,
ulong* salt); unsigned long* salt);
void password_hash_stage1(char *to, const char *password); void password_hash_stage1(char *to, const char *password);
void password_hash_stage2(char *to,const char *salt); void password_hash_stage2(char *to,const char *salt);
void password_crypt(const char* from,char* to, const char* password,int length); void password_crypt(const char* from,char* to, const char* password,int length);
void get_hash_and_password(ulong* salt, unsigned char pversion,char* hash, void get_hash_and_password(unsigned long* salt, unsigned char pversion,char* hash,
unsigned char* bin_password); unsigned char* bin_password);
void get_salt_from_password(unsigned long *res,const char *password); void get_salt_from_password(unsigned long *res,const char *password);
void create_key_from_old_password(const char* password,char* key); void create_key_from_old_password(const char* password,char* key);

View File

@ -265,4 +265,5 @@
#define ER_DERIVED_MUST_HAVE_ALIAS 1246 #define ER_DERIVED_MUST_HAVE_ALIAS 1246
#define ER_SELECT_REDUCED 1247 #define ER_SELECT_REDUCED 1247
#define ER_TABLENAME_NOT_ALLOWED_HERE 1248 #define ER_TABLENAME_NOT_ALLOWED_HERE 1248
#define ER_ERROR_MESSAGES 249 #define ER_NOT_SUPPORTED_AUTH_MODE 1249
#define ER_ERROR_MESSAGES 250

View File

@ -291,6 +291,7 @@ btr_cur_search_to_nth_level(
&& latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
&& !estimate && !estimate
&& mode != PAGE_CUR_LE_OR_EXTENDS && mode != PAGE_CUR_LE_OR_EXTENDS
&& srv_use_adaptive_hash_indexes
&& btr_search_guess_on_hash(index, info, tuple, mode, && btr_search_guess_on_hash(index, info, tuple, mode,
latch_mode, cursor, latch_mode, cursor,
has_search_latch, mtr)) { has_search_latch, mtr)) {
@ -495,9 +496,11 @@ retry_page_get:
cursor->up_bytes = up_bytes; cursor->up_bytes = up_bytes;
#ifdef BTR_CUR_ADAPT #ifdef BTR_CUR_ADAPT
btr_search_info_update(index, cursor); if (srv_use_adaptive_hash_indexes) {
#endif
btr_search_info_update(index, cursor);
}
#endif
ut_ad(cursor->up_match != ULINT_UNDEFINED ut_ad(cursor->up_match != ULINT_UNDEFINED
|| mode != PAGE_CUR_GE); || mode != PAGE_CUR_GE);
ut_ad(cursor->up_match != ULINT_UNDEFINED ut_ad(cursor->up_match != ULINT_UNDEFINED

View File

@ -95,7 +95,9 @@ btr_pcur_store_position(
ut_a(cursor->latch_mode != BTR_NO_LATCHES); ut_a(cursor->latch_mode != BTR_NO_LATCHES);
if (page_get_n_recs(page) == 0) { if (page_get_n_recs(page) == 0) {
/* It must be an empty index tree */ /* It must be an empty index tree; NOTE that in this case
we do not store the modify_clock, but always do a search
if we restore the cursor position */
ut_a(btr_page_get_next(page, mtr) == FIL_NULL ut_a(btr_page_get_next(page, mtr) == FIL_NULL
&& btr_page_get_prev(page, mtr) == FIL_NULL); && btr_page_get_prev(page, mtr) == FIL_NULL);
@ -134,6 +136,7 @@ btr_pcur_store_position(
&(cursor->old_rec_buf), &(cursor->old_rec_buf),
&(cursor->buf_size)); &(cursor->buf_size));
cursor->block_when_stored = buf_block_align(page);
cursor->modify_clock = buf_frame_get_modify_clock(page); cursor->modify_clock = buf_frame_get_modify_clock(page);
} }
@ -205,6 +208,9 @@ btr_pcur_restore_position(
if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) { || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
/* In these cases we do not try an optimistic restoration,
but always do a search */
if (cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) { if (cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
from_left = TRUE; from_left = TRUE;
} else { } else {
@ -214,6 +220,10 @@ btr_pcur_restore_position(
btr_cur_open_at_index_side(from_left, btr_cur_open_at_index_side(from_left,
btr_pcur_get_btr_cur(cursor)->index, latch_mode, btr_pcur_get_btr_cur(cursor)->index, latch_mode,
btr_pcur_get_btr_cur(cursor), mtr); btr_pcur_get_btr_cur(cursor), mtr);
cursor->block_when_stored =
buf_block_align(btr_pcur_get_page(cursor));
return(FALSE); return(FALSE);
} }
@ -224,7 +234,8 @@ btr_pcur_restore_position(
if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) { if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) {
/* Try optimistic restoration */ /* Try optimistic restoration */
if (buf_page_optimistic_get(latch_mode, page, if (buf_page_optimistic_get(latch_mode,
cursor->block_when_stored, page,
cursor->modify_clock, mtr)) { cursor->modify_clock, mtr)) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->pos_state = BTR_PCUR_IS_POSITIONED;
@ -271,8 +282,6 @@ btr_pcur_restore_position(
btr_pcur_open_with_no_init(btr_pcur_get_btr_cur(cursor)->index, tuple, btr_pcur_open_with_no_init(btr_pcur_get_btr_cur(cursor)->index, tuple,
mode, latch_mode, cursor, 0, mtr); mode, latch_mode, cursor, 0, mtr);
cursor->old_stored = BTR_PCUR_OLD_STORED;
/* Restore the old search mode */ /* Restore the old search mode */
cursor->search_mode = old_mode; cursor->search_mode = old_mode;
@ -281,10 +290,17 @@ btr_pcur_restore_position(
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor))) { && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor))) {
/* We have to store the NEW value for the modify clock, since /* We have to store the NEW value for the modify clock, since
the cursor can now be on a different page! */ the cursor can now be on a different page! But we can retain
the value of old_rec */
cursor->modify_clock =
buf_frame_get_modify_clock(btr_pcur_get_page(cursor));
cursor->block_when_stored =
buf_block_align(btr_pcur_get_page(cursor));
cursor->old_stored = BTR_PCUR_OLD_STORED;
cursor->modify_clock = buf_frame_get_modify_clock(
buf_frame_align(btr_pcur_get_rec(cursor)));
mem_heap_free(heap); mem_heap_free(heap);
return(TRUE); return(TRUE);
@ -292,6 +308,12 @@ btr_pcur_restore_position(
mem_heap_free(heap); mem_heap_free(heap);
/* We have to store new position information, modify_clock etc.,
to the cursor because it can now be on a different page, the record
under it may have been removed, etc. */
btr_pcur_store_position(cursor, mtr);
return(FALSE); return(FALSE);
} }

View File

@ -19,6 +19,9 @@ Created 2/17/1996 Heikki Tuuri
#include "btr0btr.h" #include "btr0btr.h"
#include "ha0ha.h" #include "ha0ha.h"
ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the
compiler */
ulint btr_search_n_succ = 0; ulint btr_search_n_succ = 0;
ulint btr_search_n_hash_fail = 0; ulint btr_search_n_hash_fail = 0;
@ -56,11 +59,15 @@ before hash index building is started */
/************************************************************************ /************************************************************************
Builds a hash index on a page with the given parameters. If the page already Builds a hash index on a page with the given parameters. If the page already
has a hash index with different parameters, the old hash index is removed. */ has a hash index with different parameters, the old hash index is removed.
If index is non-NULL, this function checks if n_fields and n_bytes are
sensible values, and does not build a hash index if not. */
static static
void void
btr_search_build_page_hash_index( btr_search_build_page_hash_index(
/*=============================*/ /*=============================*/
dict_index_t* index, /* in: index for which to build, or NULL if
not known */
page_t* page, /* in: index page, s- or x-latched */ page_t* page, /* in: index page, s- or x-latched */
ulint n_fields,/* in: hash this many full fields */ ulint n_fields,/* in: hash this many full fields */
ulint n_bytes,/* in: hash this many bytes from the next ulint n_bytes,/* in: hash this many bytes from the next
@ -173,7 +180,9 @@ btr_search_info_create(
} }
/************************************************************************* /*************************************************************************
Updates the search info of an index about hash successes. */ Updates the search info of an index about hash successes. NOTE that info
is NOT protected by any semaphore, to save CPU time! Do not assume its fields
are consistent. */
static static
void void
btr_search_info_update_hash( btr_search_info_update_hash(
@ -295,7 +304,9 @@ set_new_recomm:
} }
/************************************************************************* /*************************************************************************
Updates the block search info on hash successes. */ Updates the block search info on hash successes. NOTE that info and
block->n_hash_helps, n_fields, n_bytes, side are NOT protected by any
semaphore, to save CPU time! Do not assume the fields are consistent. */
static static
ibool ibool
btr_search_update_block_hash_info( btr_search_update_block_hash_info(
@ -425,12 +436,19 @@ btr_search_info_update_slow(
{ {
buf_block_t* block; buf_block_t* block;
ibool build_index; ibool build_index;
ulint* params;
ulint* params2;
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED) ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)
&& !rw_lock_own(&btr_search_latch, RW_LOCK_EX)); && !rw_lock_own(&btr_search_latch, RW_LOCK_EX));
block = buf_block_align(btr_cur_get_rec(cursor)); block = buf_block_align(btr_cur_get_rec(cursor));
/* NOTE that the following two function calls do NOT protect
info or block->n_fields etc. with any semaphore, to save CPU time!
We cannot assume the fields are consistent when we return from
those functions! */
btr_search_info_update_hash(info, cursor); btr_search_info_update_hash(info, cursor);
build_index = btr_search_update_block_hash_info(info, block, cursor); build_index = btr_search_update_block_hash_info(info, block, cursor);
@ -453,12 +471,30 @@ btr_search_info_update_slow(
} }
if (build_index) { if (build_index) {
ut_a(block->n_fields + block->n_bytes > 0); /* Note that since we did not protect block->n_fields etc.
with any semaphore, the values can be inconsistent. We have
to check inside the function call that they make sense. We
also malloc an array and store the values there to make sure
the compiler does not let the function call parameters change
inside the called function. It might be that the compiler
would optimize the call just to pass pointers to block. */
btr_search_build_page_hash_index(block->frame, params = mem_alloc(3 * sizeof(ulint));
block->n_fields, params[0] = block->n_fields;
block->n_bytes, params[1] = block->n_bytes;
block->side); params[2] = block->side;
/* Make sure the compiler cannot deduce the values and do
optimizations */
params2 = params + btr_search_this_is_zero;
btr_search_build_page_hash_index(cursor->index,
block->frame,
params2[0],
params2[1],
params2[2]);
mem_free(params);
} }
} }
@ -976,11 +1012,15 @@ btr_search_drop_page_hash_when_freed(
/************************************************************************ /************************************************************************
Builds a hash index on a page with the given parameters. If the page already Builds a hash index on a page with the given parameters. If the page already
has a hash index with different parameters, the old hash index is removed. */ has a hash index with different parameters, the old hash index is removed.
If index is non-NULL, this function checks if n_fields and n_bytes are
sensible values, and does not build a hash index if not. */
static static
void void
btr_search_build_page_hash_index( btr_search_build_page_hash_index(
/*=============================*/ /*=============================*/
dict_index_t* index, /* in: index for which to build, or NULL if
not known */
page_t* page, /* in: index page, s- or x-latched */ page_t* page, /* in: index page, s- or x-latched */
ulint n_fields,/* in: hash this many full fields */ ulint n_fields,/* in: hash this many full fields */
ulint n_bytes,/* in: hash this many bytes from the next ulint n_bytes,/* in: hash this many bytes from the next
@ -1028,7 +1068,18 @@ btr_search_build_page_hash_index(
return; return;
} }
ut_a(n_fields + n_bytes > 0); /* Check that the values for hash index build are sensible */
if (n_fields + n_bytes == 0) {
return;
}
if (index && (dict_index_get_n_unique_in_tree(index) < n_fields
|| (dict_index_get_n_unique_in_tree(index) == n_fields
&& n_bytes > 0))) {
return;
}
/* Calculate and cache fold values and corresponding records into /* Calculate and cache fold values and corresponding records into
an array for fast insertion to the hash index */ an array for fast insertion to the hash index */
@ -1186,8 +1237,8 @@ btr_search_move_or_delete_hash_entries(
ut_a(n_fields + n_bytes > 0); ut_a(n_fields + n_bytes > 0);
btr_search_build_page_hash_index(new_page, n_fields, n_bytes, btr_search_build_page_hash_index(NULL, new_page, n_fields,
side); n_bytes, side);
ut_a(n_fields == block->curr_n_fields); ut_a(n_fields == block->curr_n_fields);
ut_a(n_bytes == block->curr_n_bytes); ut_a(n_bytes == block->curr_n_bytes);
ut_a(side == block->curr_side); ut_a(side == block->curr_side);

View File

@ -196,7 +196,29 @@ If a new page is referenced in the buf_pool, and several pages
of its random access area (for instance, 32 consecutive pages of its random access area (for instance, 32 consecutive pages
in a tablespace) have recently been referenced, we may predict in a tablespace) have recently been referenced, we may predict
that the whole area may be needed in the near future, and issue that the whole area may be needed in the near future, and issue
the read requests for the whole area. */ the read requests for the whole area.
AWE implementation
------------------
By a 'block' we mean the buffer header of type buf_block_t. By a 'page'
we mean the physical 16 kB memory area allocated from RAM for that block.
By a 'frame' we mean a 16 kB area in the virtual address space of the
process, in the frame_mem of buf_pool.
We can map pages to the frames of the buffer pool.
1) A buffer block allocated to use as a non-data page, e.g., to the lock
table, is always mapped to a frame.
2) A bufferfixed or io-fixed data page is always mapped to a frame.
3) When we need to map a block to frame, we look from the list
awe_LRU_free_mapped and try to unmap its last block, but note that
bufferfixed or io-fixed pages cannot be unmapped.
4) For every frame in the buffer pool there is always a block whose page is
mapped to it. When we create the buffer pool, we map the first elements
in the free list to the frames.
5) When we have AWE enabled, we disable adaptive hash indexes.
*/
buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */ buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */
@ -346,12 +368,15 @@ void
buf_block_init( buf_block_init(
/*===========*/ /*===========*/
buf_block_t* block, /* in: pointer to control block */ buf_block_t* block, /* in: pointer to control block */
byte* frame) /* in: pointer to buffer frame */ byte* frame) /* in: pointer to buffer frame, or NULL if in
the case of AWE there is no frame */
{ {
block->state = BUF_BLOCK_NOT_USED; block->state = BUF_BLOCK_NOT_USED;
block->frame = frame; block->frame = frame;
block->awe_info = NULL;
block->modify_clock = ut_dulint_zero; block->modify_clock = ut_dulint_zero;
block->file_page_was_freed = FALSE; block->file_page_was_freed = FALSE;
@ -361,32 +386,46 @@ buf_block_init(
rw_lock_create(&(block->lock)); rw_lock_create(&(block->lock));
ut_ad(rw_lock_validate(&(block->lock))); ut_ad(rw_lock_validate(&(block->lock)));
rw_lock_create(&(block->read_lock)); #ifdef UNIV_SYNC_DEBUG
rw_lock_set_level(&(block->read_lock), SYNC_NO_ORDER_CHECK);
rw_lock_create(&(block->debug_latch)); rw_lock_create(&(block->debug_latch));
rw_lock_set_level(&(block->debug_latch), SYNC_NO_ORDER_CHECK); rw_lock_set_level(&(block->debug_latch), SYNC_NO_ORDER_CHECK);
#endif
} }
/************************************************************************ /************************************************************************
Creates a buffer buf_pool object. */ Creates the buffer pool. */
static
buf_pool_t* buf_pool_t*
buf_pool_create( buf_pool_init(
/*============*/ /*==========*/
/* out, own: buf_pool object, NULL if not /* out, own: buf_pool object, NULL if not
enough memory */ enough memory or error */
ulint max_size, /* in: maximum size of the buf_pool in ulint max_size, /* in: maximum size of the buf_pool in
blocks */ blocks */
ulint curr_size) /* in: current size to use, must be <= ulint curr_size, /* in: current size to use, must be <=
max_size, currently must be equal to max_size, currently must be equal to
max_size */ max_size */
ulint n_frames) /* in: number of frames; if AWE is used,
this is the size of the address space window
where physical memory pages are mapped; if
AWE is not used then this must be the same
as max_size */
{ {
byte* frame; byte* frame;
ulint i; ulint i;
buf_block_t* block; buf_block_t* block;
ut_a(max_size == curr_size); ut_a(max_size == curr_size);
ut_a(srv_use_awe || n_frames == max_size);
if (n_frames > curr_size) {
fprintf(stderr,
"InnoDB: AWE: Error: you must specify in my.cnf .._awe_mem_mb larger\n"
"InnoDB: than .._buffer_pool_size. Now the former is %lu pages,\n"
"InnoDB: the latter %lu pages.\n", curr_size, n_frames);
return(NULL);
}
buf_pool = mem_alloc(sizeof(buf_pool_t)); buf_pool = mem_alloc(sizeof(buf_pool_t));
@ -397,7 +436,37 @@ buf_pool_create(
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
buf_pool->frame_mem = ut_malloc(UNIV_PAGE_SIZE * (max_size + 1)); if (srv_use_awe) {
/*----------------------------------------*/
/* Allocate the virtual address space window, i.e., the
buffer pool frames */
buf_pool->frame_mem = os_awe_allocate_virtual_mem_window(
UNIV_PAGE_SIZE * (n_frames + 1));
/* Allocate the physical memory for AWE and the AWE info array
for buf_pool */
if ((curr_size % ((1024 * 1024) / UNIV_PAGE_SIZE)) != 0) {
fprintf(stderr,
"InnoDB: AWE: Error: physical memory must be allocated in full megabytes.\n"
"InnoDB: Trying to allocate %lu database pages.\n",
curr_size);
return(NULL);
}
if (!os_awe_allocate_physical_mem(&(buf_pool->awe_info),
curr_size / ((1024 * 1024) / UNIV_PAGE_SIZE))) {
return(NULL);
}
/*----------------------------------------*/
} else {
buf_pool->frame_mem = ut_malloc(
UNIV_PAGE_SIZE * (n_frames + 1));
}
if (buf_pool->frame_mem == NULL) { if (buf_pool->frame_mem == NULL) {
@ -414,19 +483,58 @@ buf_pool_create(
buf_pool->max_size = max_size; buf_pool->max_size = max_size;
buf_pool->curr_size = curr_size; buf_pool->curr_size = curr_size;
buf_pool->n_frames = n_frames;
/* Align pointer to the first frame */ /* Align pointer to the first frame */
frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE); frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE);
buf_pool->frame_zero = frame; buf_pool->frame_zero = frame;
buf_pool->high_end = frame + UNIV_PAGE_SIZE * n_frames;
buf_pool->high_end = frame + UNIV_PAGE_SIZE * curr_size; if (srv_use_awe) {
/*----------------------------------------*/
/* Map an initial part of the allocated physical memory to
the window */
os_awe_map_physical_mem_to_window(buf_pool->frame_zero,
n_frames *
(UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE),
buf_pool->awe_info);
/*----------------------------------------*/
}
buf_pool->blocks_of_frames = ut_malloc(sizeof(void*) * n_frames);
if (buf_pool->blocks_of_frames == NULL) {
return(NULL);
}
/* Init block structs and assign frames for them; in the case of
AWE there are less frames than blocks. Then we assign the frames
to the first blocks (we already mapped the memory above). We also
init the awe_info for every block. */
/* Init block structs and assign frames for them */
for (i = 0; i < max_size; i++) { for (i = 0; i < max_size; i++) {
block = buf_pool_get_nth_block(buf_pool, i); block = buf_pool_get_nth_block(buf_pool, i);
if (i < n_frames) {
frame = buf_pool->frame_zero + i * UNIV_PAGE_SIZE;
*(buf_pool->blocks_of_frames + i) = block;
} else {
frame = NULL;
}
buf_block_init(block, frame); buf_block_init(block, frame);
frame = frame + UNIV_PAGE_SIZE;
if (srv_use_awe) {
/*----------------------------------------*/
block->awe_info = buf_pool->awe_info
+ i * (UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE);
/*----------------------------------------*/
}
} }
buf_pool->page_hash = hash_create(2 * max_size); buf_pool->page_hash = hash_create(2 * max_size);
@ -438,12 +546,14 @@ buf_pool_create(
buf_pool->n_pages_read = 0; buf_pool->n_pages_read = 0;
buf_pool->n_pages_written = 0; buf_pool->n_pages_written = 0;
buf_pool->n_pages_created = 0; buf_pool->n_pages_created = 0;
buf_pool->n_pages_awe_remapped = 0;
buf_pool->n_page_gets = 0; buf_pool->n_page_gets = 0;
buf_pool->n_page_gets_old = 0; buf_pool->n_page_gets_old = 0;
buf_pool->n_pages_read_old = 0; buf_pool->n_pages_read_old = 0;
buf_pool->n_pages_written_old = 0; buf_pool->n_pages_written_old = 0;
buf_pool->n_pages_created_old = 0; buf_pool->n_pages_created_old = 0;
buf_pool->n_pages_awe_remapped_old = 0;
/* 2. Initialize flushing fields /* 2. Initialize flushing fields
---------------------------- */ ---------------------------- */
@ -466,40 +576,120 @@ buf_pool_create(
buf_pool->LRU_old = NULL; buf_pool->LRU_old = NULL;
UT_LIST_INIT(buf_pool->awe_LRU_free_mapped);
/* Add control blocks to the free list */ /* Add control blocks to the free list */
UT_LIST_INIT(buf_pool->free); UT_LIST_INIT(buf_pool->free);
for (i = 0; i < curr_size; i++) { for (i = 0; i < curr_size; i++) {
block = buf_pool_get_nth_block(buf_pool, i); block = buf_pool_get_nth_block(buf_pool, i);
/* Wipe contents of page to eliminate a Purify warning */ if (block->frame) {
/* Wipe contents of frame to eliminate a Purify
warning */
memset(block->frame, '\0', UNIV_PAGE_SIZE); memset(block->frame, '\0', UNIV_PAGE_SIZE);
UT_LIST_ADD_FIRST(free, buf_pool->free, block); if (srv_use_awe) {
/* Add to the list of blocks mapped to
frames */
UT_LIST_ADD_LAST(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped, block);
}
}
UT_LIST_ADD_LAST(free, buf_pool->free, block);
} }
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
btr_search_sys_create(curr_size * UNIV_PAGE_SIZE / sizeof(void*) / 64); if (srv_use_adaptive_hash_indexes) {
btr_search_sys_create(
curr_size * UNIV_PAGE_SIZE / sizeof(void*) / 64);
} else {
/* Create only a small dummy system */
btr_search_sys_create(1000);
}
return(buf_pool); return(buf_pool);
} }
/************************************************************************ /************************************************************************
Initializes the buffer buf_pool of the database. */ Maps the page of block to a frame, if not mapped yet. Unmaps some page
from the end of the awe_LRU_free_mapped. */
void void
buf_pool_init( buf_awe_map_page_to_frame(
/*==========*/ /*======================*/
ulint max_size, /* in: maximum size of the buf_pool in blocks */ buf_block_t* block, /* in: block whose page should be
ulint curr_size) /* in: current size to use, must be <= mapped to a frame */
max_size */ ibool add_to_mapped_list) /* in: TRUE if we in the case
we need to map the page should also
add the block to the
awe_LRU_free_mapped list */
{ {
ut_a(buf_pool == NULL); buf_block_t* bck;
buf_pool_create(max_size, curr_size); ut_ad(mutex_own(&(buf_pool->mutex)));
ut_ad(block);
ut_ad(buf_validate()); if (block->frame) {
return;
}
/* Scan awe_LRU_free_mapped from the end and try to find a block
which is not bufferfixed or io-fixed */
bck = UT_LIST_GET_LAST(buf_pool->awe_LRU_free_mapped);
while (bck) {
if (bck->state == BUF_BLOCK_FILE_PAGE
&& (bck->buf_fix_count != 0 || bck->io_fix != 0)) {
/* We have to skip this */
bck = UT_LIST_GET_PREV(awe_LRU_free_mapped, bck);
} else {
/* We can map block to the frame of bck */
os_awe_map_physical_mem_to_window(
bck->frame,
UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE,
block->awe_info);
block->frame = bck->frame;
*(buf_pool->blocks_of_frames
+ (((ulint)(block->frame
- buf_pool->frame_zero))
>> UNIV_PAGE_SIZE_SHIFT))
= block;
bck->frame = NULL;
UT_LIST_REMOVE(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped,
bck);
if (add_to_mapped_list) {
UT_LIST_ADD_FIRST(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped,
block);
}
buf_pool->n_pages_awe_remapped++;
return;
}
}
fprintf(stderr,
"InnoDB: AWE: Fatal error: cannot find a page to unmap\n"
"InnoDB: awe_LRU_free_mapped list length %lu\n",
UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
ut_a(0);
} }
/************************************************************************ /************************************************************************
@ -508,7 +698,9 @@ UNIV_INLINE
buf_block_t* buf_block_t*
buf_block_alloc(void) buf_block_alloc(void)
/*=================*/ /*=================*/
/* out, own: the allocated block */ /* out, own: the allocated block; also if AWE
is used it is guaranteed that the page is
mapped to a frame */
{ {
buf_block_t* block; buf_block_t* block;
@ -846,6 +1038,19 @@ loop:
} }
} }
/* If AWE is enabled and the page is not mapped to a frame, then
map it */
if (block->frame == NULL) {
ut_a(srv_use_awe);
/* We set second parameter TRUE because the block is in the
LRU list and we must put it to awe_LRU_free_mapped list once
mapped to a frame */
buf_awe_map_page_to_frame(block, TRUE);
}
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
buf_block_buf_fix_inc_debug(block, file, line); buf_block_buf_fix_inc_debug(block, file, line);
#else #else
@ -900,8 +1105,26 @@ loop:
} else if (rw_latch == RW_NO_LATCH) { } else if (rw_latch == RW_NO_LATCH) {
if (must_read) { if (must_read) {
rw_lock_x_lock(&(block->read_lock)); /* Let us wait until the read operation
rw_lock_x_unlock(&(block->read_lock)); completes */
for (;;) {
mutex_enter(&(buf_pool->mutex));
if (block->io_fix == BUF_IO_READ) {
mutex_exit(&(buf_pool->mutex));
/* Sleep 20 milliseconds */
os_thread_sleep(20000);
} else {
mutex_exit(&(buf_pool->mutex));
break;
}
}
} }
fix_type = MTR_MEMO_BUF_FIX; fix_type = MTR_MEMO_BUF_FIX;
@ -940,28 +1163,27 @@ buf_page_optimistic_get_func(
/*=========================*/ /*=========================*/
/* out: TRUE if success */ /* out: TRUE if success */
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */ ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
buf_frame_t* guess, /* in: guessed frame */ buf_block_t* block, /* in: guessed buffer block */
buf_frame_t* guess, /* in: guessed frame; note that AWE may move
frames */
dulint modify_clock,/* in: modify clock value if mode is dulint modify_clock,/* in: modify clock value if mode is
..._GUESS_ON_CLOCK */ ..._GUESS_ON_CLOCK */
char* file, /* in: file name */ char* file, /* in: file name */
ulint line, /* in: line where called */ ulint line, /* in: line where called */
mtr_t* mtr) /* in: mini-transaction */ mtr_t* mtr) /* in: mini-transaction */
{ {
buf_block_t* block;
ibool accessed; ibool accessed;
ibool success; ibool success;
ulint fix_type; ulint fix_type;
ut_ad(mtr && guess); ut_ad(mtr && block);
ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
buf_pool->n_page_gets++;
block = buf_block_align(guess);
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
if (block->state != BUF_BLOCK_FILE_PAGE) { /* If AWE is used, block may have a different frame now, e.g., NULL */
if (block->state != BUF_BLOCK_FILE_PAGE || block->frame != guess) {
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
@ -1054,12 +1276,15 @@ buf_page_optimistic_get_func(
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
ut_a(ibuf_count_get(block->space, block->offset) == 0); ut_a(ibuf_count_get(block->space, block->offset) == 0);
#endif #endif
buf_pool->n_page_gets++;
return(TRUE); return(TRUE);
} }
/************************************************************************ /************************************************************************
This is used to get access to a known database page, when no waiting can be This is used to get access to a known database page, when no waiting can be
done. */ done. For example, if a search in an adaptive hash index leads us to this
frame. */
ibool ibool
buf_page_get_known_nowait( buf_page_get_known_nowait(
@ -1079,12 +1304,10 @@ buf_page_get_known_nowait(
ut_ad(mtr); ut_ad(mtr);
ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
buf_pool->n_page_gets++; mutex_enter(&(buf_pool->mutex));
block = buf_block_align(guess); block = buf_block_align(guess);
mutex_enter(&(buf_pool->mutex));
if (block->state == BUF_BLOCK_REMOVE_HASH) { if (block->state == BUF_BLOCK_REMOVE_HASH) {
/* Another thread is just freeing the block from the LRU list /* Another thread is just freeing the block from the LRU list
of the buffer pool: do not try to access this page; this of the buffer pool: do not try to access this page; this
@ -1152,6 +1375,8 @@ buf_page_get_known_nowait(
ut_a((mode == BUF_KEEP_OLD) ut_a((mode == BUF_KEEP_OLD)
|| (ibuf_count_get(block->space, block->offset) == 0)); || (ibuf_count_get(block->space, block->offset) == 0));
#endif #endif
buf_pool->n_page_gets++;
return(TRUE); return(TRUE);
} }
@ -1323,8 +1548,6 @@ buf_page_init_for_read(
rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ); rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ);
rw_lock_x_lock_gen(&(block->read_lock), BUF_IO_READ);
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
if (mode == BUF_READ_IBUF_PAGES_ONLY) { if (mode == BUF_READ_IBUF_PAGES_ONLY) {
@ -1546,9 +1769,7 @@ buf_page_io_complete(
buf_pool->n_pend_reads--; buf_pool->n_pend_reads--;
buf_pool->n_pages_read++; buf_pool->n_pages_read++;
rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ); rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ);
rw_lock_x_unlock_gen(&(block->read_lock), BUF_IO_READ);
if (buf_debug_prints) { if (buf_debug_prints) {
printf("Has read "); printf("Has read ");
@ -1732,7 +1953,7 @@ buf_print(void)
ut_ad(buf_pool); ut_ad(buf_pool);
size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE; size = buf_pool->curr_size;
index_ids = mem_alloc(sizeof(dulint) * size); index_ids = mem_alloc(sizeof(dulint) * size);
counts = mem_alloc(sizeof(ulint) * size); counts = mem_alloc(sizeof(ulint) * size);
@ -1847,7 +2068,7 @@ buf_print_io(
return; return;
} }
size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE; size = buf_pool->curr_size;
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
@ -1866,6 +2087,15 @@ buf_print_io(
buf += sprintf(buf, buf += sprintf(buf,
"Modified db pages %lu\n", "Modified db pages %lu\n",
UT_LIST_GET_LEN(buf_pool->flush_list)); UT_LIST_GET_LEN(buf_pool->flush_list));
if (srv_use_awe) {
buf += sprintf(buf,
"AWE: Buffer pool memory frames %lu\n",
buf_pool->n_frames);
buf += sprintf(buf,
"AWE: Database pages and free buffers mapped in frames %lu\n",
UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
}
buf += sprintf(buf, "Pending reads %lu \n", buf_pool->n_pend_reads); buf += sprintf(buf, "Pending reads %lu \n", buf_pool->n_pend_reads);
@ -1891,6 +2121,13 @@ buf_print_io(
(buf_pool->n_pages_written - buf_pool->n_pages_written_old) (buf_pool->n_pages_written - buf_pool->n_pages_written_old)
/ time_elapsed); / time_elapsed);
if (srv_use_awe) {
buf += sprintf(buf, "AWE: %.2f page remaps/s\n",
(buf_pool->n_pages_awe_remapped
- buf_pool->n_pages_awe_remapped_old)
/ time_elapsed);
}
if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) { if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
buf += sprintf(buf, "Buffer pool hit rate %lu / 1000\n", buf += sprintf(buf, "Buffer pool hit rate %lu / 1000\n",
1000 1000
@ -1906,6 +2143,7 @@ buf_print_io(
buf_pool->n_pages_read_old = buf_pool->n_pages_read; buf_pool->n_pages_read_old = buf_pool->n_pages_read;
buf_pool->n_pages_created_old = buf_pool->n_pages_created; buf_pool->n_pages_created_old = buf_pool->n_pages_created;
buf_pool->n_pages_written_old = buf_pool->n_pages_written; buf_pool->n_pages_written_old = buf_pool->n_pages_written;
buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
} }
@ -1922,6 +2160,7 @@ buf_refresh_io_stats(void)
buf_pool->n_pages_read_old = buf_pool->n_pages_read; buf_pool->n_pages_read_old = buf_pool->n_pages_read;
buf_pool->n_pages_created_old = buf_pool->n_pages_created; buf_pool->n_pages_created_old = buf_pool->n_pages_created;
buf_pool->n_pages_written_old = buf_pool->n_pages_written; buf_pool->n_pages_written_old = buf_pool->n_pages_written;
buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
} }
/************************************************************************* /*************************************************************************

View File

@ -24,6 +24,7 @@ Created 11/11/1995 Heikki Tuuri
#include "log0log.h" #include "log0log.h"
#include "os0file.h" #include "os0file.h"
#include "trx0sys.h" #include "trx0sys.h"
#include "srv0srv.h"
/* When flushed, dirty blocks are searched in neigborhoods of this size, and /* When flushed, dirty blocks are searched in neigborhoods of this size, and
flushed along with the original page. */ flushed along with the original page. */
@ -134,7 +135,6 @@ buf_flush_ready_for_flush(
if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0) if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
&& (block->io_fix == 0)) { && (block->io_fix == 0)) {
if (flush_type != BUF_FLUSH_LRU) { if (flush_type != BUF_FLUSH_LRU) {
return(TRUE); return(TRUE);
@ -436,6 +436,20 @@ buf_flush_try_page(
&& block && buf_flush_ready_for_flush(block, flush_type)) { && block && buf_flush_ready_for_flush(block, flush_type)) {
block->io_fix = BUF_IO_WRITE; block->io_fix = BUF_IO_WRITE;
/* If AWE is enabled and the page is not mapped to a frame,
then map it */
if (block->frame == NULL) {
ut_a(srv_use_awe);
/* We set second parameter TRUE because the block is
in the LRU list and we must put it to
awe_LRU_free_mapped list once mapped to a frame */
buf_awe_map_page_to_frame(block, TRUE);
}
block->flush_type = flush_type; block->flush_type = flush_type;
if (buf_pool->n_flush[flush_type] == 0) { if (buf_pool->n_flush[flush_type] == 0) {
@ -486,6 +500,20 @@ buf_flush_try_page(
..._ready_for_flush). */ ..._ready_for_flush). */
block->io_fix = BUF_IO_WRITE; block->io_fix = BUF_IO_WRITE;
/* If AWE is enabled and the page is not mapped to a frame,
then map it */
if (block->frame == NULL) {
ut_a(srv_use_awe);
/* We set second parameter TRUE because the block is
in the LRU list and we must put it to
awe_LRU_free_mapped list once mapped to a frame */
buf_awe_map_page_to_frame(block, TRUE);
}
block->flush_type = flush_type; block->flush_type = flush_type;
if (buf_pool->n_flush[flush_type] == 0) { if (buf_pool->n_flush[flush_type] == 0) {
@ -511,6 +539,20 @@ buf_flush_try_page(
&& buf_flush_ready_for_flush(block, flush_type)) { && buf_flush_ready_for_flush(block, flush_type)) {
block->io_fix = BUF_IO_WRITE; block->io_fix = BUF_IO_WRITE;
/* If AWE is enabled and the page is not mapped to a frame,
then map it */
if (block->frame == NULL) {
ut_a(srv_use_awe);
/* We set second parameter TRUE because the block is
in the LRU list and we must put it to
awe_LRU_free_mapped list once mapped to a frame */
buf_awe_map_page_to_frame(block, TRUE);
}
block->flush_type = flush_type; block->flush_type = flush_type;
if (buf_pool->n_flush[block->flush_type] == 0) { if (buf_pool->n_flush[block->flush_type] == 0) {

View File

@ -132,7 +132,13 @@ buf_LRU_search_and_free_block(
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
/* Remove possible adaptive hash index built on the
page; in the case of AWE the block may not have a
frame at all */
if (block->frame) {
btr_search_drop_page_hash_index(block->frame); btr_search_drop_page_hash_index(block->frame);
}
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
@ -196,7 +202,9 @@ list. */
buf_block_t* buf_block_t*
buf_LRU_get_free_block(void) buf_LRU_get_free_block(void)
/*========================*/ /*========================*/
/* out: the free control block */ /* out: the free control block; also if AWE is
used, it is guaranteed that the block has its
page mapped to a frame when we return */
{ {
buf_block_t* block = NULL; buf_block_t* block = NULL;
ibool freed; ibool freed;
@ -257,6 +265,22 @@ loop:
block = UT_LIST_GET_FIRST(buf_pool->free); block = UT_LIST_GET_FIRST(buf_pool->free);
UT_LIST_REMOVE(free, buf_pool->free, block); UT_LIST_REMOVE(free, buf_pool->free, block);
if (srv_use_awe) {
if (block->frame) {
/* Remove from the list of mapped pages */
UT_LIST_REMOVE(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped, block);
} else {
/* We map the page to a frame; second param
FALSE below because we do not want it to be
added to the awe_LRU_free_mapped list */
buf_awe_map_page_to_frame(block, FALSE);
}
}
block->state = BUF_BLOCK_READY_FOR_USE; block->state = BUF_BLOCK_READY_FOR_USE;
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
@ -429,6 +453,13 @@ buf_LRU_remove_block(
/* Remove the block from the LRU list */ /* Remove the block from the LRU list */
UT_LIST_REMOVE(LRU, buf_pool->LRU, block); UT_LIST_REMOVE(LRU, buf_pool->LRU, block);
if (srv_use_awe && block->frame) {
/* Remove from the list of mapped pages */
UT_LIST_REMOVE(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped, block);
}
/* If the LRU list is so short that LRU_old not defined, return */ /* If the LRU list is so short that LRU_old not defined, return */
if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) { if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
@ -475,6 +506,13 @@ buf_LRU_add_block_to_end_low(
UT_LIST_ADD_LAST(LRU, buf_pool->LRU, block); UT_LIST_ADD_LAST(LRU, buf_pool->LRU, block);
if (srv_use_awe && block->frame) {
/* Add to the list of mapped pages */
UT_LIST_ADD_LAST(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped, block);
}
if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) { if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
buf_pool->LRU_old_len++; buf_pool->LRU_old_len++;
@ -518,6 +556,15 @@ buf_LRU_add_block_low(
block->old = old; block->old = old;
cl = buf_pool_clock_tic(); cl = buf_pool_clock_tic();
if (srv_use_awe && block->frame) {
/* Add to the list of mapped pages; for simplicity we always
add to the start, even if the user would have set 'old'
TRUE */
UT_LIST_ADD_FIRST(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped, block);
}
if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) { if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, block); UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, block);
@ -613,6 +660,13 @@ buf_LRU_block_free_non_file_page(
memset(block->frame, '\0', UNIV_PAGE_SIZE); memset(block->frame, '\0', UNIV_PAGE_SIZE);
#endif #endif
UT_LIST_ADD_FIRST(free, buf_pool->free, block); UT_LIST_ADD_FIRST(free, buf_pool->free, block);
if (srv_use_awe && block->frame) {
/* Add to the list of mapped pages */
UT_LIST_ADD_FIRST(awe_LRU_free_mapped,
buf_pool->awe_LRU_free_mapped, block);
}
} }
/********************************************************************** /**********************************************************************
@ -639,7 +693,9 @@ buf_LRU_block_remove_hashed_page(
buf_pool->freed_page_clock += 1; buf_pool->freed_page_clock += 1;
buf_frame_modify_clock_inc(block->frame); /* Note that if AWE is enabled the block may not have a frame at all */
buf_block_modify_clock_inc(block);
HASH_DELETE(buf_block_t, hash, buf_pool->page_hash, HASH_DELETE(buf_block_t, hash, buf_pool->page_hash,
buf_page_address_fold(block->space, block->offset), buf_page_address_fold(block->space, block->offset),

View File

@ -576,7 +576,7 @@ buf_read_recv_pages(
os_aio_print_debug = FALSE; os_aio_print_debug = FALSE;
while (buf_pool->n_pend_reads >= RECV_POOL_N_FREE_BLOCKS / 2) { while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) {
os_aio_simulated_wake_handler_threads(); os_aio_simulated_wake_handler_threads();
os_thread_sleep(500000); os_thread_sleep(500000);

View File

@ -1113,6 +1113,7 @@ dict_index_add_to_cache(
ulint n_ord; ulint n_ord;
ibool success; ibool success;
ulint i; ulint i;
ulint j;
ut_ad(index); ut_ad(index);
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
@ -1143,6 +1144,28 @@ dict_index_add_to_cache(
return(FALSE); return(FALSE);
} }
/* Check that the same column does not appear twice in the index.
InnoDB assumes this in its algorithms, e.g., update of an index
entry */
for (i = 0; i < dict_index_get_n_fields(index); i++) {
for (j = 0; j < i; j++) {
if (dict_index_get_nth_field(index, j)->col
== dict_index_get_nth_field(index, i)->col) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: column %s appears twice in index %s of table %s\n"
"InnoDB: This is not allowed in InnoDB.\n"
"InnoDB: UPDATE can cause such an index to become corrupt in InnoDB.\n",
dict_index_get_nth_field(index, i)->col->name,
index->name, table->name);
}
}
}
/* Build the cache internal representation of the index, /* Build the cache internal representation of the index,
containing also the added system fields */ containing also the added system fields */
@ -2212,6 +2235,9 @@ dict_create_foreign_constraints(
ulint error; ulint error;
ulint i; ulint i;
ulint j; ulint j;
ibool is_on_delete;
ulint n_on_deletes;
ulint n_on_updates;
dict_col_t* columns[500]; dict_col_t* columns[500];
char* column_names[500]; char* column_names[500];
ulint column_name_lens[500]; ulint column_name_lens[500];
@ -2371,6 +2397,12 @@ col_loop2:
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
n_on_deletes = 0;
n_on_updates = 0;
scan_on_conditions:
/* Loop here as long as we can find ON ... conditions */
ptr = dict_accept(ptr, "ON", &success); ptr = dict_accept(ptr, "ON", &success);
if (!success) { if (!success) {
@ -2381,23 +2413,58 @@ col_loop2:
ptr = dict_accept(ptr, "DELETE", &success); ptr = dict_accept(ptr, "DELETE", &success);
if (!success) { if (!success) {
ptr = dict_accept(ptr, "UPDATE", &success);
if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
is_on_delete = FALSE;
n_on_updates++;
} else {
is_on_delete = TRUE;
n_on_deletes++;
}
ptr = dict_accept(ptr, "RESTRICT", &success); ptr = dict_accept(ptr, "RESTRICT", &success);
if (success) { if (success) {
goto try_find_index; goto scan_on_conditions;
} }
ptr = dict_accept(ptr, "CASCADE", &success); ptr = dict_accept(ptr, "CASCADE", &success);
if (success) { if (success) {
foreign->type = DICT_FOREIGN_ON_DELETE_CASCADE; if (is_on_delete) {
foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
} else {
foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
}
goto try_find_index; goto scan_on_conditions;
}
ptr = dict_accept(ptr, "NO", &success);
if (success) {
ptr = dict_accept(ptr, "ACTION", &success);
if (!success) {
dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT);
}
if (is_on_delete) {
foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
} else {
foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
}
goto scan_on_conditions;
} }
ptr = dict_accept(ptr, "SET", &success); ptr = dict_accept(ptr, "SET", &success);
@ -2430,15 +2497,18 @@ col_loop2:
} }
} }
foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL; if (is_on_delete) {
foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
} else {
foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
}
goto scan_on_conditions;
try_find_index: try_find_index:
/* We check that there are no superfluous words like 'ON UPDATE ...' if (n_on_deletes > 1 || n_on_updates > 1) {
which we do not support yet. */ /* It is an error to define more than 1 action */
ptr = dict_accept(ptr, (char *) "ON", &success);
if (success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
@ -3265,7 +3335,8 @@ dict_print_info_on_foreign_keys_in_create_format(
/*=============================================*/ /*=============================================*/
char* buf, /* in: auxiliary buffer */ char* buf, /* in: auxiliary buffer */
char* str, /* in/out: pointer to a string */ char* str, /* in/out: pointer to a string */
ulint len, /* in: space in str available for info */ ulint len, /* in: str has to be a buffer at least
len + 5000 bytes */
dict_table_t* table) /* in: table */ dict_table_t* table) /* in: table */
{ {
@ -3335,14 +3406,30 @@ dict_print_info_on_foreign_keys_in_create_format(
buf2 += sprintf(buf2, ")"); buf2 += sprintf(buf2, ")");
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) { if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
buf2 += sprintf(buf2, " ON DELETE CASCADE"); buf2 += sprintf(buf2, " ON DELETE CASCADE");
} }
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) { if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
buf2 += sprintf(buf2, " ON DELETE SET NULL"); buf2 += sprintf(buf2, " ON DELETE SET NULL");
} }
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
buf2 += sprintf(buf2, " ON DELETE NO ACTION");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
buf2 += sprintf(buf2, " ON UPDATE CASCADE");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
buf2 += sprintf(buf2, " ON UPDATE SET NULL");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
} }
no_space: no_space:
@ -3434,6 +3521,22 @@ dict_print_info_on_foreign_keys(
buf2 += sprintf(buf2, " ON DELETE SET NULL"); buf2 += sprintf(buf2, " ON DELETE SET NULL");
} }
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
buf2 += sprintf(buf2, " ON DELETE NO ACTION");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
buf2 += sprintf(buf2, " ON UPDATE CASCADE");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
buf2 += sprintf(buf2, " ON UPDATE SET NULL");
}
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign); foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
} }
no_space: no_space:

View File

@ -2479,20 +2479,20 @@ try_again:
n_free = n_free_list_ext + n_free_up; n_free = n_free_list_ext + n_free_up;
if (alloc_type == FSP_NORMAL) { if (alloc_type == FSP_NORMAL) {
/* We reserve 1 extent + 4 % of the space size to undo logs /* We reserve 1 extent + 0.5 % of the space size to undo logs
and 1 extent + 1 % to cleaning operations; NOTE: this source and 1 extent + 0.5 % to cleaning operations; NOTE: this source
code is duplicated in the function below! */ code is duplicated in the function below! */
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 5) / 100; reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
if (n_free <= reserve + n_ext) { if (n_free <= reserve + n_ext) {
goto try_to_extend; goto try_to_extend;
} }
} else if (alloc_type == FSP_UNDO) { } else if (alloc_type == FSP_UNDO) {
/* We reserve 1 % of the space size to cleaning operations */ /* We reserve 0.5 % of the space size to cleaning operations */
reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 100; reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
if (n_free <= reserve + n_ext) { if (n_free <= reserve + n_ext) {
@ -2572,11 +2572,11 @@ fsp_get_available_space_in_free_extents(
n_free = n_free_list_ext + n_free_up; n_free = n_free_list_ext + n_free_up;
/* We reserve 1 extent + 4 % of the space size to undo logs /* We reserve 1 extent + 0.5 % of the space size to undo logs
and 1 extent + 1 % to cleaning operations; NOTE: this source and 1 extent + 0.5 % to cleaning operations; NOTE: this source
code is duplicated in the function above! */ code is duplicated in the function above! */
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 5) / 100; reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
if (reserve > n_free) { if (reserve > n_free) {
return(0); return(0);

View File

@ -2658,9 +2658,6 @@ reset_bit:
} }
} }
ibuf_data->n_merges++;
ibuf_data->n_merged_recs += n_inserts;
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
/* printf("Ibuf merge %lu records volume %lu to page no %lu\n", /* printf("Ibuf merge %lu records volume %lu to page no %lu\n",
n_inserts, volume, page_no); */ n_inserts, volume, page_no); */
@ -2670,6 +2667,14 @@ reset_bit:
mem_heap_free(heap); mem_heap_free(heap);
/* Protect our statistics keeping from race conditions */
mutex_enter(&ibuf_mutex);
ibuf_data->n_merges++;
ibuf_data->n_merged_recs += n_inserts;
mutex_exit(&ibuf_mutex);
ibuf_exit(); ibuf_exit();
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
ut_a(ibuf_count_get(space, page_no) == 0); ut_a(ibuf_count_get(space, page_no) == 0);

View File

@ -466,6 +466,9 @@ struct btr_pcur_struct{
BTR_PCUR_AFTER, depending on whether BTR_PCUR_AFTER, depending on whether
cursor was on, before, or after the cursor was on, before, or after the
old_rec record */ old_rec record */
buf_block_t* block_when_stored;/* buffer block when the position was
stored; note that if AWE is on, frames
may move */
dulint modify_clock; /* the modify clock value of the dulint modify_clock; /* the modify clock value of the
buffer block when the cursor position buffer block when the cursor position
was stored */ was stored */

View File

@ -30,6 +30,7 @@ Created 11/5/1995 Heikki Tuuri
#include "sync0rw.h" #include "sync0rw.h"
#include "hash0hash.h" #include "hash0hash.h"
#include "ut0byte.h" #include "ut0byte.h"
#include "os0proc.h"
/* Flags for flush types */ /* Flags for flush types */
#define BUF_FLUSH_LRU 1 #define BUF_FLUSH_LRU 1
@ -58,23 +59,34 @@ extern ibool buf_debug_prints;/* If this is set TRUE, the program
occurs */ occurs */
/************************************************************************ /************************************************************************
Initializes the buffer pool of the database. */ Creates the buffer pool. */
void buf_pool_t*
buf_pool_init( buf_pool_init(
/*==========*/ /*==========*/
ulint max_size, /* in: maximum size of the pool in blocks */ /* out, own: buf_pool object, NULL if not
ulint curr_size); /* in: current size to use, must be <= enough memory or error */
ulint max_size, /* in: maximum size of the buf_pool in
blocks */
ulint curr_size, /* in: current size to use, must be <=
max_size, currently must be equal to
max_size */ max_size */
ulint n_frames); /* in: number of frames; if AWE is used,
this is the size of the address space window
where physical memory pages are mapped; if
AWE is not used then this must be the same
as max_size */
/************************************************************************* /*************************************************************************
Gets the current size of buffer pool in bytes. */ Gets the current size of buffer buf_pool in bytes. In the case of AWE, the
size of AWE window (= the frames). */
UNIV_INLINE UNIV_INLINE
ulint ulint
buf_pool_get_curr_size(void); buf_pool_get_curr_size(void);
/*========================*/ /*========================*/
/* out: size in bytes */ /* out: size in bytes */
/************************************************************************* /*************************************************************************
Gets the maximum size of buffer pool in bytes. */ Gets the maximum size of buffer pool in bytes. In the case of AWE, the
size of AWE window (= the frames). */
UNIV_INLINE UNIV_INLINE
ulint ulint
buf_pool_get_max_size(void); buf_pool_get_max_size(void);
@ -138,8 +150,8 @@ improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed as LA! */
NOTE! The following macros should be used instead of NOTE! The following macros should be used instead of
buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and
RW_X_LATCH are allowed as LA! */ RW_X_LATCH are allowed as LA! */
#define buf_page_optimistic_get(LA, G, MC, MTR) buf_page_optimistic_get_func(\ #define buf_page_optimistic_get(LA, BL, G, MC, MTR) buf_page_optimistic_get_func(\
LA, G, MC, IB__FILE__, __LINE__, MTR) LA, BL, G, MC, IB__FILE__, __LINE__, MTR)
/************************************************************************ /************************************************************************
This is the general function used to get optimistic access to a database This is the general function used to get optimistic access to a database
page. */ page. */
@ -149,7 +161,9 @@ buf_page_optimistic_get_func(
/*=========================*/ /*=========================*/
/* out: TRUE if success */ /* out: TRUE if success */
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */ ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
buf_frame_t* guess, /* in: guessed frame */ buf_block_t* block, /* in: guessed block */
buf_frame_t* guess, /* in: guessed frame; note that AWE may move
frames */
dulint modify_clock,/* in: modify clock value if mode is dulint modify_clock,/* in: modify clock value if mode is
..._GUESS_ON_CLOCK */ ..._GUESS_ON_CLOCK */
char* file, /* in: file name */ char* file, /* in: file name */
@ -350,6 +364,16 @@ buf_frame_modify_clock_inc(
/* out: new value */ /* out: new value */
buf_frame_t* frame); /* in: pointer to a frame */ buf_frame_t* frame); /* in: pointer to a frame */
/************************************************************************ /************************************************************************
Increments the modify clock of a frame by 1. The caller must (1) own the
buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
on the block. */
UNIV_INLINE
dulint
buf_block_modify_clock_inc(
/*=======================*/
/* out: new value */
buf_block_t* block); /* in: block */
/************************************************************************
Returns the value of the modify clock. The caller must have an s-lock Returns the value of the modify clock. The caller must have an s-lock
or x-lock on the block. */ or x-lock on the block. */
UNIV_INLINE UNIV_INLINE
@ -428,7 +452,7 @@ UNIV_INLINE
buf_frame_t* buf_frame_t*
buf_frame_align( buf_frame_align(
/*============*/ /*============*/
/* out: pointer to block */ /* out: pointer to frame */
byte* ptr); /* in: pointer to a frame */ byte* ptr); /* in: pointer to a frame */
/*********************************************************************** /***********************************************************************
Checks if a pointer points to the block array of the buffer pool (blocks, not Checks if a pointer points to the block array of the buffer pool (blocks, not
@ -505,6 +529,19 @@ buf_pool_invalidate(void);
--------------------------- LOWER LEVEL ROUTINES ------------------------- --------------------------- LOWER LEVEL ROUTINES -------------------------
=========================================================================*/ =========================================================================*/
/************************************************************************
Maps the page of block to a frame, if not mapped yet. Unmaps some page
from the end of the awe_LRU_free_mapped. */
void
buf_awe_map_page_to_frame(
/*======================*/
buf_block_t* block, /* in: block whose page should be
mapped to a frame */
ibool add_to_mapped_list);/* in: TRUE if we in the case
we need to map the page should also
add the block to the
awe_LRU_free_mapped list */
/************************************************************************* /*************************************************************************
Adds latch level info for the rw-lock protecting the buffer frame. This Adds latch level info for the rw-lock protecting the buffer frame. This
should be called in the debug version after a successful latching of a should be called in the debug version after a successful latching of a
@ -638,7 +675,16 @@ struct buf_block_struct{
byte* frame; /* pointer to buffer frame which byte* frame; /* pointer to buffer frame which
is of size UNIV_PAGE_SIZE, and is of size UNIV_PAGE_SIZE, and
aligned to an address divisible by aligned to an address divisible by
UNIV_PAGE_SIZE */ UNIV_PAGE_SIZE; if AWE is used, this
will be NULL for the pages which are
currently not mapped into the virtual
address space window of the buffer
pool */
os_awe_t* awe_info; /* if AWE is used, then an array of
awe page infos for
UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE
(normally = 4) physical memory
pages; otherwise NULL */
ulint space; /* space id of the page */ ulint space; /* space id of the page */
ulint offset; /* page number within the space */ ulint offset; /* page number within the space */
ulint lock_hash_val; /* hashed value of the page address ulint lock_hash_val; /* hashed value of the page address
@ -647,14 +693,6 @@ struct buf_block_struct{
record lock hash table */ record lock hash table */
rw_lock_t lock; /* read-write lock of the buffer rw_lock_t lock; /* read-write lock of the buffer
frame */ frame */
rw_lock_t read_lock; /* rw-lock reserved when a page read
to the frame is requested; a thread
can wait for this rw-lock if it wants
to wait for the read to complete;
the usual way is to wait for lock,
but if the thread just wants a
bufferfix and no latch on the page,
then it can wait for this rw-lock */
buf_block_t* hash; /* node used in chaining to the page buf_block_t* hash; /* node used in chaining to the page
hash table */ hash table */
ibool check_index_page_at_flush; ibool check_index_page_at_flush;
@ -691,6 +729,10 @@ struct buf_block_struct{
/* node of the free block list */ /* node of the free block list */
UT_LIST_NODE_T(buf_block_t) LRU; UT_LIST_NODE_T(buf_block_t) LRU;
/* node of the LRU list */ /* node of the LRU list */
UT_LIST_NODE_T(buf_block_t) awe_LRU_free_mapped;
/* in the AWE version node in the
list of free and LRU blocks which are
mapped to a frame */
ulint LRU_position; /* value which monotonically ulint LRU_position; /* value which monotonically
decreases (or may stay constant if decreases (or may stay constant if
the block is in the old blocks) toward the block is in the old blocks) toward
@ -728,8 +770,8 @@ struct buf_block_struct{
bufferfixed, or (2) the thread has an bufferfixed, or (2) the thread has an
x-latch on the block */ x-latch on the block */
/* 5. Hash search fields: NOTE that these fields are protected by /* 5. Hash search fields: NOTE that the first 4 fields are NOT
btr_search_mutex */ protected by any semaphore! */
ulint n_hash_helps; /* counter which controls building ulint n_hash_helps; /* counter which controls building
of a new hash index for the page */ of a new hash index for the page */
@ -742,6 +784,9 @@ struct buf_block_struct{
whether the leftmost record of several whether the leftmost record of several
records with the same prefix should be records with the same prefix should be
indexed in the hash index */ indexed in the hash index */
/* The following 4 fields are protected by btr_search_latch: */
ibool is_hashed; /* TRUE if hash index has already been ibool is_hashed; /* TRUE if hash index has already been
built on this page; note that it does built on this page; note that it does
not guarantee that the index is not guarantee that the index is
@ -755,11 +800,12 @@ struct buf_block_struct{
BTR_SEARCH_RIGHT_SIDE in hash BTR_SEARCH_RIGHT_SIDE in hash
indexing */ indexing */
/* 6. Debug fields */ /* 6. Debug fields */
#ifdef UNIV_SYNC_DEBUG
rw_lock_t debug_latch; /* in the debug version, each thread rw_lock_t debug_latch; /* in the debug version, each thread
which bufferfixes the block acquires which bufferfixes the block acquires
an s-latch here; so we can use the an s-latch here; so we can use the
debug utilities in sync0rw */ debug utilities in sync0rw */
#endif
ibool file_page_was_freed; ibool file_page_was_freed;
/* this is set to TRUE when fsp /* this is set to TRUE when fsp
frees a page in buffer pool */ frees a page in buffer pool */
@ -778,16 +824,36 @@ struct buf_pool_struct{
struct and control blocks, except the struct and control blocks, except the
read-write lock in them */ read-write lock in them */
byte* frame_mem; /* pointer to the memory area which byte* frame_mem; /* pointer to the memory area which
was allocated for the frames */ was allocated for the frames; in AWE
this is the virtual address space
window where we map pages stored
in physical memory */
byte* frame_zero; /* pointer to the first buffer frame: byte* frame_zero; /* pointer to the first buffer frame:
this may differ from frame_mem, because this may differ from frame_mem, because
this is aligned by the frame size */ this is aligned by the frame size */
byte* high_end; /* pointer to the end of the byte* high_end; /* pointer to the end of the buffer
buffer pool */ frames */
ulint n_frames; /* number of frames */
buf_block_t* blocks; /* array of buffer control blocks */ buf_block_t* blocks; /* array of buffer control blocks */
buf_block_t** blocks_of_frames;/* inverse mapping which can be used
to retrieve the buffer control block
of a frame; this is an array which
lists the blocks of frames in the
order frame_zero,
frame_zero + UNIV_PAGE_SIZE, ...
a control block is always assigned
for each frame, even if the frame does
not contain any data; note that in AWE
there are more control blocks than
buffer frames */
os_awe_t* awe_info; /* if AWE is used, AWE info for the
physical 4 kB memory pages associated
with buffer frames */
ulint max_size; /* number of control blocks == ulint max_size; /* number of control blocks ==
maximum pool size in pages */ maximum pool size in pages */
ulint curr_size; /* current pool size in pages */ ulint curr_size; /* current pool size in pages;
currently always the same as
max_size */
hash_table_t* page_hash; /* hash table of the file pages */ hash_table_t* page_hash; /* hash table of the file pages */
ulint n_pend_reads; /* number of pending read operations */ ulint n_pend_reads; /* number of pending read operations */
@ -799,11 +865,14 @@ struct buf_pool_struct{
ulint n_pages_created;/* number of pages created in the pool ulint n_pages_created;/* number of pages created in the pool
with no read */ with no read */
ulint n_page_gets; /* number of page gets performed; ulint n_page_gets; /* number of page gets performed;
also successful seraches through also successful searches through
the adaptive hash index are the adaptive hash index are
counted as page gets; this field counted as page gets; this field
is NOT protected by the buffer is NOT protected by the buffer
pool mutex */ pool mutex */
ulint n_pages_awe_remapped; /* if AWE is enabled, the
number of remaps of blocks to
buffer frames */
ulint n_page_gets_old;/* n_page_gets when buf_print was ulint n_page_gets_old;/* n_page_gets when buf_print was
last time called: used to calculate last time called: used to calculate
hit rate */ hit rate */
@ -812,6 +881,7 @@ struct buf_pool_struct{
ulint n_pages_written_old;/* number write operations */ ulint n_pages_written_old;/* number write operations */
ulint n_pages_created_old;/* number of pages created in ulint n_pages_created_old;/* number of pages created in
the pool with no read */ the pool with no read */
ulint n_pages_awe_remapped_old;
/* 2. Page flushing algorithm fields */ /* 2. Page flushing algorithm fields */
UT_LIST_BASE_NODE_T(buf_block_t) flush_list; UT_LIST_BASE_NODE_T(buf_block_t) flush_list;
@ -844,7 +914,10 @@ struct buf_pool_struct{
/* 3. LRU replacement algorithm fields */ /* 3. LRU replacement algorithm fields */
UT_LIST_BASE_NODE_T(buf_block_t) free; UT_LIST_BASE_NODE_T(buf_block_t) free;
/* base node of the free block list */ /* base node of the free block list;
in the case of AWE, at the start are
always free blocks for which the
physical memory is mapped to a frame */
UT_LIST_BASE_NODE_T(buf_block_t) LRU; UT_LIST_BASE_NODE_T(buf_block_t) LRU;
/* base node of the LRU list */ /* base node of the LRU list */
buf_block_t* LRU_old; /* pointer to the about 3/8 oldest buf_block_t* LRU_old; /* pointer to the about 3/8 oldest
@ -856,6 +929,12 @@ struct buf_pool_struct{
see buf0lru.c for the restrictions see buf0lru.c for the restrictions
on this value; not defined if on this value; not defined if
LRU_old == NULL */ LRU_old == NULL */
UT_LIST_BASE_NODE_T(buf_block_t) awe_LRU_free_mapped;
/* list of those blocks which are
in the LRU list or the free list, and
where the page is mapped to a frame;
thus, frames allocated, e.g., to the
locki table, are not in this list */
}; };
/* States of a control block */ /* States of a control block */

View File

@ -36,25 +36,27 @@ buf_block_peek_if_too_old(
} }
/************************************************************************* /*************************************************************************
Gets the current size of buffer buf_pool in bytes. */ Gets the current size of buffer buf_pool in bytes. In the case of AWE, the
size of AWE window (= the frames). */
UNIV_INLINE UNIV_INLINE
ulint ulint
buf_pool_get_curr_size(void) buf_pool_get_curr_size(void)
/*========================*/ /*========================*/
/* out: size in bytes */ /* out: size in bytes */
{ {
return((buf_pool->curr_size) * UNIV_PAGE_SIZE); return((buf_pool->n_frames) * UNIV_PAGE_SIZE);
} }
/************************************************************************* /*************************************************************************
Gets the maximum size of buffer buf_pool in bytes. */ Gets the maximum size of buffer buf_pool in bytes. In the case of AWE, the
size of AWE window (= the frames). */
UNIV_INLINE UNIV_INLINE
ulint ulint
buf_pool_get_max_size(void) buf_pool_get_max_size(void)
/*=======================*/ /*=======================*/
/* out: size in bytes */ /* out: size in bytes */
{ {
return((buf_pool->max_size) * UNIV_PAGE_SIZE); return((buf_pool->n_frames) * UNIV_PAGE_SIZE);
} }
/*********************************************************************** /***********************************************************************
@ -207,54 +209,24 @@ buf_block_align(
frame_zero = buf_pool->frame_zero; frame_zero = buf_pool->frame_zero;
ut_ad((ulint)ptr >= (ulint)frame_zero); if ((ulint)ptr < (ulint)frame_zero
|| (ulint)ptr > (ulint)(buf_pool->high_end)) {
block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero))
>> UNIV_PAGE_SIZE_SHIFT);
if (block < buf_pool->blocks
|| block >= buf_pool->blocks + buf_pool->max_size) {
ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
" InnoDB: Error: trying to access a stray pointer %lx\n" " InnoDB: Error: trying to access a stray pointer %lx\n"
"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr, "InnoDB: buf pool start is at %lx, end at %lx\n"
(ulint)frame_zero, buf_pool->max_size); "InnoDB: Probable reason is database corruption or memory\n"
ut_a(0); "InnoDB: corruption. If this happens in an InnoDB database recovery,\n"
} "InnoDB: you can look from section 6.1 at http://www.innodb.com/ibman.html\n"
"InnoDB: how to force recovery.\n",
return(block); (ulint)ptr, (ulint)frame_zero,
} (ulint)(buf_pool->high_end));
/***********************************************************************
Gets the block to whose frame the pointer is pointing to. Does not
require a file page to be bufferfixed. */
UNIV_INLINE
buf_block_t*
buf_block_align_low(
/*================*/
/* out: pointer to block */
byte* ptr) /* in: pointer to a frame */
{
buf_block_t* block;
buf_frame_t* frame_zero;
ut_ad(ptr);
frame_zero = buf_pool->frame_zero;
ut_ad((ulint)ptr >= (ulint)frame_zero);
block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero))
>> UNIV_PAGE_SIZE_SHIFT);
if (block < buf_pool->blocks
|| block >= buf_pool->blocks + buf_pool->max_size) {
fprintf(stderr,
"InnoDB: Error: trying to access a stray pointer %lx\n"
"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr,
(ulint)frame_zero, buf_pool->max_size);
ut_a(0); ut_a(0);
} }
block = *(buf_pool->blocks_of_frames + (((ulint)(ptr - frame_zero))
>> UNIV_PAGE_SIZE_SHIFT));
return(block); return(block);
} }
@ -264,7 +236,7 @@ UNIV_INLINE
buf_frame_t* buf_frame_t*
buf_frame_align( buf_frame_align(
/*============*/ /*============*/
/* out: pointer to block */ /* out: pointer to frame */
byte* ptr) /* in: pointer to a frame */ byte* ptr) /* in: pointer to a frame */
{ {
buf_frame_t* frame; buf_frame_t* frame;
@ -273,14 +245,19 @@ buf_frame_align(
frame = ut_align_down(ptr, UNIV_PAGE_SIZE); frame = ut_align_down(ptr, UNIV_PAGE_SIZE);
if (((ulint)frame if (((ulint)frame < (ulint)(buf_pool->frame_zero))
< (ulint)(buf_pool->frame_zero)) || (ulint)frame >= (ulint)(buf_pool->high_end)) {
|| ((ulint)frame > (ulint)(buf_pool_get_nth_block(buf_pool,
buf_pool->max_size - 1)->frame))) { ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
" InnoDB: Error: trying to access a stray pointer %lx\n" " InnoDB: Error: trying to access a stray pointer %lx\n"
"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr, "InnoDB: buf pool start is at %lx, end at %lx\n"
(ulint)(buf_pool->frame_zero), buf_pool->max_size); "InnoDB: Probable reason is database corruption or memory\n"
"InnoDB: corruption. If this happens in an InnoDB database recovery,\n"
"InnoDB: you can look from section 6.1 at http://www.innodb.com/ibman.html\n"
"InnoDB: how to force recovery.\n",
(ulint)ptr, (ulint)(buf_pool->frame_zero),
(ulint)(buf_pool->high_end));
ut_a(0); ut_a(0);
} }
@ -469,7 +446,7 @@ buf_frame_modify_clock_inc(
ut_ad(frame); ut_ad(frame);
block = buf_block_align_low(frame); block = buf_block_align(frame);
ut_ad((mutex_own(&(buf_pool->mutex)) && (block->buf_fix_count == 0)) ut_ad((mutex_own(&(buf_pool->mutex)) && (block->buf_fix_count == 0))
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE)); || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
@ -479,6 +456,25 @@ buf_frame_modify_clock_inc(
return(block->modify_clock); return(block->modify_clock);
} }
/************************************************************************
Increments the modify clock of a frame by 1. The caller must (1) own the
buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
on the block. */
UNIV_INLINE
dulint
buf_block_modify_clock_inc(
/*=======================*/
/* out: new value */
buf_block_t* block) /* in: block */
{
ut_ad((mutex_own(&(buf_pool->mutex)) && (block->buf_fix_count == 0))
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
UT_DULINT_INC(block->modify_clock);
return(block->modify_clock);
}
/************************************************************************ /************************************************************************
Returns the value of the modify clock. The caller must have an s-lock Returns the value of the modify clock. The caller must have an s-lock
or x-lock on the block. */ or x-lock on the block. */
@ -508,15 +504,16 @@ void
buf_block_buf_fix_inc_debug( buf_block_buf_fix_inc_debug(
/*========================*/ /*========================*/
buf_block_t* block, /* in: block to bufferfix */ buf_block_t* block, /* in: block to bufferfix */
char* file, /* in: file name */ char* file __attribute__ ((unused)), /* in: file name */
ulint line) /* in: line */ ulint line __attribute__ ((unused))) /* in: line */
{ {
#ifdef UNIV_SYNC_DEBUG
ibool ret; ibool ret;
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line); ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line);
ut_ad(ret == TRUE); ut_ad(ret == TRUE);
#endif
block->buf_fix_count++; block->buf_fix_count++;
} }

View File

@ -53,7 +53,9 @@ LRU list to the free list. */
buf_block_t* buf_block_t*
buf_LRU_get_free_block(void); buf_LRU_get_free_block(void);
/*=========================*/ /*=========================*/
/* out: the free control block */ /* out: the free control block; also if AWE is
used, it is guaranteed that the block has its
page mapped to a frame when we return */
/********************************************************************** /**********************************************************************
Puts a block back to the free list. */ Puts a block back to the free list. */

View File

@ -42,6 +42,8 @@ Created 5/24/1996 Heikki Tuuri
#define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint #define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint
to a table failed */ to a table failed */
#define DB_CORRUPTION 39 /* data structure corruption noticed */ #define DB_CORRUPTION 39 /* data structure corruption noticed */
#define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index
where same column appears twice */
/* The following are partial failure codes */ /* The following are partial failure codes */
#define DB_FAIL 1000 #define DB_FAIL 1000

View File

@ -280,8 +280,15 @@ struct dict_foreign_struct{
table */ table */
}; };
/* The flags for ON_UPDATE and ON_DELETE can be ORed; the default is that
a foreign key constraint is enforced, therefore RESTRICT just means no flag */
#define DICT_FOREIGN_ON_DELETE_CASCADE 1 #define DICT_FOREIGN_ON_DELETE_CASCADE 1
#define DICT_FOREIGN_ON_DELETE_SET_NULL 2 #define DICT_FOREIGN_ON_DELETE_SET_NULL 2
#define DICT_FOREIGN_ON_UPDATE_CASCADE 4
#define DICT_FOREIGN_ON_UPDATE_SET_NULL 8
#define DICT_FOREIGN_ON_DELETE_NO_ACTION 16
#define DICT_FOREIGN_ON_UPDATE_NO_ACTION 32
#define DICT_INDEX_MAGIC_N 76789786 #define DICT_INDEX_MAGIC_N 76789786

View File

@ -355,12 +355,7 @@ in the debug version: spaces with an odd number as the id are replicate
spaces */ spaces */
#define RECV_REPLICA_SPACE_ADD 1 #define RECV_REPLICA_SPACE_ADD 1
/* This many blocks must be left free in the buffer pool when we scan extern ulint recv_n_pool_free_frames;
the log and store the scanned log records in the buffer pool: we will
use these free blocks to read in pages when we start applying the
log records to the database. */
#define RECV_POOL_N_FREE_BLOCKS (ut_min(256, buf_pool_get_curr_size() / 8))
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "log0recv.ic" #include "log0recv.ic"

View File

@ -127,16 +127,18 @@ mem_heap_create_func(
ulint line /* in: line where created */ ulint line /* in: line where created */
); );
/********************************************************************* /*********************************************************************
NOTE: Use the corresponding macro instead of this function. NOTE: Use the corresponding macro instead of this function. Frees the space
Frees the space occupied by a memory heap. */ occupied by a memory heap. In the debug version erases the heap memory
blocks. */
UNIV_INLINE UNIV_INLINE
void void
mem_heap_free_func( mem_heap_free_func(
/*===============*/ /*===============*/
mem_heap_t* heap, /* in, own: heap to be freed */ mem_heap_t* heap, /* in, own: heap to be freed */
char* file_name, /* in: file name where freed */ char* file_name __attribute__((unused)),
ulint line /* in: line where freed */ /* in: file name where freed */
); ulint line __attribute__((unused)));
/* in: line where freed */
/******************************************************************* /*******************************************************************
Allocates n bytes of memory from a memory heap. */ Allocates n bytes of memory from a memory heap. */
UNIV_INLINE UNIV_INLINE

View File

@ -440,9 +440,10 @@ void
mem_heap_free_func( mem_heap_free_func(
/*===============*/ /*===============*/
mem_heap_t* heap, /* in, own: heap to be freed */ mem_heap_t* heap, /* in, own: heap to be freed */
char* file_name, /* in: file name where freed */ char* file_name __attribute__((unused)),
ulint line /* in: line where freed */ /* in: file name where freed */
) ulint line __attribute__((unused)))
/* in: line where freed */
{ {
mem_block_t* block; mem_block_t* block;
mem_block_t* prev_block; mem_block_t* prev_block;

View File

@ -19,6 +19,8 @@ typedef struct mem_pool_struct mem_pool_t;
/* The common memory pool */ /* The common memory pool */
extern mem_pool_t* mem_comm_pool; extern mem_pool_t* mem_comm_pool;
extern ulint mem_out_of_mem_err_msg_count;
/* Memory area header */ /* Memory area header */
struct mem_area_struct{ struct mem_area_struct{

View File

@ -15,6 +15,76 @@ Created 9/30/1995 Heikki Tuuri
typedef void* os_process_t; typedef void* os_process_t;
typedef unsigned long int os_process_id_t; typedef unsigned long int os_process_id_t;
/* The cell type in os_awe_allocate_mem page info */
#ifdef __NT__
typedef ULONG_PTR os_awe_t;
#else
typedef ulint os_awe_t;
#endif
/* Physical page size when Windows AWE is used. This is the normal
page size of an Intel x86 processor. We cannot use AWE with 2 MB or 4 MB
pages. */
#define OS_AWE_X86_PAGE_SIZE 4096
/********************************************************************
Windows AWE support. Tries to enable the "lock pages in memory" privilege for
the current process so that the current process can allocate memory-locked
virtual address space to act as the window where AWE maps physical memory. */
ibool
os_awe_enable_lock_pages_in_mem(void);
/*=================================*/
/* out: TRUE if success, FALSE if error;
prints error info to stderr if no success */
/********************************************************************
Allocates physical RAM memory up to 64 GB in an Intel 32-bit x86
processor. */
ibool
os_awe_allocate_physical_mem(
/*=========================*/
/* out: TRUE if success */
os_awe_t** page_info, /* out, own: array of opaque data containing
the info for allocated physical memory pages;
each allocated 4 kB physical memory page has
one slot of type os_awe_t in the array */
ulint n_megabytes); /* in: number of megabytes to allocate */
/********************************************************************
Allocates a window in the virtual address space where we can map then
pages of physical memory. */
byte*
os_awe_allocate_virtual_mem_window(
/*===============================*/
/* out, own: allocated memory, or NULL if did not
succeed */
ulint size); /* in: virtual memory allocation size in bytes, must
be < 2 GB */
/********************************************************************
With this function you can map parts of physical memory allocated with
the ..._allocate_physical_mem to the virtual address space allocated with
the previous function. Intel implements this so that the process page
tables are updated accordingly. A test on a 1.5 GHz AMD processor and XP
showed that this takes < 1 microsecond, much better than the estimated 80 us
for copying a 16 kB page memory to memory. But, the operation will at least
partially invalidate the translation lookaside buffer (TLB) of all
processors. Under a real-world load the performance hit may be bigger. */
ibool
os_awe_map_physical_mem_to_window(
/*==============================*/
/* out: TRUE if success; the function
calls exit(1) in case of an error */
byte* ptr, /* in: a page-aligned pointer to
somewhere in the virtual address
space window; we map the physical mem
pages here */
ulint n_mem_pages, /* in: number of 4 kB mem pages to
map */
os_awe_t* page_info); /* in: array of page infos for those
pages; each page has one slot in the
array */
/******************************************************************** /********************************************************************
Converts the current process id to a number. It is not guaranteed that the Converts the current process id to a number. It is not guaranteed that the
number is unique. In Linux returns the 'process number' of the current number is unique. In Linux returns the 'process number' of the current

View File

@ -52,6 +52,14 @@ row_mysql_read_var_ref_noninline(
ulint* len, /* out: variable-length field length */ ulint* len, /* out: variable-length field length */
byte* field); /* in: field */ byte* field); /* in: field */
/*********************************************************************** /***********************************************************************
Frees the blob heap in prebuilt when no longer needed. */
void
row_mysql_prebuilt_free_blob_heap(
/*==============================*/
row_prebuilt_t* prebuilt); /* in: prebuilt struct of a
ha_innobase:: table handle */
/***********************************************************************
Stores a reference to a BLOB in the MySQL format. */ Stores a reference to a BLOB in the MySQL format. */
void void
@ -492,7 +500,11 @@ struct row_prebuilt_struct {
fetch many rows from the same cursor: fetch many rows from the same cursor:
it saves CPU time to fetch them in a it saves CPU time to fetch them in a
batch; we reserve mysql_row_len batch; we reserve mysql_row_len
bytes for each such row */ bytes for each such row; these
pointers point 4 bytes past the
allocated mem buf start, because
there is a 4 byte magic number at the
start and at the end */
ulint fetch_cache_first;/* position of the first not yet ulint fetch_cache_first;/* position of the first not yet
fetched row in fetch_cache */ fetched row in fetch_cache */
ulint n_fetch_cached; /* number of not yet fetched rows ulint n_fetch_cached; /* number of not yet fetched rows
@ -501,8 +513,12 @@ struct row_prebuilt_struct {
to this heap */ to this heap */
mem_heap_t* old_vers_heap; /* memory heap where a previous mem_heap_t* old_vers_heap; /* memory heap where a previous
version is built in consistent read */ version is built in consistent read */
ulint magic_n2; /* this should be the same as
magic_n */
}; };
#define ROW_PREBUILT_FETCH_MAGIC_N 465765687
#define ROW_MYSQL_WHOLE_ROW 0 #define ROW_MYSQL_WHOLE_ROW 0
#define ROW_MYSQL_REC_FIELDS 1 #define ROW_MYSQL_REC_FIELDS 1
#define ROW_MYSQL_NO_TEMPLATE 2 #define ROW_MYSQL_NO_TEMPLATE 2

View File

@ -115,7 +115,8 @@ row_search_for_mysql(
/*=================*/ /*=================*/
/* out: DB_SUCCESS, /* out: DB_SUCCESS,
DB_RECORD_NOT_FOUND, DB_RECORD_NOT_FOUND,
DB_END_OF_INDEX, or DB_DEADLOCK */ DB_END_OF_INDEX, DB_DEADLOCK,
or DB_TOO_BIG_RECORD */
byte* buf, /* in/out: buffer for the fetched byte* buf, /* in/out: buffer for the fetched
row in the MySQL format */ row in the MySQL format */
ulint mode, /* in: search mode PAGE_CUR_L, ... */ ulint mode, /* in: search mode PAGE_CUR_L, ... */

View File

@ -312,8 +312,11 @@ struct upd_node_struct{
ibool in_mysql_interface; ibool in_mysql_interface;
/* TRUE if the update node was created /* TRUE if the update node was created
for the MySQL interface */ for the MySQL interface */
dict_foreign_t* foreign;/* NULL or pointer to a foreign key
constraint if this update node is used in
doing an ON DELETE or ON UPDATE operation */
upd_node_t* cascade_node;/* NULL or an update node template which upd_node_t* cascade_node;/* NULL or an update node template which
is used to implement ON DELETE CASCADE is used to implement ON DELETE/UPDATE CASCADE
or ... SET NULL for foreign keys */ or ... SET NULL for foreign keys */
mem_heap_t* cascade_heap;/* NULL or a mem heap where the cascade mem_heap_t* cascade_heap;/* NULL or a mem heap where the cascade
node is created */ node is created */

View File

@ -61,6 +61,7 @@ extern ulint srv_flush_log_at_trx_commit;
extern byte srv_latin1_ordering[256];/* The sort order table of the latin1 extern byte srv_latin1_ordering[256];/* The sort order table of the latin1
character set */ character set */
extern ulint srv_pool_size; extern ulint srv_pool_size;
extern ulint srv_awe_window_size;
extern ulint srv_mem_pool_size; extern ulint srv_mem_pool_size;
extern ulint srv_lock_table_size; extern ulint srv_lock_table_size;
@ -86,6 +87,8 @@ extern ibool srv_use_doublewrite_buf;
extern ibool srv_set_thread_priorities; extern ibool srv_set_thread_priorities;
extern int srv_query_thread_priority; extern int srv_query_thread_priority;
extern ibool srv_use_awe;
extern ibool srv_use_adaptive_hash_indexes;
/*-------------------------------------------*/ /*-------------------------------------------*/
extern ulint srv_n_rows_inserted; extern ulint srv_n_rows_inserted;

View File

@ -9,7 +9,8 @@ Created 1/20/1994 Heikki Tuuri
#ifndef univ_i #ifndef univ_i
#define univ_i #define univ_i
#if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) && !defined(MYSQL_SERVER) #if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) && !defined(MYSQL_SERVER) && !defined(__WIN__)
#undef __WIN__
#define __WIN__ #define __WIN__
#include <windows.h> #include <windows.h>
@ -56,6 +57,7 @@ of the 32-bit x86 assembler in mutex operations. */
Microsoft Visual C++ */ Microsoft Visual C++ */
#if !defined(__GNUC__) && !defined(__WIN__) #if !defined(__GNUC__) && !defined(__WIN__)
#undef UNIV_MUST_NOT_INLINE /* Remove compiler warning */
#define UNIV_MUST_NOT_INLINE #define UNIV_MUST_NOT_INLINE
#endif #endif

View File

@ -50,6 +50,16 @@ ut_malloc(
/* out, own: allocated memory */ /* out, own: allocated memory */
ulint n); /* in: number of bytes to allocate */ ulint n); /* in: number of bytes to allocate */
/************************************************************************** /**************************************************************************
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
out. It cannot be used if we want to return an error message. Prints to
stderr a message if fails. */
ibool
ut_test_malloc(
/*===========*/
/* out: TRUE if succeeded */
ulint n); /* in: try to allocate this many bytes */
/**************************************************************************
Frees a memory bloock allocated with ut_malloc. */ Frees a memory bloock allocated with ut_malloc. */
void void

View File

@ -438,24 +438,28 @@ log_group_calc_lsn_offset(
log_group_t* group) /* in: log group */ log_group_t* group) /* in: log group */
{ {
dulint gr_lsn; dulint gr_lsn;
ulint gr_lsn_size_offset; ib_longlong gr_lsn_size_offset;
ulint difference; ib_longlong difference;
ulint group_size; ib_longlong group_size;
ulint offset; ib_longlong offset;
ut_ad(mutex_own(&(log_sys->mutex))); ut_ad(mutex_own(&(log_sys->mutex)));
/* If total log file size is > 2 GB we can easily get overflows
with 32-bit integers. Use 64-bit integers instead. */
gr_lsn = group->lsn; gr_lsn = group->lsn;
gr_lsn_size_offset = log_group_calc_size_offset(group->lsn_offset, gr_lsn_size_offset = (ib_longlong)
group); log_group_calc_size_offset(group->lsn_offset, group);
group_size = log_group_get_capacity(group);
group_size = (ib_longlong) log_group_get_capacity(group);
if (ut_dulint_cmp(lsn, gr_lsn) >= 0) { if (ut_dulint_cmp(lsn, gr_lsn) >= 0) {
difference = ut_dulint_minus(lsn, gr_lsn); difference = (ib_longlong) ut_dulint_minus(lsn, gr_lsn);
} else { } else {
difference = ut_dulint_minus(gr_lsn, lsn); difference = (ib_longlong) ut_dulint_minus(gr_lsn, lsn);
difference = difference % group_size; difference = difference % group_size;
@ -464,7 +468,13 @@ log_group_calc_lsn_offset(
offset = (gr_lsn_size_offset + difference) % group_size; offset = (gr_lsn_size_offset + difference) % group_size;
return(log_group_calc_real_offset(offset, group)); ut_a(offset <= 0xFFFFFFFF);
/* printf("Offset is %lu gr_lsn_offset is %lu difference is %lu\n",
(ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference);
*/
return(log_group_calc_real_offset((ulint)offset, group));
} }
/*********************************************************************** /***********************************************************************
@ -3054,8 +3064,8 @@ log_check_log_recs(
ut_memcpy(scan_buf, start, end - start); ut_memcpy(scan_buf, start, end - start);
recv_scan_log_recs(TRUE, recv_scan_log_recs(TRUE,
buf_pool_get_curr_size() - (buf_pool->n_frames -
RECV_POOL_N_FREE_BLOCKS * UNIV_PAGE_SIZE, recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
FALSE, scan_buf, end - start, FALSE, scan_buf, end - start,
ut_dulint_align_down(buf_start_lsn, ut_dulint_align_down(buf_start_lsn,
OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE),

View File

@ -71,6 +71,14 @@ ulint recv_previous_parsed_rec_is_multi = 0;
ulint recv_max_parsed_page_no = 0; ulint recv_max_parsed_page_no = 0;
/* This many frames must be left free in the buffer pool when we scan
the log and store the scanned log records in the buffer pool: we will
use these free frames to read in pages when we start applying the
log records to the database. */
ulint recv_n_pool_free_frames = 256;
/************************************************************ /************************************************************
Creates the recovery system. */ Creates the recovery system. */
@ -1018,10 +1026,10 @@ recv_recover_page(
block = buf_block_align(page); block = buf_block_align(page);
if (just_read_in) { if (just_read_in) {
/* Move the ownership of the x-latch on the page to this OS /* Move the ownership of the x-latch on the page to
thread, so that we can acquire a second x-latch on it. This this OS thread, so that we can acquire a second
is needed for the operations to the page to pass the debug x-latch on it. This is needed for the operations to
checks. */ the page to pass the debug checks. */
rw_lock_x_lock_move_ownership(&(block->lock)); rw_lock_x_lock_move_ownership(&(block->lock));
} }
@ -2362,8 +2370,8 @@ recv_group_scan_log_recs(
group, start_lsn, end_lsn); group, start_lsn, end_lsn);
finished = recv_scan_log_recs(TRUE, finished = recv_scan_log_recs(TRUE,
buf_pool_get_curr_size() (buf_pool->n_frames
- RECV_POOL_N_FREE_BLOCKS * UNIV_PAGE_SIZE, - recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
TRUE, log_sys->buf, TRUE, log_sys->buf,
RECV_SCAN_SIZE, start_lsn, RECV_SCAN_SIZE, start_lsn,
contiguous_lsn, group_scanned_lsn); contiguous_lsn, group_scanned_lsn);
@ -3001,8 +3009,8 @@ ask_again:
read_offset % UNIV_PAGE_SIZE, len, buf, NULL); read_offset % UNIV_PAGE_SIZE, len, buf, NULL);
ret = recv_scan_log_recs(TRUE, ret = recv_scan_log_recs(TRUE,
buf_pool_get_curr_size() - (buf_pool->n_frames -
RECV_POOL_N_FREE_BLOCKS * UNIV_PAGE_SIZE, recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
TRUE, buf, len, start_lsn, TRUE, buf, len, start_lsn,
&dummy_lsn, &scanned_lsn); &dummy_lsn, &scanned_lsn);

View File

@ -15,6 +15,7 @@ Created 5/12/1997 Heikki Tuuri
#include "ut0mem.h" #include "ut0mem.h"
#include "ut0lst.h" #include "ut0lst.h"
#include "ut0byte.h" #include "ut0byte.h"
#include "mem0mem.h"
/* We would like to use also the buffer frames to allocate memory. This /* We would like to use also the buffer frames to allocate memory. This
would be desirable, because then the memory consumption of the database would be desirable, because then the memory consumption of the database
@ -251,7 +252,6 @@ mem_pool_fill_free_list(
mem_area_t* area; mem_area_t* area;
mem_area_t* area2; mem_area_t* area2;
ibool ret; ibool ret;
char err_buf[500];
ut_ad(mutex_own(&(pool->mutex))); ut_ad(mutex_own(&(pool->mutex)));
@ -259,19 +259,6 @@ mem_pool_fill_free_list(
/* We come here when we have run out of space in the /* We come here when we have run out of space in the
memory pool: */ memory pool: */
if (mem_out_of_mem_err_msg_count % 1000000000 == 0) {
/* We do not print the message every time: */
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Out of memory in additional memory pool.\n"
"InnoDB: InnoDB will start allocating memory from the OS.\n"
"InnoDB: You may get better performance if you configure a bigger\n"
"InnoDB: value in the MySQL my.cnf file for\n"
"InnoDB: innodb_additional_mem_pool_size.\n");
}
mem_out_of_mem_err_msg_count++; mem_out_of_mem_err_msg_count++;
return(FALSE); return(FALSE);
@ -300,11 +287,8 @@ mem_pool_fill_free_list(
} }
if (UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0) { if (UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0) {
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); mem_analyze_corruption((byte*)area);
fprintf(stderr,
"InnoDB: Error: Removing element from mem pool free list %lu\n"
"InnoDB: though the list length is 0! Dump of 100 bytes around element:\n%s\n",
i + 1, err_buf);
ut_a(0); ut_a(0);
} }
@ -340,7 +324,6 @@ mem_area_alloc(
mem_area_t* area; mem_area_t* area;
ulint n; ulint n;
ibool ret; ibool ret;
char err_buf[500];
n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE)); n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE));
@ -364,20 +347,22 @@ mem_area_alloc(
} }
if (!mem_area_get_free(area)) { if (!mem_area_get_free(area)) {
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100);
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: Removing element from mem pool free list %lu though the\n" "InnoDB: Error: Removing element from mem pool free list %lu though the\n"
"InnoDB: element is not marked free! Dump of 100 bytes around element:\n%s\n", "InnoDB: element is not marked free!\n",
n, err_buf); n);
mem_analyze_corruption((byte*)area);
ut_a(0); ut_a(0);
} }
if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) { if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) {
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100);
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: Removing element from mem pool free list %lu\n" "InnoDB: Error: Removing element from mem pool free list %lu\n"
"InnoDB: though the list length is 0! Dump of 100 bytes around element:\n%s\n", "InnoDB: though the list length is 0!\n",
n, err_buf); n);
mem_analyze_corruption((byte*)area);
ut_a(0); ut_a(0);
} }
@ -451,7 +436,6 @@ mem_area_free(
void* new_ptr; void* new_ptr;
ulint size; ulint size;
ulint n; ulint n;
char err_buf[500];
if (mem_out_of_mem_err_msg_count > 0) { if (mem_out_of_mem_err_msg_count > 0) {
/* It may be that the area was really allocated from the /* It may be that the area was really allocated from the
@ -469,17 +453,24 @@ mem_area_free(
area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE); area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE);
if (mem_area_get_free(area)) { if (mem_area_get_free(area)) {
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100);
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: Freeing element to mem pool free list though the\n" "InnoDB: Error: Freeing element to mem pool free list though the\n"
"InnoDB: element is marked free! Dump of 100 bytes around element:\n%s\n", "InnoDB: element is marked free!\n");
err_buf);
mem_analyze_corruption((byte*)area);
ut_a(0); ut_a(0);
} }
size = mem_area_get_size(area); size = mem_area_get_size(area);
ut_ad(size != 0); if (size == 0) {
fprintf(stderr,
"InnoDB: Error: Mem area size is 0. Possibly a memory overrun of the\n"
"InnoDB: previous allocated area!\n");
mem_analyze_corruption((byte*)area);
ut_a(0);
}
#ifdef UNIV_LIGHT_MEM_DEBUG #ifdef UNIV_LIGHT_MEM_DEBUG
if (((byte*)area) + size < pool->buf + pool->size) { if (((byte*)area) + size < pool->buf + pool->size) {
@ -488,7 +479,15 @@ mem_area_free(
next_size = mem_area_get_size( next_size = mem_area_get_size(
(mem_area_t*)(((byte*)area) + size)); (mem_area_t*)(((byte*)area) + size));
ut_a(ut_2_power_up(next_size) == next_size); if (ut_2_power_up(next_size) != next_size) {
fprintf(stderr,
"InnoDB: Error: Memory area size %lu, next area size %lu not a power of 2!\n"
"InnoDB: Possibly a memory overrun of the buffer being freed here.\n",
size, next_size);
mem_analyze_corruption((byte*)area);
ut_a(0);
}
} }
#endif #endif
buddy = mem_area_get_buddy(area, size, pool); buddy = mem_area_get_buddy(area, size, pool);

View File

@ -12,11 +12,469 @@ Created 9/30/1995 Heikki Tuuri
#include "os0proc.ic" #include "os0proc.ic"
#endif #endif
#ifdef __WIN__ #include "ut0mem.h"
#include <windows.h> #include "ut0byte.h"
/*
How to get AWE to compile on Windows?
-------------------------------------
the Visual C++ has to be relatively recent and _WIN32_WINNT has to be
defined to a value >= 0x0500 when windows.h is included. An easy way
to accomplish that is to put
#define _WIN32_WINNT 0x0500
to the start of file \mysql\include\config-win.h
Where does AWE work?
-------------------
See the error message in os_awe_allocate_physical_mem().
How to assign privileges for mysqld to use AWE?
-----------------------------------------------
See the error message in os_awe_enable_lock_pages_in_mem().
Use Windows AWE functions in this order
---------------------------------------
(1) os_awe_enable_lock_pages_in_mem();
(2) os_awe_allocate_physical_mem();
(3) os_awe_allocate_virtual_mem_window();
(4) os_awe_map_physical_mem_to_window().
To test 'AWE' in a computer which does not have the AWE API,
you can compile with UNIV_SIMULATE_AWE defined in this file.
*/
#ifdef UNIV_SIMULATE_AWE
/* If we simulate AWE, we allocate the 'physical memory' here */
byte* os_awe_simulate_mem;
ulint os_awe_simulate_mem_size;
os_awe_t* os_awe_simulate_page_info;
byte* os_awe_simulate_window;
ulint os_awe_simulate_window_size;
/* In simulated AWE the following contains a NULL pointer or a pointer
to a mapped 'physical page' for each 4 kB page in the AWE window */
byte** os_awe_simulate_map;
#endif #endif
#include "ut0mem.h" #ifdef __NT__
os_awe_t* os_awe_page_info;
ulint os_awe_n_pages;
byte* os_awe_window;
ulint os_awe_window_size;
#endif
/********************************************************************
Windows AWE support. Tries to enable the "lock pages in memory" privilege for
the current process so that the current process can allocate memory-locked
virtual address space to act as the window where AWE maps physical memory. */
ibool
os_awe_enable_lock_pages_in_mem(void)
/*=================================*/
/* out: TRUE if success, FALSE if error;
prints error info to stderr if no success */
{
#ifdef UNIV_SIMULATE_AWE
return(TRUE);
#elif defined(__NT__)
struct {
DWORD Count;
LUID_AND_ATTRIBUTES Privilege[1];
} Info;
HANDLE hProcess;
HANDLE Token;
BOOL Result;
hProcess = GetCurrentProcess();
/* Open the token of the current process */
Result = OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES,
&Token);
if (Result != TRUE) {
fprintf(stderr,
"InnoDB: AWE: Cannot open process token, error %lu\n",
(ulint)GetLastError());
return(FALSE);
}
Info.Count = 1;
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
/* Get the local unique identifier (LUID) of the SE_LOCK_MEMORY
privilege */
Result = LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME,
&(Info.Privilege[0].Luid));
if (Result != TRUE) {
fprintf(stderr,
"InnoDB: AWE: Cannot get local privilege value for %s, error %lu.\n",
SE_LOCK_MEMORY_NAME, (ulint)GetLastError());
return(FALSE);
}
/* Try to adjust the privilege */
Result = AdjustTokenPrivileges(Token, FALSE,
(PTOKEN_PRIVILEGES)&Info,
0, NULL, NULL);
/* Check the result */
if (Result != TRUE) {
fprintf(stderr,
"InnoDB: AWE: Cannot adjust process token privileges, error %u.\n",
GetLastError());
return(FALSE);
} else if (GetLastError() != ERROR_SUCCESS) {
fprintf(stderr,
"InnoDB: AWE: Cannot enable SE_LOCK_MEMORY privilege, error %lu.\n"
"InnoDB: In Windows XP Home you cannot use AWE. In Windows 2000 and XP\n"
"InnoDB: Professional you must go to the Control Panel, to\n"
"InnoDB: Security Settings, to Local Policies, and enable\n"
"InnoDB: the 'lock pages in memory' privilege for the user who runs\n"
"InnoDB: the MySQL server.\n", GetLastError());
return(FALSE);
}
CloseHandle(Token);
return(TRUE);
#else
#ifdef __WIN__
fprintf(stderr,
"InnoDB: AWE: Error: to use AWE you must use a ...-nt MySQL executable.\n");
#endif
return(FALSE);
#endif
}
/********************************************************************
Allocates physical RAM memory up to 64 GB in an Intel 32-bit x86
processor. */
ibool
os_awe_allocate_physical_mem(
/*=========================*/
/* out: TRUE if success */
os_awe_t** page_info, /* out, own: array of opaque data containing
the info for allocated physical memory pages;
each allocated 4 kB physical memory page has
one slot of type os_awe_t in the array */
ulint n_megabytes) /* in: number of megabytes to allocate */
{
#ifdef UNIV_SIMULATE_AWE
os_awe_simulate_page_info = ut_malloc(sizeof(os_awe_t) *
n_megabytes * ((1024 * 1024) / OS_AWE_X86_PAGE_SIZE));
os_awe_simulate_mem = ut_align(ut_malloc(
4096 + 1024 * 1024 * n_megabytes),
4096);
os_awe_simulate_mem_size = n_megabytes * 1024 * 1024;
*page_info = os_awe_simulate_page_info;
return(TRUE);
#elif defined(__NT__)
BOOL bResult;
ULONG_PTR NumberOfPages; /* Question: why does Windows
use the name ULONG_PTR for
a scalar integer type? Maybe
because we may also refer to
&NumberOfPages? */
ULONG_PTR NumberOfPagesInitial;
SYSTEM_INFO sSysInfo;
int PFNArraySize;
if (n_megabytes > 64 * 1024) {
fprintf(stderr,
"InnoDB: AWE: Error: tried to allocate %lu MB.\n"
"InnoDB: AWE cannot allocate more than 64 GB in any computer.\n", n_megabytes);
return(FALSE);
}
GetSystemInfo(&sSysInfo); /* fill the system information structure */
if ((ulint)OS_AWE_X86_PAGE_SIZE != (ulint)sSysInfo.dwPageSize) {
fprintf(stderr,
"InnoDB: AWE: Error: this computer has a page size of %lu.\n"
"InnoDB: Should be 4096 bytes for InnoDB AWE support to work.\n",
(ulint)sSysInfo.dwPageSize);
return(FALSE);
}
/* Calculate the number of pages of memory to request */
NumberOfPages = n_megabytes * ((1024 * 1024) / OS_AWE_X86_PAGE_SIZE);
/* Calculate the size of page_info for allocated physical pages */
PFNArraySize = NumberOfPages * sizeof(ULONG_PTR);
*page_info = (ULONG_PTR*)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
if (*page_info == NULL) {
fprintf(stderr,
"InnoDB: AWE: Failed to allocate page info array from process heap, error %lu\n",
(ulint)GetLastError());
return(FALSE);
}
ut_total_allocated_memory += PFNArraySize;
/* Enable this process' privilege to lock pages to physical memory */
if (!os_awe_enable_lock_pages_in_mem()) {
return(FALSE);
}
/* Allocate the physical memory */
NumberOfPagesInitial = NumberOfPages;
os_awe_page_info = *page_info;
os_awe_n_pages = (ulint)NumberOfPages;
/* Compilation note: if the compiler complains the function is not
defined, see the note at the start of this file */
bResult = AllocateUserPhysicalPages(GetCurrentProcess(),
&NumberOfPages,
*page_info);
if (bResult != TRUE) {
fprintf(stderr,
"InnoDB: AWE: Cannot allocate physical pages, error %lu.\n",
(ulint)GetLastError());
return(FALSE);
}
if (NumberOfPagesInitial != NumberOfPages) {
fprintf(stderr,
"InnoDB: AWE: Error: allocated only %lu pages of %lu requested.\n"
"InnoDB: Check that you have enough free RAM.\n"
"InnoDB: In Windows XP Professional and 2000 Professional\n"
"InnoDB: Windows PAE size is max 4 GB. In 2000 and .NET\n"
"InnoDB: Advanced Servers and 2000 Datacenter Server it is 32 GB,\n"
"InnoDB: and in .NET Datacenter Server it is 64 GB.\n"
"InnoDB: A Microsoft web page said that the processor must be an Intel\n"
"InnoDB: processor.\n",
(ulint)NumberOfPages,
(ulint)NumberOfPagesInitial);
return(FALSE);
}
fprintf(stderr,
"InnoDB: Using Address Windowing Extensions (AWE); allocated %lu MB\n",
n_megabytes);
return(TRUE);
#else
return(FALSE);
#endif
}
/********************************************************************
Allocates a window in the virtual address space where we can map then
pages of physical memory. */
byte*
os_awe_allocate_virtual_mem_window(
/*===============================*/
/* out, own: allocated memory, or NULL if did not
succeed */
ulint size) /* in: virtual memory allocation size in bytes, must
be < 2 GB */
{
#ifdef UNIV_SIMULATE_AWE
ulint i;
os_awe_simulate_window = ut_align(ut_malloc(4096 + size), 4096);
os_awe_simulate_window_size = size;
os_awe_simulate_map = ut_malloc(sizeof(byte*) * (size / 4096));
for (i = 0; i < (size / 4096); i++) {
*(os_awe_simulate_map + i) = NULL;
}
return(os_awe_simulate_window);
#elif defined(__NT__)
byte* ptr;
if (size > 0x7FFFFFFFFF) {
fprintf(stderr,
"InnoDB: AWE: Cannot allocate %lu bytes of virtual memory\n", size);
return(NULL);
}
ptr = VirtualAlloc(NULL, (SIZE_T)size, MEM_RESERVE | MEM_PHYSICAL,
PAGE_READWRITE);
if (ptr == NULL) {
fprintf(stderr,
"InnoDB: AWE: Cannot allocate %lu bytes of virtual memory, error %lu\n",
size, (ulint)GetLastError());
return(NULL);
}
os_awe_window = ptr;
os_awe_window_size = size;
ut_total_allocated_memory += size;
return(ptr);
#else
return(NULL);
#endif
}
/********************************************************************
With this function you can map parts of physical memory allocated with
the ..._allocate_physical_mem to the virtual address space allocated with
the previous function. Intel implements this so that the process page
tables are updated accordingly. A test on a 1.5 GHz AMD processor and XP
showed that this takes < 1 microsecond, much better than the estimated 80 us
for copying a 16 kB page memory to memory. But, the operation will at least
partially invalidate the translation lookaside buffer (TLB) of all
processors. Under a real-world load the performance hit may be bigger. */
ibool
os_awe_map_physical_mem_to_window(
/*==============================*/
/* out: TRUE if success; the function
calls exit(1) in case of an error */
byte* ptr, /* in: a page-aligned pointer to
somewhere in the virtual address
space window; we map the physical mem
pages here */
ulint n_mem_pages, /* in: number of 4 kB mem pages to
map */
os_awe_t* page_info) /* in: array of page infos for those
pages; each page has one slot in the
array */
{
#ifdef UNIV_SIMULATE_AWE
ulint i;
byte** map;
byte* page;
byte* phys_page;
ut_a(ptr >= os_awe_simulate_window);
ut_a(ptr < os_awe_simulate_window + os_awe_simulate_window_size);
ut_a(page_info >= os_awe_simulate_page_info);
ut_a(page_info < os_awe_simulate_page_info +
(os_awe_simulate_mem_size / 4096));
/* First look if some other 'physical pages' are mapped at ptr,
and copy them back to where they were if yes */
map = os_awe_simulate_map
+ ((ulint)(ptr - os_awe_simulate_window)) / 4096;
page = ptr;
for (i = 0; i < n_mem_pages; i++) {
if (*map != NULL) {
ut_memcpy(*map, page, 4096);
}
map++;
page += 4096;
}
/* Then copy to ptr the 'physical pages' determined by page_info; we
assume page_info is a segment of the array we created at the start */
phys_page = os_awe_simulate_mem
+ (ulint)(page_info - os_awe_simulate_page_info)
* 4096;
ut_memcpy(ptr, phys_page, n_mem_pages * 4096);
/* Update the map */
map = os_awe_simulate_map
+ ((ulint)(ptr - os_awe_simulate_window)) / 4096;
for (i = 0; i < n_mem_pages; i++) {
*map = phys_page;
map++;
phys_page += 4096;
}
return(TRUE);
#elif defined(__NT__)
BOOL bResult;
ULONG_PTR n_pages;
n_pages = (ULONG_PTR)n_mem_pages;
if (!(ptr >= os_awe_window)) {
fprintf(stderr,
"InnoDB: AWE: Error: trying to map to address %lx but AWE window start %lx\n",
(ulint)ptr, (ulint)os_awe_window);
ut_a(0);
}
if (!(ptr <= os_awe_window + os_awe_window_size - UNIV_PAGE_SIZE)) {
fprintf(stderr,
"InnoDB: AWE: Error: trying to map to address %lx but AWE window end %lx\n",
(ulint)ptr, (ulint)os_awe_window + os_awe_window_size);
ut_a(0);
}
if (!(page_info >= os_awe_page_info)) {
fprintf(stderr,
"InnoDB: AWE: Error: trying to map page info at %lx but array start %lx\n",
(ulint)page_info, (ulint)os_awe_page_info);
ut_a(0);
}
if (!(page_info <= os_awe_page_info + (os_awe_n_pages - 4))) {
fprintf(stderr,
"InnoDB: AWE: Error: trying to map page info at %lx but array end %lx\n",
(ulint)page_info, (ulint)(os_awe_page_info + os_awe_n_pages));
ut_a(0);
}
bResult = MapUserPhysicalPages((PVOID)ptr, n_pages, page_info);
if (bResult != TRUE) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: AWE: Mapping of %lu physical pages to address %lx failed,\n"
"InnoDB: error %lu.\n"
"InnoDB: Cannot continue operation.\n",
n_mem_pages, (ulint)ptr, (ulint)GetLastError());
exit(1);
}
return(TRUE);
#else
return(FALSE);
#endif
}
/******************************************************************** /********************************************************************
Converts the current process id to a number. It is not guaranteed that the Converts the current process id to a number. It is not guaranteed that the

View File

@ -322,13 +322,129 @@ row_ins_clust_index_entry_by_modify(
} }
/************************************************************************* /*************************************************************************
Either deletes or sets the referencing columns SQL NULL in a child row. Returns TRUE if in a cascaded update/delete an ancestor node of node
Used in ON DELETE ... clause for foreign keys when a parent row is updates table. */
deleted. */ static
ibool
row_ins_cascade_ancestor_updates_table(
/*===================================*/
/* out: TRUE if an ancestor updates table */
que_node_t* node, /* in: node in a query graph */
dict_table_t* table) /* in: table */
{
que_node_t* parent;
upd_node_t* upd_node;
parent = que_node_get_parent(node);
while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
upd_node = parent;
if (upd_node->table == table) {
return(TRUE);
}
parent = que_node_get_parent(parent);
ut_a(parent);
}
return(FALSE);
}
/**********************************************************************
Calculates the update vector node->cascade->update for a child table in
a cascaded update. */
static static
ulint ulint
row_ins_foreign_delete_or_set_null( row_ins_cascade_calc_update_vec(
/*===============================*/ /*============================*/
/* out: number of fields in the
calculated update vector; the value
can also be 0 if no foreign key
fields changed */
upd_node_t* node, /* in: update node of the parent
table */
dict_foreign_t* foreign) /* in: foreign key constraint whose
type is != 0 */
{
upd_node_t* cascade = node->cascade_node;
dict_table_t* table = foreign->foreign_table;
dict_index_t* index = foreign->foreign_index;
upd_t* update;
upd_field_t* ufield;
dict_table_t* parent_table;
dict_index_t* parent_index;
upd_t* parent_update;
upd_field_t* parent_ufield;
ulint n_fields_updated;
ulint parent_field_no;
ulint i;
ulint j;
ut_a(node && foreign && cascade && table && index);
/* Calculate the appropriate update vector which will set the fields
in the child index record to the same value as the referenced index
record will get in the update. */
parent_table = node->table;
ut_a(parent_table == foreign->referenced_table);
parent_index = foreign->referenced_index;
parent_update = node->update;
update = cascade->update;
update->info_bits = 0;
update->n_fields = foreign->n_fields;
n_fields_updated = 0;
for (i = 0; i < foreign->n_fields; i++) {
parent_field_no = dict_table_get_nth_col_pos(
parent_table,
dict_index_get_nth_col_no(
parent_index, i));
for (j = 0; j < parent_update->n_fields; j++) {
parent_ufield = parent_update->fields + j;
if (parent_ufield->field_no == parent_field_no) {
/* A field in the parent index record is
updated. Let us make the update vector
field for the child table. */
ufield = update->fields + n_fields_updated;
ufield->field_no =
dict_table_get_nth_col_pos(table,
dict_index_get_nth_col_no(index, i));
ufield->exp = NULL;
ufield->new_val = parent_ufield->new_val;
ufield->extern_storage = FALSE;
n_fields_updated++;
}
}
}
update->n_fields = n_fields_updated;
return(n_fields_updated);
}
/*************************************************************************
Perform referential actions or checks when a parent row is deleted or updated
and the constraint had an ON DELETE or ON UPDATE condition which was not
RESTRICT. */
static
ulint
row_ins_foreign_check_on_constraint(
/*================================*/
/* out: DB_SUCCESS, DB_LOCK_WAIT, /* out: DB_SUCCESS, DB_LOCK_WAIT,
or error code */ or error code */
que_thr_t* thr, /* in: query thread whose run_node que_thr_t* thr, /* in: query thread whose run_node
@ -378,15 +494,34 @@ row_ins_foreign_delete_or_set_null(
ut_strlen(table->name) + 1); ut_strlen(table->name) + 1);
node = thr->run_node; node = thr->run_node;
ut_a(que_node_get_type(node) == QUE_NODE_UPDATE); if (node->is_delete && 0 == (foreign->type &
(DICT_FOREIGN_ON_DELETE_CASCADE
| DICT_FOREIGN_ON_DELETE_SET_NULL))) {
if (!node->is_delete) { /* No action is defined: return a foreign key error if
/* According to SQL-92 an UPDATE with respect to FOREIGN NO ACTION is not specified */
KEY constraints is not semantically equivalent to a
DELETE + INSERT. Therefore we do not perform any action if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
here and consequently the child rows would be left
orphaned if we would let the UPDATE happen. Thus we return return(DB_SUCCESS);
an error. */ }
return(DB_ROW_IS_REFERENCED);
}
if (!node->is_delete && 0 == (foreign->type &
(DICT_FOREIGN_ON_UPDATE_CASCADE
| DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
/* This is an UPDATE */
/* No action is defined: return a foreign key error if
NO ACTION is not specified */
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
return(DB_SUCCESS);
}
return(DB_ROW_IS_REFERENCED); return(DB_ROW_IS_REFERENCED);
} }
@ -411,7 +546,10 @@ row_ins_foreign_delete_or_set_null(
cascade->table = table; cascade->table = table;
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE ) { cascade->foreign = foreign;
if (node->is_delete
&& (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) {
cascade->is_delete = TRUE; cascade->is_delete = TRUE;
} else { } else {
cascade->is_delete = FALSE; cascade->is_delete = FALSE;
@ -425,8 +563,30 @@ row_ins_foreign_delete_or_set_null(
} }
} }
/* We do not allow cyclic cascaded updating of the same
table. Check that we are not updating the same table which
is already being modified in this cascade chain. We have to
check this because the modification of the indexes of a
'parent' table may still be incomplete, and we must avoid
seeing the indexes of the parent table in an inconsistent
state! In this way we also prevent possible infinite
update loops caused by cyclic cascaded updates. */
if (!cascade->is_delete
&& row_ins_cascade_ancestor_updates_table(cascade, table)) {
/* We do not know if this would break foreign key
constraints, but play safe and return an error */
err = DB_ROW_IS_REFERENCED;
goto nonstandard_exit_func;
}
index = btr_pcur_get_btr_cur(pcur)->index; index = btr_pcur_get_btr_cur(pcur)->index;
ut_a(index == foreign->foreign_index);
rec = btr_pcur_get_rec(pcur); rec = btr_pcur_get_rec(pcur);
if (index->type & DICT_CLUSTERED) { if (index->type & DICT_CLUSTERED) {
@ -520,7 +680,11 @@ row_ins_foreign_delete_or_set_null(
goto nonstandard_exit_func; goto nonstandard_exit_func;
} }
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) { if ((node->is_delete
&& (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL))
|| (!node->is_delete
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
/* Build the appropriate update vector which sets /* Build the appropriate update vector which sets
foreign->n_fields first fields in rec to SQL NULL */ foreign->n_fields first fields in rec to SQL NULL */
@ -540,6 +704,26 @@ row_ins_foreign_delete_or_set_null(
} }
} }
if (!node->is_delete
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) {
/* Build the appropriate update vector which sets changing
foreign->n_fields first fields in rec to new values */
row_ins_cascade_calc_update_vec(node, foreign);
if (cascade->update->n_fields == 0) {
/* The update does not change any columns referred
to in this foreign key constraint: no need to do
anything */
err = DB_SUCCESS;
goto nonstandard_exit_func;
}
}
/* Store pcur position and initialize or store the cascade node /* Store pcur position and initialize or store the cascade node
pcur stored position */ pcur stored position */
@ -629,6 +813,7 @@ row_ins_check_foreign_constraint(
dtuple_t* entry, /* in: index entry for index */ dtuple_t* entry, /* in: index entry for index */
que_thr_t* thr) /* in: query thread */ que_thr_t* thr) /* in: query thread */
{ {
upd_node_t* upd_node;
dict_table_t* check_table; dict_table_t* check_table;
dict_index_t* check_index; dict_index_t* check_index;
ulint n_fields_cmp; ulint n_fields_cmp;
@ -665,6 +850,30 @@ run_again:
} }
} }
if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
upd_node = thr->run_node;
if (!(upd_node->is_delete) && upd_node->foreign == foreign) {
/* If a cascaded update is done as defined by a
foreign key constraint, do not check that
constraint for the child row. In ON UPDATE CASCADE
the update of the parent row is only half done when
we come here: if we would check the constraint here
for the child row it would fail.
A QUESTION remains: if in the child table there are
several constraints which refer to the same parent
table, we should merge all updates to the child as
one update? And the updates can be contradictory!
Currently we just perform the update associated
with each foreign key constraint, one after
another, and the user has problems predicting in
which order they are performed. */
return(DB_SUCCESS);
}
}
if (check_ref) { if (check_ref) {
check_table = foreign->referenced_table; check_table = foreign->referenced_table;
check_index = foreign->referenced_index; check_index = foreign->referenced_index;
@ -774,8 +983,12 @@ run_again:
break; break;
} else if (foreign->type != 0) { } else if (foreign->type != 0) {
/* There is an ON UPDATE or ON DELETE
condition: check them in a separate
function */
err = err =
row_ins_foreign_delete_or_set_null( row_ins_foreign_check_on_constraint(
thr, foreign, &pcur, &mtr); thr, foreign, &pcur, &mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {

View File

@ -58,6 +58,19 @@ row_mysql_read_var_ref_noninline(
return(row_mysql_read_var_ref(len, field)); return(row_mysql_read_var_ref(len, field));
} }
/***********************************************************************
Frees the blob heap in prebuilt when no longer needed. */
void
row_mysql_prebuilt_free_blob_heap(
/*==============================*/
row_prebuilt_t* prebuilt) /* in: prebuilt struct of a
ha_innobase:: table handle */
{
mem_heap_free(prebuilt->blob_heap);
prebuilt->blob_heap = NULL;
}
/*********************************************************************** /***********************************************************************
Stores a reference to a BLOB in the MySQL format. */ Stores a reference to a BLOB in the MySQL format. */
@ -313,6 +326,7 @@ row_create_prebuilt(
prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t)); prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED; prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
prebuilt->table = table; prebuilt->table = table;
@ -378,11 +392,12 @@ row_prebuilt_free(
{ {
ulint i; ulint i;
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n" "InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name %s\n", "InnoDB: table handle. Magic n %lu, magic n2 %lu, table name %s\n",
prebuilt->magic_n, prebuilt->table->name); prebuilt->magic_n, prebuilt->magic_n2, prebuilt->table->name);
mem_analyze_corruption((byte*)prebuilt); mem_analyze_corruption((byte*)prebuilt);
@ -390,6 +405,7 @@ row_prebuilt_free(
} }
prebuilt->magic_n = ROW_PREBUILT_FREED; prebuilt->magic_n = ROW_PREBUILT_FREED;
prebuilt->magic_n2 = ROW_PREBUILT_FREED;
btr_pcur_free_for_mysql(prebuilt->pcur); btr_pcur_free_for_mysql(prebuilt->pcur);
btr_pcur_free_for_mysql(prebuilt->clust_pcur); btr_pcur_free_for_mysql(prebuilt->clust_pcur);
@ -420,7 +436,23 @@ row_prebuilt_free(
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) { for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
if (prebuilt->fetch_cache[i] != NULL) { if (prebuilt->fetch_cache[i] != NULL) {
mem_free(prebuilt->fetch_cache[i]);
if ((ROW_PREBUILT_FETCH_MAGIC_N !=
mach_read_from_4((prebuilt->fetch_cache[i]) - 4))
|| (ROW_PREBUILT_FETCH_MAGIC_N !=
mach_read_from_4((prebuilt->fetch_cache[i])
+ prebuilt->mysql_row_len))) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
"InnoDB: fetch buffer.\n");
mem_analyze_corruption(
prebuilt->fetch_cache[i]);
ut_a(0);
}
mem_free((prebuilt->fetch_cache[i]) - 4);
} }
} }
@ -1435,7 +1467,7 @@ int
row_create_index_for_mysql( row_create_index_for_mysql(
/*=======================*/ /*=======================*/
/* out: error number or DB_SUCCESS */ /* out: error number or DB_SUCCESS */
dict_index_t* index, /* in: index defintion */ dict_index_t* index, /* in: index definition */
trx_t* trx) /* in: transaction handle */ trx_t* trx) /* in: transaction handle */
{ {
ind_node_t* node; ind_node_t* node;
@ -1444,6 +1476,8 @@ row_create_index_for_mysql(
ulint namelen; ulint namelen;
ulint keywordlen; ulint keywordlen;
ulint err; ulint err;
ulint i;
ulint j;
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
@ -1465,6 +1499,31 @@ row_create_index_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/* Check that the same column does not appear twice in the index.
InnoDB assumes this in its algorithms, e.g., update of an index
entry */
for (i = 0; i < dict_index_get_n_fields(index); i++) {
for (j = 0; j < i; j++) {
if (0 == ut_strcmp(
dict_index_get_nth_field(index, j)->name,
dict_index_get_nth_field(index, i)->name)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: column %s appears twice in index %s of table %s\n"
"InnoDB: This is not allowed in InnoDB.\n",
dict_index_get_nth_field(index, i)->name,
index->name, index->table_name);
err = DB_COL_APPEARS_TWICE_IN_INDEX;
goto error_handling;
}
}
}
heap = mem_heap_create(512); heap = mem_heap_create(512);
trx->dict_operation = TRUE; trx->dict_operation = TRUE;
@ -1479,9 +1538,11 @@ row_create_index_for_mysql(
err = trx->error_state; err = trx->error_state;
que_graph_free((que_t*) que_node_get_parent(thr));
error_handling:
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
/* We have special error handling here */ /* We have special error handling here */
ut_a(err == DB_OUT_OF_FILE_SPACE);
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
@ -1492,8 +1553,6 @@ row_create_index_for_mysql(
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
que_graph_free((que_t*) que_node_get_parent(thr));
trx->op_info = (char *) ""; trx->op_info = (char *) "";
return((int) err); return((int) err);

View File

@ -2039,9 +2039,12 @@ Note that the template in prebuilt may advise us to copy only a few
columns to mysql_rec, other columns are left blank. All columns may not columns to mysql_rec, other columns are left blank. All columns may not
be needed in the query. */ be needed in the query. */
static static
void ibool
row_sel_store_mysql_rec( row_sel_store_mysql_rec(
/*====================*/ /*====================*/
/* out: TRUE if success, FALSE
if could not allocate memory for a
BLOB */
byte* mysql_rec, /* out: row in the MySQL format */ byte* mysql_rec, /* out: row in the MySQL format */
row_prebuilt_t* prebuilt, /* in: prebuilt struct */ row_prebuilt_t* prebuilt, /* in: prebuilt struct */
rec_t* rec) /* in: Innobase record in the index rec_t* rec) /* in: Innobase record in the index
@ -2093,6 +2096,18 @@ row_sel_store_mysql_rec(
ut_a(prebuilt->templ_contains_blob); ut_a(prebuilt->templ_contains_blob);
/* A heuristic test that we can allocate
the memory for a big BLOB. We have a safety
margin of 1000000 bytes. Since the test
takes some CPU time, we do not use for small
BLOBs. */
if (len > 2000000
&& !ut_test_malloc(len + 1000000)) {
return(FALSE);
}
/* Copy the BLOB data to the BLOB /* Copy the BLOB data to the BLOB
heap of prebuilt */ heap of prebuilt */
@ -2142,6 +2157,8 @@ row_sel_store_mysql_rec(
} }
} }
} }
return(TRUE);
} }
/************************************************************************* /*************************************************************************
@ -2415,6 +2432,7 @@ row_sel_push_cache_row_for_mysql(
row_prebuilt_t* prebuilt, /* in: prebuilt struct */ row_prebuilt_t* prebuilt, /* in: prebuilt struct */
rec_t* rec) /* in: record to push */ rec_t* rec) /* in: record to push */
{ {
byte* buf;
ulint i; ulint i;
ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE); ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
@ -2424,8 +2442,18 @@ row_sel_push_cache_row_for_mysql(
/* Allocate memory for the fetch cache */ /* Allocate memory for the fetch cache */
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) { for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
prebuilt->fetch_cache[i] = mem_alloc(
prebuilt->mysql_row_len); /* A user has reported memory corruption in these
buffers in Linux. Put magic numbers there to help
to track a possible bug. */
buf = mem_alloc(prebuilt->mysql_row_len + 8);
prebuilt->fetch_cache[i] = buf + 4;
mach_write_to_4(buf, ROW_PREBUILT_FETCH_MAGIC_N);
mach_write_to_4(buf + 4 + prebuilt->mysql_row_len,
ROW_PREBUILT_FETCH_MAGIC_N);
} }
} }
@ -2515,7 +2543,8 @@ row_search_for_mysql(
/*=================*/ /*=================*/
/* out: DB_SUCCESS, /* out: DB_SUCCESS,
DB_RECORD_NOT_FOUND, DB_RECORD_NOT_FOUND,
DB_END_OF_INDEX, or DB_DEADLOCK */ DB_END_OF_INDEX, DB_DEADLOCK,
or DB_TOO_BIG_RECORD */
byte* buf, /* in/out: buffer for the fetched byte* buf, /* in/out: buffer for the fetched
row in the MySQL format */ row in the MySQL format */
ulint mode, /* in: search mode PAGE_CUR_L, ... */ ulint mode, /* in: search mode PAGE_CUR_L, ... */
@ -2747,7 +2776,12 @@ row_search_for_mysql(
#ifdef UNIV_SEARCH_DEBUG #ifdef UNIV_SEARCH_DEBUG
ut_a(0 == cmp_dtuple_rec(search_tuple, rec)); ut_a(0 == cmp_dtuple_rec(search_tuple, rec));
#endif #endif
row_sel_store_mysql_rec(buf, prebuilt, rec); if (!row_sel_store_mysql_rec(buf, prebuilt,
rec)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
}
mtr_commit(&mtr); mtr_commit(&mtr);
@ -3189,7 +3223,11 @@ rec_loop:
rec_get_size(rec)); rec_get_size(rec));
mach_write_to_4(buf, rec_get_extra_size(rec) + 4); mach_write_to_4(buf, rec_get_extra_size(rec) + 4);
} else { } else {
row_sel_store_mysql_rec(buf, prebuilt, rec); if (!row_sel_store_mysql_rec(buf, prebuilt, rec)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
}
} }
if (prebuilt->clust_index_was_generated) { if (prebuilt->clust_index_was_generated) {

View File

@ -71,6 +71,20 @@ the x-latch freed? The most efficient way for performing a
searched delete is obviously to keep the x-latch for several searched delete is obviously to keep the x-latch for several
steps of query graph execution. */ steps of query graph execution. */
/***************************************************************
Checks if an update vector changes some of the first fields of an index
record. */
static
ibool
row_upd_changes_first_fields(
/*=========================*/
/* out: TRUE if changes */
dtuple_t* entry, /* in: old value of index entry */
dict_index_t* index, /* in: index of entry */
upd_t* update, /* in: update vector for the row */
ulint n); /* in: how many first fields to check */
/************************************************************************* /*************************************************************************
Checks if index currently is mentioned as a referenced index in a foreign Checks if index currently is mentioned as a referenced index in a foreign
key constraint. */ key constraint. */
@ -132,6 +146,7 @@ ulint
row_upd_check_references_constraints( row_upd_check_references_constraints(
/*=================================*/ /*=================================*/
/* out: DB_SUCCESS or an error code */ /* out: DB_SUCCESS or an error code */
upd_node_t* node, /* in: row update node */
btr_pcur_t* pcur, /* in: cursor positioned on a record; NOTE: the btr_pcur_t* pcur, /* in: cursor positioned on a record; NOTE: the
cursor position is lost in this function! */ cursor position is lost in this function! */
dict_table_t* table, /* in: table in question */ dict_table_t* table, /* in: table in question */
@ -173,7 +188,16 @@ row_upd_check_references_constraints(
foreign = UT_LIST_GET_FIRST(table->referenced_list); foreign = UT_LIST_GET_FIRST(table->referenced_list);
while (foreign) { while (foreign) {
if (foreign->referenced_index == index) { /* Note that we may have an update which updates the index
record, but does NOT update the first fields which are
referenced in a foreign key constraint. Then the update does
NOT break the constraint. */
if (foreign->referenced_index == index
&& (node->is_delete
|| row_upd_changes_first_fields(entry, index,
node->update, foreign->n_fields))) {
if (foreign->foreign_table == NULL) { if (foreign->foreign_table == NULL) {
dict_table_get(foreign->foreign_table_name, dict_table_get(foreign->foreign_table_name,
trx); trx);
@ -189,10 +213,9 @@ row_upd_check_references_constraints(
} }
/* NOTE that if the thread ends up waiting for a lock /* NOTE that if the thread ends up waiting for a lock
we will release dict_operation_lock we will release dict_operation_lock temporarily!
temporarily! But the counter on the table But the counter on the table protects 'foreign' from
protects 'foreign' from being dropped while the check being dropped while the check is running. */
is running. */
err = row_ins_check_foreign_constraint(FALSE, foreign, err = row_ins_check_foreign_constraint(FALSE, foreign,
table, index, entry, thr); table, index, entry, thr);
@ -255,6 +278,7 @@ upd_node_create(
node->index = NULL; node->index = NULL;
node->update = NULL; node->update = NULL;
node->foreign = NULL;
node->cascade_heap = NULL; node->cascade_heap = NULL;
node->cascade_node = NULL; node->cascade_node = NULL;
@ -953,6 +977,53 @@ row_upd_changes_some_index_ord_field_binary(
return(FALSE); return(FALSE);
} }
/***************************************************************
Checks if an update vector changes some of the first fields of an index
record. */
static
ibool
row_upd_changes_first_fields(
/*=========================*/
/* out: TRUE if changes */
dtuple_t* entry, /* in: index entry */
dict_index_t* index, /* in: index of entry */
upd_t* update, /* in: update vector for the row */
ulint n) /* in: how many first fields to check */
{
upd_field_t* upd_field;
dict_field_t* ind_field;
dict_col_t* col;
ulint n_upd_fields;
ulint col_pos;
ulint i, j;
ut_a(update && index);
ut_a(n <= dict_index_get_n_fields(index));
n_upd_fields = upd_get_n_fields(update);
for (i = 0; i < n; i++) {
ind_field = dict_index_get_nth_field(index, i);
col = dict_field_get_col(ind_field);
col_pos = dict_col_get_clust_pos(col);
for (j = 0; j < n_upd_fields; j++) {
upd_field = upd_get_nth_field(update, j);
if (col_pos == upd_field->field_no
&& cmp_dfield_dfield(
dtuple_get_nth_field(entry, i),
&(upd_field->new_val))) {
return(TRUE);
}
}
}
return(FALSE);
}
/************************************************************************* /*************************************************************************
Copies the column values from a record. */ Copies the column values from a record. */
UNIV_INLINE UNIV_INLINE
@ -1106,9 +1177,11 @@ row_upd_sec_index_entry(
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE, err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
thr, &mtr); thr, &mtr);
if (err == DB_SUCCESS && check_ref) { if (err == DB_SUCCESS && check_ref) {
/* NOTE that the following call loses /* NOTE that the following call loses
the position of pcur ! */ the position of pcur ! */
err = row_upd_check_references_constraints( err = row_upd_check_references_constraints(
node,
&pcur, index->table, &pcur, index->table,
index, thr, &mtr); index, thr, &mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -1224,7 +1297,7 @@ row_upd_clust_rec_by_insert(
if (check_ref) { if (check_ref) {
/* NOTE that the following call loses /* NOTE that the following call loses
the position of pcur ! */ the position of pcur ! */
err = row_upd_check_references_constraints( err = row_upd_check_references_constraints(node,
pcur, table, pcur, table,
index, thr, mtr); index, thr, mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -1392,7 +1465,8 @@ row_upd_del_mark_clust_rec(
if (err == DB_SUCCESS && check_ref) { if (err == DB_SUCCESS && check_ref) {
/* NOTE that the following call loses the position of pcur ! */ /* NOTE that the following call loses the position of pcur ! */
err = row_upd_check_references_constraints(pcur, index->table, err = row_upd_check_references_constraints(node,
pcur, index->table,
index, thr, mtr); index, thr, mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
mtr_commit(mtr); mtr_commit(mtr);

View File

@ -140,9 +140,14 @@ byte srv_latin1_ordering[256] /* The sort order table of the latin1
, 0xD8, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0xFF , 0xD8, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0xFF
}; };
ulint srv_pool_size = ULINT_MAX; /* size in database pages; ulint srv_pool_size = ULINT_MAX; /* size in pages; MySQL inits
MySQL originally sets this this to size in kilobytes but
value in megabytes */ we normalize this to pages in
srv_boot() */
ulint srv_awe_window_size = 0; /* size in pages; MySQL inits
this to bytes, but we
normalize it to pages in
srv_boot() */
ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */ ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */
ulint srv_lock_table_size = ULINT_MAX; ulint srv_lock_table_size = ULINT_MAX;
@ -218,6 +223,13 @@ ibool srv_use_doublewrite_buf = TRUE;
ibool srv_set_thread_priorities = TRUE; ibool srv_set_thread_priorities = TRUE;
int srv_query_thread_priority = 0; int srv_query_thread_priority = 0;
/* TRUE if the Address Windowing Extensions of Windows are used; then we must
disable adaptive hash indexes */
ibool srv_use_awe = FALSE;
ibool srv_use_adaptive_hash_indexes = TRUE;
/*-------------------------------------------*/ /*-------------------------------------------*/
ulint srv_n_spin_wait_rounds = 20; ulint srv_n_spin_wait_rounds = 20;
ulint srv_spin_wait_delay = 5; ulint srv_spin_wait_delay = 5;
@ -1956,9 +1968,19 @@ srv_normalize_init_values(void)
srv_log_buffer_size = srv_log_buffer_size / UNIV_PAGE_SIZE; srv_log_buffer_size = srv_log_buffer_size / UNIV_PAGE_SIZE;
srv_pool_size = srv_pool_size / UNIV_PAGE_SIZE; srv_pool_size = srv_pool_size / (UNIV_PAGE_SIZE / 1024);
srv_lock_table_size = 20 * srv_pool_size; srv_awe_window_size = srv_awe_window_size / UNIV_PAGE_SIZE;
if (srv_use_awe) {
/* If we are using AWE we must save memory in the 32-bit
address space of the process, and cannot bind the lock
table size to the real buffer pool size. */
srv_lock_table_size = 20 * srv_awe_window_size;
} else {
srv_lock_table_size = 5 * srv_pool_size;
}
return(DB_SUCCESS); return(DB_SUCCESS);
} }
@ -2323,6 +2345,18 @@ srv_sprintf_innodb_monitor(
"Total memory allocated %lu; in additional pool allocated %lu\n", "Total memory allocated %lu; in additional pool allocated %lu\n",
ut_total_allocated_memory, ut_total_allocated_memory,
mem_pool_get_reserved(mem_comm_pool)); mem_pool_get_reserved(mem_comm_pool));
if (mem_out_of_mem_err_msg_count > 0) {
buf += sprintf(buf,
"Mem allocation has spilled out of additional mem pool %lu times\n");
}
if (srv_use_awe) {
buf += sprintf(buf,
"In addition to that %lu MB of AWE memory allocated\n",
srv_pool_size / ((1024 * 1024) / UNIV_PAGE_SIZE));
}
buf_print_io(buf, buf_end); buf_print_io(buf, buf_end);
buf = buf + strlen(buf); buf = buf + strlen(buf);
ut_a(buf < buf_end + 1500); ut_a(buf < buf_end + 1500);

View File

@ -529,6 +529,9 @@ open_or_create_log_file(
new database */ new database */
ibool* log_file_created, /* out: TRUE if new log file ibool* log_file_created, /* out: TRUE if new log file
created */ created */
ibool log_file_has_been_opened,/* in: TRUE if a log file has been
opened before: then it is an error
to try to create another log file */
ulint k, /* in: log group number */ ulint k, /* in: log group number */
ulint i) /* in: log file number in group */ ulint i) /* in: log file number in group */
{ {
@ -587,6 +590,11 @@ open_or_create_log_file(
fprintf(stderr, fprintf(stderr,
" InnoDB: Log file %s did not exist: new to be created\n", " InnoDB: Log file %s did not exist: new to be created\n",
name); name);
if (log_file_has_been_opened) {
return(DB_ERROR);
}
fprintf(stderr, "InnoDB: Setting log file %s size to %lu MB\n", fprintf(stderr, "InnoDB: Setting log file %s size to %lu MB\n",
name, srv_log_file_size name, srv_log_file_size
>> (20 - UNIV_PAGE_SIZE_SHIFT)); >> (20 - UNIV_PAGE_SIZE_SHIFT));
@ -927,6 +935,7 @@ innobase_start_or_create_for_mysql(void)
/*====================================*/ /*====================================*/
/* out: DB_SUCCESS or error code */ /* out: DB_SUCCESS or error code */
{ {
buf_pool_t* ret;
ibool create_new_db; ibool create_new_db;
ibool log_file_created; ibool log_file_created;
ibool log_created = FALSE; ibool log_created = FALSE;
@ -962,6 +971,11 @@ innobase_start_or_create_for_mysql(void)
#ifdef UNIV_MEM_DEBUG #ifdef UNIV_MEM_DEBUG
fprintf(stderr, fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!!!!!!!\n"); "InnoDB: !!!!!!!!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!!!!!!!\n");
#endif
#ifdef UNIV_SIMULATE_AWE
fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_SIMULATE_AWE switched on !!!!!!!!!!!!!!!!!\n");
#endif #endif
if (srv_sizeof_trx_t_in_ha_innodb_cc != (ulint)sizeof(trx_t)) { if (srv_sizeof_trx_t_in_ha_innodb_cc != (ulint)sizeof(trx_t)) {
@ -994,6 +1008,17 @@ innobase_start_or_create_for_mysql(void)
srv_startup_is_before_trx_rollback_phase = TRUE; srv_startup_is_before_trx_rollback_phase = TRUE;
os_aio_use_native_aio = FALSE; os_aio_use_native_aio = FALSE;
#if !defined(__NT__) && !defined(UNIV_SIMULATE_AWE)
if (srv_use_awe) {
fprintf(stderr,
"InnoDB: Error: You have specified innodb_buffer_pool_awe_mem_mb\n"
"InnoDB: in my.cnf, but AWE can only be used in Windows 2000 and later.\n");
return(DB_ERROR);
}
#endif
#ifdef __WIN__ #ifdef __WIN__
if (os_get_os_version() == OS_WIN95 if (os_get_os_version() == OS_WIN95
|| os_get_os_version() == OS_WIN31 || os_get_os_version() == OS_WIN31
@ -1049,6 +1074,9 @@ innobase_start_or_create_for_mysql(void)
return(DB_ERROR); return(DB_ERROR);
} }
/* Note that the call srv_boot() also changes the values of
srv_pool_size etc. to the units used by InnoDB internally */
err = srv_boot(); err = srv_boot();
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -1080,7 +1108,26 @@ innobase_start_or_create_for_mysql(void)
fil_init(SRV_MAX_N_OPEN_FILES); fil_init(SRV_MAX_N_OPEN_FILES);
buf_pool_init(srv_pool_size, srv_pool_size); if (srv_use_awe) {
fprintf(stderr,
"InnoDB: Using AWE: Memory window is %lu MB and AWE memory is %lu MB\n",
srv_awe_window_size / ((1024 * 1024) / UNIV_PAGE_SIZE),
srv_pool_size / ((1024 * 1024) / UNIV_PAGE_SIZE));
/* We must disable adaptive hash indexes because they do not
tolerate remapping of pages in AWE */
srv_use_adaptive_hash_indexes = FALSE;
ret = buf_pool_init(srv_pool_size, srv_pool_size,
srv_awe_window_size);
} else {
ret = buf_pool_init(srv_pool_size, srv_pool_size,
srv_pool_size);
}
if (ret == NULL) {
return(DB_ERROR);
}
fsp_init(); fsp_init();
log_init(); log_init();
@ -1160,7 +1207,8 @@ innobase_start_or_create_for_mysql(void)
for (i = 0; i < srv_n_log_files; i++) { for (i = 0; i < srv_n_log_files; i++) {
err = open_or_create_log_file(create_new_db, err = open_or_create_log_file(create_new_db,
&log_file_created, k, i); &log_file_created,
log_opened, k, i);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
return((int) err); return((int) err);

View File

@ -77,6 +77,7 @@ ut_malloc_low(
ret = malloc(n + sizeof(ut_mem_block_t)); ret = malloc(n + sizeof(ut_mem_block_t));
if (ret == NULL) { if (ret == NULL) {
ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
" InnoDB: Fatal error: cannot allocate %lu bytes of\n" " InnoDB: Fatal error: cannot allocate %lu bytes of\n"
"InnoDB: memory with malloc! Total allocated memory\n" "InnoDB: memory with malloc! Total allocated memory\n"
@ -134,6 +135,40 @@ ut_malloc(
return(ut_malloc_low(n, TRUE)); return(ut_malloc_low(n, TRUE));
} }
/**************************************************************************
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
out. It cannot be used if we want to return an error message. Prints to
stderr a message if fails. */
ibool
ut_test_malloc(
/*===========*/
/* out: TRUE if succeeded */
ulint n) /* in: try to allocate this many bytes */
{
void* ret;
ret = malloc(n);
if (ret == NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: cannot allocate %lu bytes of memory for\n"
"InnoDB: a BLOB with malloc! Total allocated memory\n"
"InnoDB: by InnoDB %lu bytes. Operating system errno: %d\n"
"InnoDB: Check if you should increase the swap file or\n"
"InnoDB: ulimits of your operating system.\n"
"InnoDB: On FreeBSD check you have compiled the OS with\n"
"InnoDB: a big enough maximum process size.\n",
n, ut_total_allocated_memory, errno);
return(FALSE);
}
free(ret);
return(TRUE);
}
/************************************************************************** /**************************************************************************
Frees a memory block allocated with ut_malloc. */ Frees a memory block allocated with ut_malloc. */

View File

@ -262,7 +262,7 @@ ut_print_buf(
data = buf; data = buf;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (isprint((char)(*data))) { if (isprint((int)(*data))) {
printf("%c", (char)*data); printf("%c", (char)*data);
} }
data++; data++;
@ -302,7 +302,7 @@ ut_sprintf_buf(
data = buf; data = buf;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (isprint((char)(*data))) { if (isprint((int)(*data))) {
n += sprintf(str + n, "%c", (char)*data); n += sprintf(str + n, "%c", (char)*data);
} else { } else {
n += sprintf(str + n, "."); n += sprintf(str + n, ".");

View File

@ -37,12 +37,12 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \
int2str.lo str2int.lo strinstr.lo strcont.lo \ int2str.lo str2int.lo strinstr.lo strcont.lo \
strcend.lo bcmp.lo \ strcend.lo bcmp.lo \
bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \ bchange.lo bmove.lo bmove_upp.lo longlong2str.lo \
strtoull.lo strtoll.lo llstr.lo \ strtoull.lo strtoll.lo llstr.lo my_vsnprintf.lo \
ctype.lo ctype-simple.lo ctype-bin.lo ctype-mb.lo \ ctype.lo ctype-simple.lo ctype-bin.lo ctype-mb.lo \
ctype-big5.lo ctype-czech.lo ctype-euc_kr.lo \ ctype-big5.lo ctype-czech.lo ctype-euc_kr.lo \
ctype-win1250ch.lo ctype-utf8.lo \ ctype-win1250ch.lo ctype-utf8.lo \
ctype-gb2312.lo ctype-gbk.lo ctype-latin1_de.lo \ ctype-gb2312.lo ctype-gbk.lo ctype-latin1_de.lo \
ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo xml.lo
mystringsextra= strto.c mystringsextra= strto.c
dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo
@ -60,7 +60,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
my_compress.lo array.lo my_once.lo list.lo my_net.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \
charset.lo hash.lo mf_iocache.lo \ charset.lo hash.lo mf_iocache.lo \
mf_iocache2.lo my_seek.lo \ mf_iocache2.lo my_seek.lo \
my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo sha1.lo\ my_pread.lo mf_cache.lo md5.lo sha1.lo\
my_getopt.lo my_gethostbyname.lo my_port.lo my_getopt.lo my_gethostbyname.lo my_port.lo
sqlobjects = net.lo sqlobjects = net.lo

View File

@ -61,7 +61,7 @@ static my_bool mysql_client_init=0;
uint mysql_port=0; uint mysql_port=0;
my_string mysql_unix_port=0; my_string mysql_unix_port=0;
ulong net_buffer_length=8192; ulong net_buffer_length=8192;
ulong max_allowed_packet=16*1024*1024L; ulong max_allowed_packet= 1024L*1024L*1024L;
ulong net_read_timeout= NET_READ_TIMEOUT; ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT; ulong net_write_timeout= NET_WRITE_TIMEOUT;
@ -928,7 +928,8 @@ static const char *default_options[]=
"character-sets-dir", "default-character-set", "interactive-timeout", "character-sets-dir", "default-character-set", "interactive-timeout",
"connect-timeout", "local-infile", "disable-local-infile", "connect-timeout", "local-infile", "disable-local-infile",
"replication-probe", "enable-reads-from-master", "repl-parse-query", "replication-probe", "enable-reads-from-master", "repl-parse-query",
"ssl-cipher","protocol", "shared_memory_base_name", "ssl-cipher", "max-allowed-packet",
"protocol", "shared-memory-base-name",
NullS NullS
}; };
@ -947,7 +948,7 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd)
} }
if (!(tmp= my_strdup(cmd,MYF(MY_WME))) || if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
insert_dynamic(options->init_commands, (byte*)&tmp)) insert_dynamic(options->init_commands, (gptr)&tmp))
{ {
my_free(tmp, MYF(MY_ALLOW_ZERO_PTR)); my_free(tmp, MYF(MY_ALLOW_ZERO_PTR));
return 1; return 1;
@ -1099,14 +1100,17 @@ static void mysql_read_default_options(struct st_mysql_options *options,
case 25: /* repl-parse-query */ case 25: /* repl-parse-query */
options->rpl_parse= 1; options->rpl_parse= 1;
break; break;
case 27:/* protocol */ case 27:
options->max_allowed_packet= atoi(opt_arg);
break;
case 28: /* protocol */
if ((options->protocol = find_type(opt_arg, &sql_protocol_typelib,0)) == ~(ulong) 0) if ((options->protocol = find_type(opt_arg, &sql_protocol_typelib,0)) == ~(ulong) 0)
{ {
fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg); fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg);
exit(1); exit(1);
} }
break; break;
case 28: /*shared_memory_base_name*/ case 29: /* shared_memory_base_name */
#ifdef HAVE_SMEM #ifdef HAVE_SMEM
if (options->shared_memory_base_name != def_shared_memory_base_name) if (options->shared_memory_base_name != def_shared_memory_base_name)
my_free(options->shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); my_free(options->shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
@ -1269,7 +1273,7 @@ static MYSQL_DATA *read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
else else
{ {
cur->data[field] = to; cur->data[field] = to;
if (to+len > end_to) if (len > (ulong) (end_to - to))
{ {
free_rows(result); free_rows(result);
net->last_errno=CR_MALFORMED_PACKET; net->last_errno=CR_MALFORMED_PACKET;
@ -1315,7 +1319,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
{ {
uint field; uint field;
ulong pkt_len,len; ulong pkt_len,len;
uchar *pos,*prev_pos; uchar *pos,*prev_pos, *end_pos;
if ((pkt_len=net_safe_read(mysql)) == packet_error) if ((pkt_len=net_safe_read(mysql)) == packet_error)
return -1; return -1;
@ -1327,6 +1331,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
} }
prev_pos= 0; /* allowed to write at packet[-1] */ prev_pos= 0; /* allowed to write at packet[-1] */
pos=mysql->net.read_pos; pos=mysql->net.read_pos;
end_pos=pos+pkt_len;
for (field=0 ; field < fields ; field++) for (field=0 ; field < fields ; field++)
{ {
if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH) if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
@ -1336,6 +1341,12 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
} }
else else
{ {
if (len > (ulong) (end_pos - pos))
{
mysql->net.last_errno=CR_UNKNOWN_ERROR;
strmov(mysql->net.last_error,ER(mysql->net.last_errno));
return -1;
}
row[field] = (char*) pos; row[field] = (char*) pos;
pos+=len; pos+=len;
*lengths++=len; *lengths++=len;
@ -1753,7 +1764,7 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
mysql->options.ssl_ca= strdup_if_not_null(ca); mysql->options.ssl_ca= strdup_if_not_null(ca);
mysql->options.ssl_capath= strdup_if_not_null(capath); mysql->options.ssl_capath= strdup_if_not_null(capath);
mysql->options.ssl_cipher= strdup_if_not_null(cipher); mysql->options.ssl_cipher= strdup_if_not_null(cipher);
#endif #endif /* HAVE_OPENSSL */
return 0; return 0;
} }
@ -1763,10 +1774,10 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
NB! Errors are not reported until you do mysql_real_connect. NB! Errors are not reported until you do mysql_real_connect.
**************************************************************************/ **************************************************************************/
#ifdef HAVE_OPENSSL
static void static void
mysql_ssl_free(MYSQL *mysql __attribute__((unused))) mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
{ {
#ifdef HAVE_OPENSLL
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
@ -1780,8 +1791,8 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
mysql->options.ssl_cipher= 0; mysql->options.ssl_cipher= 0;
mysql->options.use_ssl = FALSE; mysql->options.use_ssl = FALSE;
mysql->connector_fd = 0; mysql->connector_fd = 0;
#endif /* HAVE_OPENSLL */
} }
#endif /* HAVE_OPENSSL */
/************************************************************************** /**************************************************************************
Connect to sql server Connect to sql server
@ -2235,6 +2246,7 @@ Try also with PIPE or TCP/IP
DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d client_flag: %d", DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d client_flag: %d",
mysql->server_version,mysql->server_capabilities, mysql->server_version,mysql->server_capabilities,
mysql->server_status, client_flag)); mysql->server_status, client_flag));
/* This needs to be changed as it's not useful with big packets */
int3store(buff+2,max_allowed_packet); int3store(buff+2,max_allowed_packet);
if (user && user[0]) if (user && user[0])
strmake(buff+5,user,32); /* Max user name */ strmake(buff+5,user,32); /* Max user name */
@ -2343,6 +2355,8 @@ Try also with PIPE or TCP/IP
if (client_flag & CLIENT_COMPRESS) /* We will use compression */ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1; net->compress=1;
if (mysql->options.max_allowed_packet)
net->max_packet_size= mysql->options.max_allowed_packet;
if (db && mysql_select_db(mysql,db)) if (db && mysql_select_db(mysql,db))
goto error; goto error;
@ -2623,8 +2637,13 @@ mysql_close(MYSQL *mysql)
my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
if (mysql->options.init_commands) if (mysql->options.init_commands)
{ {
delete_dynamic(mysql->options.init_commands); DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
my_free((char*)mysql->options.init_commands,MYF(MY_WME)); char **ptr= (char**)init_commands->buffer;
char **end= ptr + init_commands->elements;
for (; ptr<end; ptr++)
my_free(*ptr,MYF(MY_WME));
delete_dynamic(init_commands);
my_free((char*)init_commands,MYF(MY_WME));
} }
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
mysql_ssl_free(mysql); mysql_ssl_free(mysql);
@ -2841,7 +2860,7 @@ mysql_real_query(MYSQL *mysql, const char *query, ulong length)
{ {
DBUG_ENTER("mysql_real_query"); DBUG_ENTER("mysql_real_query");
DBUG_PRINT("enter",("handle: %lx",mysql)); DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = \"%s\"",query)); DBUG_PRINT("query",("Query = '%-.4096s'",query));
if (mysql_send_query(mysql,query,length)) if (mysql_send_query(mysql,query,length))
DBUG_RETURN(1); DBUG_RETURN(1);
@ -3503,18 +3522,6 @@ uint STDCALL mysql_thread_safe(void)
#endif #endif
} }
MYSQL_RES *STDCALL mysql_warnings(MYSQL *mysql)
{
uint warning_count;
DBUG_ENTER("mysql_warnings");
/* Save warning count as mysql_real_query may change this */
warning_count= mysql->warning_count;
if (mysql_real_query(mysql, "SHOW WARNINGS", 13))
DBUG_RETURN(0);
mysql->warning_count= warning_count;
DBUG_RETURN(mysql_store_result(mysql));
}
/**************************************************************************** /****************************************************************************
Some support functions Some support functions
****************************************************************************/ ****************************************************************************/
@ -3819,12 +3826,13 @@ static my_bool my_realloc_str(NET *net, ulong length)
1 error 1 error
*/ */
static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) static my_bool read_prepare_result(MYSQL_STMT *stmt)
{ {
uchar *pos; uchar *pos;
uint field_count; uint field_count;
ulong length, param_count;
MYSQL_DATA *fields_data; MYSQL_DATA *fields_data;
ulong length; MYSQL *mysql= stmt->mysql;
DBUG_ENTER("read_prepare_result"); DBUG_ENTER("read_prepare_result");
mysql= mysql->last_used_con; mysql= mysql->last_used_con;
@ -3834,7 +3842,7 @@ static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
pos=(uchar*) mysql->net.read_pos; pos=(uchar*) mysql->net.read_pos;
stmt->stmt_id= uint4korr(pos); pos+=4; stmt->stmt_id= uint4korr(pos); pos+=4;
field_count= uint2korr(pos); pos+=2; field_count= uint2korr(pos); pos+=2;
stmt->param_count=uint2korr(pos); pos+=2; param_count= uint2korr(pos); pos+=2;
if (field_count != 0) if (field_count != 0)
{ {
@ -3859,7 +3867,8 @@ static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
} }
stmt->bind= (stmt->params + stmt->param_count); stmt->bind= (stmt->params + stmt->param_count);
stmt->field_count= (uint) field_count; stmt->field_count= (uint) field_count;
mysql->status= MYSQL_STATUS_READY; stmt->param_count= (ulong) param_count;
stmt->mysql->status= MYSQL_STATUS_READY;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -3903,13 +3912,13 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length)
} }
init_alloc_root(&stmt->mem_root,8192,0); init_alloc_root(&stmt->mem_root,8192,0);
if (read_prepare_result(mysql, stmt)) stmt->mysql= mysql;
if (read_prepare_result(stmt))
{ {
stmt_close(stmt, 1); stmt_close(stmt, 1);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
stmt->state= MY_ST_PREPARE; stmt->state= MY_ST_PREPARE;
stmt->mysql= mysql;
mysql->stmts= list_add(mysql->stmts, &stmt->list); mysql->stmts= list_add(mysql->stmts, &stmt->list);
stmt->list.data= stmt; stmt->list.data= stmt;
DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count)); DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count));
@ -3928,10 +3937,14 @@ mysql_prepare_result(MYSQL_STMT *stmt)
MYSQL_RES *result; MYSQL_RES *result;
DBUG_ENTER("mysql_prepare_result"); DBUG_ENTER("mysql_prepare_result");
if (!stmt->fields) if (!stmt->field_count || !stmt->fields)
DBUG_RETURN(0); DBUG_RETURN(0);
result= &stmt->tmp_result;
bzero((char*) result, sizeof(MYSQL_RES)); if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
sizeof(ulong)*stmt->field_count,
MYF(MY_WME | MY_ZEROFILL))))
return 0;
result->eof=1; /* Marker for buffered */ result->eof=1; /* Marker for buffered */
result->fields= stmt->fields; result->fields= stmt->fields;
result->field_count= stmt->field_count; result->field_count= stmt->field_count;
@ -4084,7 +4097,8 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
DBUG_PRINT("enter",("type: %d, buffer:%lx, length: %d", param->buffer_type, DBUG_PRINT("enter",("type: %d, buffer:%lx, length: %d", param->buffer_type,
param->buffer ? param->buffer : "0", *param->length)); param->buffer ? param->buffer : "0", *param->length));
if (param->is_null || param->buffer_type == MYSQL_TYPE_NULL) if (param->buffer_type == MYSQL_TYPE_NULL ||
*param->length == MYSQL_NULL_DATA)
store_param_null(net, param); store_param_null(net, param);
else else
{ {
@ -4096,7 +4110,6 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/* /*
Send the prepare query to server for execution Send the prepare query to server for execution
*/ */
@ -4120,13 +4133,6 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length)
} }
stmt->state= MY_ST_EXECUTE; stmt->state= MY_ST_EXECUTE;
mysql_free_result(stmt->result); mysql_free_result(stmt->result);
#if USED_IN_FETCH
if (stmt->res_buffers) /* Result buffers exists, cache results */
{
mysql_free_result(stmt->result);
stmt->result= mysql_store_result(mysql);
}
#endif
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -4184,7 +4190,7 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt)
for (param= stmt->params; param < param_end; param++) for (param= stmt->params; param < param_end; param++)
{ {
/* Check for long data which has not been propery given/terminated */ /* Check for long data which has not been propery given/terminated */
if (param->is_long_data) if (*param->length == MYSQL_LONG_DATA)
{ {
if (!param->long_ended) if (!param->long_ended)
DBUG_RETURN(MYSQL_NEED_DATA); DBUG_RETURN(MYSQL_NEED_DATA);
@ -4219,6 +4225,14 @@ ulong STDCALL mysql_param_count(MYSQL_STMT * stmt)
DBUG_RETURN(stmt->param_count); DBUG_RETURN(stmt->param_count);
} }
/*
Return total affected rows from the last statement
*/
my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt)
{
return stmt->mysql->last_used_con->affected_rows;
}
/* /*
Setup the parameter data buffers from application Setup the parameter data buffers from application
@ -4252,7 +4266,7 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
param++) param++)
{ {
param->param_number= count++; param->param_number= count++;
if (param->is_long_data && if (param->length && *param->length == MYSQL_LONG_DATA &&
(param->buffer_type < MYSQL_TYPE_TINY_BLOB || (param->buffer_type < MYSQL_TYPE_TINY_BLOB ||
param->buffer_type > MYSQL_TYPE_STRING)) param->buffer_type > MYSQL_TYPE_STRING))
{ {
@ -4275,7 +4289,7 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
/* Setup data copy functions for the different supported types */ /* Setup data copy functions for the different supported types */
switch (param->buffer_type) { switch (param->buffer_type) {
case MYSQL_TYPE_NULL: case MYSQL_TYPE_NULL:
param->is_null=1; param->bind_length= MYSQL_NULL_DATA;
break; break;
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
param->bind_length= 1; param->bind_length= 1;
@ -4406,6 +4420,318 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number,
1 Error (Can't alloc net->buffer) 1 Error (Can't alloc net->buffer)
****************************************************************************/ ****************************************************************************/
/* Return the default binary data length for the common types */
static unsigned int get_binary_length(uint type)
{
switch(type) {
case MYSQL_TYPE_TINY:
return 1;
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_YEAR:
return 2;
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_FLOAT:
return 4;
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_DOUBLE:
return 8;
default:
return 0;
}
}
/* Convert Numeric to buffer types */
static void send_data_long(MYSQL_BIND *param, longlong value)
{
char *buffer= param->buffer;
switch(param->buffer_type) {
case MYSQL_TYPE_TINY:
*param->buffer= (uchar) value;
break;
case MYSQL_TYPE_SHORT:
int2store(buffer, (short)value);
break;
case MYSQL_TYPE_LONG:
int4store(buffer, (int32)value);
break;
case MYSQL_TYPE_LONGLONG:
int8store(buffer, (longlong)value);
break;
case MYSQL_TYPE_FLOAT:
{
float data= (float)value;
float4store(buffer, data);
break;
}
case MYSQL_TYPE_DOUBLE:
{
double data= (double)value;
float8store(buffer, data);
break;
}
default:
{
uint length= sprintf(buffer,"%lld",value);
*param->length= length;
buffer[length]='\0';
}
}
}
/* Convert Double to buffer types */
static void send_data_double(MYSQL_BIND *param, double value)
{
char *buffer= param->buffer;
switch(param->buffer_type) {
case MYSQL_TYPE_TINY:
*buffer= (uchar)value;
break;
case MYSQL_TYPE_SHORT:
int2store(buffer, (short)value);
break;
case MYSQL_TYPE_LONG:
int4store(buffer, (int32)value);
break;
case MYSQL_TYPE_LONGLONG:
int8store(buffer, (longlong)value);
break;
case MYSQL_TYPE_FLOAT:
{
float data= (float)value;
float4store(buffer, data);
break;
}
case MYSQL_TYPE_DOUBLE:
{
double data= (double)value;
float8store(buffer, data);
break;
}
default:
{
uint length= sprintf(buffer,"%g",value);
*param->length= length;
buffer[length]='\0';
}
}
}
/* Convert string to buffer types */
static void send_data_str(MYSQL_BIND *param, char *value, uint length)
{
char *buffer= param->buffer;
switch(param->buffer_type) {
case MYSQL_TYPE_TINY:
{
uchar data= (uchar)my_strntol(system_charset_info,value,length,NULL,10);
*buffer= data;
break;
}
case MYSQL_TYPE_SHORT:
{
short data= (short)my_strntol(system_charset_info,value,length,NULL,10);
int2store(buffer, data);
break;
}
case MYSQL_TYPE_LONG:
{
int32 data= (int32)my_strntol(system_charset_info,value,length,NULL,10);
int4store(buffer, data);
break;
}
case MYSQL_TYPE_LONGLONG:
{
longlong data= my_strntoll(system_charset_info,value,length,NULL,10);
int8store(buffer, data);
break;
}
case MYSQL_TYPE_FLOAT:
{
float data = (float)my_strntod(system_charset_info,value,length,NULL);
float4store(buffer, data);
break;
}
case MYSQL_TYPE_DOUBLE:
{
double data= my_strntod(system_charset_info,value,length,NULL);
float8store(buffer, data);
break;
}
default:
*param->length= length;
memcpy(buffer, value, length);
buffer[length]='\0';
}
}
/* Fetch data to buffers */
static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param,
uint field_type, uchar **row)
{
ulong length;
length= (ulong)get_binary_length(field_type);
switch (field_type) {
case MYSQL_TYPE_TINY:
{
uchar value= (uchar) **row;
send_data_long(param,(longlong)value);
break;
}
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_YEAR:
{
short value= (short)sint2korr(*row);
send_data_long(param,(longlong)value);
break;
}
case MYSQL_TYPE_LONG:
{
int32 value= (int32)sint4korr(*row);
send_data_long(param,(int32)value);
break;
}
case MYSQL_TYPE_LONGLONG:
{
longlong value= (longlong)sint8korr(*row);
send_data_long(param,value);
break;
}
case MYSQL_TYPE_FLOAT:
{
float value;
float4get(value,*row);
send_data_double(param,(double)value);
break;
}
case MYSQL_TYPE_DOUBLE:
{
double value;
float8get(value,*row);
send_data_double(param,(double)value);
break;
}
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
{
uchar month,day;
short year;
int arg_length;
char ts[50],frac[10],time[20],date[20];
if (!(length= net_field_length(row)))
{
*param->length= 0;
break;
}
if (param->buffer_type < MYSQL_TYPE_VAR_STRING ||
param->buffer_type > MYSQL_TYPE_STRING)
{
/*
Don't allow fetching of date/time/ts to non-string types
TODO: Allow fetching of date or time to long types.
*/
sprintf(stmt->last_error,
ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
param->buffer_type, param->param_number);
return 1;
}
arg_length= 0;
if (length > 7)
{
int sec_part= sint4korr(*row+7);
sprintf(frac,".%04d", sec_part);
arg_length+= 5;
}
if (length == 7)
{
uchar hour, minute, sec;
hour= *(*row+4);
minute= *(*row+5);
sec= *(*row+6);
sprintf((char *)time," %02d:%02d:%02d",hour,minute,sec);
arg_length+= 9;
}
year= sint2korr(*row);
month= *(*row+2);
day= *(*row+3);
sprintf((char*) date,"%04d-%02d-%02d",year,month,day);
arg_length+= 10;
if (arg_length != 19)
time[0]='\0';
if (arg_length != 24)
frac[0]='\0';
strxmov(ts,date,time,frac,NullS);
send_data_str(param,ts,arg_length);
break;
}
case MYSQL_TYPE_TIME:
{
int day, arg_length;
uchar hour, minute, sec;
char ts[255], frac[20], time[20];
const char *sign= "";
if (!(length= net_field_length(row)))
{
*param->length= 0;
break;
}
if (param->buffer_type < MYSQL_TYPE_VAR_STRING ||
param->buffer_type > MYSQL_TYPE_STRING)
{
/*
Don't allow fetching of date/time/ts to non-string types
TODO: Allow fetching of time to long types without
any conversion.
*/
sprintf(stmt->last_error,
ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
param->buffer_type, param->param_number);
return 1;
}
arg_length= 0;
if (length > 8)
{
int sec_part= sint4korr(*row+8);
sprintf(frac,".%04d", sec_part);
arg_length+= 5;
}
if (**row)
sign="-";
day= sint4korr(*row); /* TODO: how to handle this case */
hour= *(*row+5);
minute= *(*row+6);
sec= *(*row+7);
arg_length+= sprintf((char *)time,"%s%02d:%02d:%02d",sign,hour,minute,sec);
if (arg_length <= 9)
frac[0]='\0';
strxmov(ts,time,frac,NullS);
send_data_str(param,ts,arg_length);
break;
}
default:
length= net_field_length(row);
send_data_str(param,*row,length);
break;
}
*row+= length;
return 0;
}
static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row) static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row)
{ {
@ -4415,21 +4741,21 @@ static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row)
static void fetch_result_short(MYSQL_BIND *param, uchar **row) static void fetch_result_short(MYSQL_BIND *param, uchar **row)
{ {
short value= *(short *)row; short value = (short)sint2korr(*row);
int2store(param->buffer, value); int2store(param->buffer, value);
*row+= 2; *row+= 2;
} }
static void fetch_result_int32(MYSQL_BIND *param, uchar **row) static void fetch_result_int32(MYSQL_BIND *param, uchar **row)
{ {
int32 value= *(int32 *)row; int32 value= (int32)sint4korr(*row);
int4store(param->buffer, value); int4store(param->buffer, value);
*row+= 4; *row+= 4;
} }
static void fetch_result_int64(MYSQL_BIND *param, uchar **row) static void fetch_result_int64(MYSQL_BIND *param, uchar **row)
{ {
longlong value= *(longlong *)row; longlong value= (longlong)sint8korr(*row);
int8store(param->buffer, value); int8store(param->buffer, value);
*row+= 8; *row+= 8;
} }
@ -4438,7 +4764,7 @@ static void fetch_result_float(MYSQL_BIND *param, uchar **row)
{ {
float value; float value;
float4get(value,*row); float4get(value,*row);
float4store(param->buffer, *row); float4store(param->buffer, value);
*row+= 4; *row+= 4;
} }
@ -4454,6 +4780,7 @@ static void fetch_result_str(MYSQL_BIND *param, uchar **row)
{ {
ulong length= net_field_length(row); ulong length= net_field_length(row);
memcpy(param->buffer, (char *)*row, length); memcpy(param->buffer, (char *)*row, length);
*(param->buffer+length)= '\0';
*param->length= length; *param->length= length;
*row+= length; *row+= length;
} }
@ -4470,6 +4797,11 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
DBUG_ASSERT(stmt != 0); DBUG_ASSERT(stmt != 0);
#ifdef CHECK_EXTRA_ARGUMENTS #ifdef CHECK_EXTRA_ARGUMENTS
if (stmt->state == MY_ST_UNKNOWN)
{
set_stmt_error(stmt, CR_NO_PREPARE_STMT);
DBUG_RETURN(1);
}
if (!bind) if (!bind)
{ {
set_stmt_error(stmt, CR_NULL_POINTER); set_stmt_error(stmt, CR_NULL_POINTER);
@ -4485,35 +4817,29 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
/* Setup data copy functions for the different supported types */ /* Setup data copy functions for the different supported types */
switch (param->buffer_type) { switch (param->buffer_type) {
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
param->bind_length= 1;
param->fetch_result= fetch_result_tinyint; param->fetch_result= fetch_result_tinyint;
break; break;
case MYSQL_TYPE_SHORT: case MYSQL_TYPE_SHORT:
param->bind_length= 2;
param->fetch_result= fetch_result_short; param->fetch_result= fetch_result_short;
break; break;
case MYSQL_TYPE_LONG: case MYSQL_TYPE_LONG:
param->bind_length= 4;
param->fetch_result= fetch_result_int32; param->fetch_result= fetch_result_int32;
break; break;
case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_LONGLONG:
param->bind_length= 8;
param->fetch_result= fetch_result_int64; param->fetch_result= fetch_result_int64;
break; break;
case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_FLOAT:
param->bind_length= 4;
param->fetch_result= fetch_result_float; param->fetch_result= fetch_result_float;
break; break;
case MYSQL_TYPE_DOUBLE: case MYSQL_TYPE_DOUBLE:
param->bind_length= 8;
param->fetch_result= fetch_result_double; param->fetch_result= fetch_result_double;
break; break;
case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING: case MYSQL_TYPE_STRING:
param->length= &param->buffer_length;
param->fetch_result= fetch_result_str; param->fetch_result= fetch_result_str;
break; break;
default: default:
@ -4523,6 +4849,7 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
} }
if (!param->length) if (!param->length)
param->length= &param->bind_length; param->length= &param->bind_length;
*param->length= (long)get_binary_length(param->buffer_type);
} }
stmt->res_buffers= 1; stmt->res_buffers= 1;
DBUG_RETURN(0); DBUG_RETURN(0);
@ -4532,26 +4859,32 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
Fetch row data to bind buffers Fetch row data to bind buffers
*/ */
static my_bool static void
stmt_fetch_row(MYSQL_STMT *stmt, uchar **row) stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
{ {
MYSQL_BIND *bind, *end; MYSQL_BIND *bind, *end;
uchar *null_ptr= (uchar*) *row, bit; MYSQL_FIELD *field, *field_end;
uchar *null_ptr, bit;
row+= (stmt->field_count+9)/8; null_ptr= row;
bit= 4; /* First 2 bits are reserved */ row+= (stmt->field_count+9)/8; /* skip null bits */
bit= 4; /* first 2 bits are reserved */
/* Copy complete row to application buffers */ /* Copy complete row to application buffers */
for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count; for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count,
bind < end; field= stmt->fields,
bind++) field_end= (MYSQL_FIELD *)stmt->fields+stmt->field_count;
bind < end && field < field_end;
bind++, field++)
{ {
if (*null_ptr & bit) if (*null_ptr & bit)
bind->is_null= 1; *bind->length= MYSQL_NULL_DATA;
else else
{ {
bind->is_null= 0; if (field->type == bind->buffer_type)
(*bind->fetch_result)(bind, row); (*bind->fetch_result)(bind, &row);
else if (fetch_results(stmt, bind, field->type, &row))
break;
} }
if (! (bit<<=1) & 255) if (! (bit<<=1) & 255)
{ {
@ -4559,14 +4892,18 @@ stmt_fetch_row(MYSQL_STMT *stmt, uchar **row)
null_ptr++; null_ptr++;
} }
} }
return 0;
} }
static int read_binary_data(MYSQL *mysql) static int read_binary_data(MYSQL *mysql)
{ {
/* TODO : Changes needed based on logic of use_result/store_result
Currently by default it is use_result. In case of
store_result, the data packet must point to already
read data.
*/
if (packet_error == net_safe_read(mysql)) if (packet_error == net_safe_read(mysql))
return -1; return -1;
if (mysql->net.read_pos[0]) if (mysql->net.read_pos[0] == 254)
return 1; /* End of data */ return 1; /* End of data */
return 0; return 0;
} }
@ -4579,30 +4916,25 @@ static int read_binary_data(MYSQL *mysql)
int STDCALL mysql_fetch(MYSQL_STMT *stmt) int STDCALL mysql_fetch(MYSQL_STMT *stmt)
{ {
MYSQL *mysql= stmt->mysql; MYSQL *mysql= stmt->mysql;
int res;
DBUG_ENTER("mysql_fetch"); DBUG_ENTER("mysql_fetch");
if (stmt->res_buffers)
{
int res;
if (!(res= read_binary_data(mysql))) if (!(res= read_binary_data(mysql)))
{ {
if (stmt->res_buffers) if (stmt->res_buffers)
DBUG_RETURN((int) stmt_fetch_row(stmt,(uchar **) &mysql->net.read_pos+1)); stmt_fetch_row(stmt, mysql->net.read_pos+1);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
DBUG_PRINT("info", ("end of data"));
mysql->status= MYSQL_STATUS_READY; mysql->status= MYSQL_STATUS_READY;
if (res < 0) /* Network error */ if (res < 0) /* Network error */
{ {
set_stmt_errmsg(stmt,(char *)mysql->net.last_error, set_stmt_errmsg(stmt,(char *)mysql->net.last_error,
mysql->net.last_errno); mysql->net.last_errno);
DBUG_RETURN(MYSQL_STATUS_ERROR); DBUG_RETURN(1);
} }
DBUG_PRINT("info", ("end of data"));
DBUG_RETURN(MYSQL_NO_DATA); /* no more data */ DBUG_RETURN(MYSQL_NO_DATA); /* no more data */
} }
DBUG_RETURN(0); //?? do we need to set MYSQL_STATUS_READY ?
}
/******************************************************************** /********************************************************************

View File

@ -231,7 +231,7 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd)
} }
if (!(tmp= my_strdup(cmd,MYF(MY_WME))) || if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
insert_dynamic(options->init_commands, (byte*)&tmp)) insert_dynamic(options->init_commands, (gptr)&tmp))
{ {
my_free(tmp, MYF(MY_ALLOW_ZERO_PTR)); my_free(tmp, MYF(MY_ALLOW_ZERO_PTR));
return 1; return 1;
@ -630,8 +630,13 @@ mysql_close(MYSQL *mysql)
my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
if (mysql->options.init_commands) if (mysql->options.init_commands)
{ {
delete_dynamic(mysql->options.init_commands); DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
my_free((char*)mysql->options.init_commands,MYF(MY_WME)); char **ptr= (char**)init_commands->buffer;
char **end= ptr + init_commands->elements;
for (; ptr<end; ptr++)
my_free(*ptr,MYF(MY_WME));
delete_dynamic(init_commands);
my_free((char*)init_commands,MYF(MY_WME));
} }
/* Clear pointers for better safety */ /* Clear pointers for better safety */
bzero((char*) &mysql->options,sizeof(mysql->options)); bzero((char*) &mysql->options,sizeof(mysql->options));

View File

@ -97,6 +97,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
SEARCH_FIND | SEARCH_PREFIX, aio->key_root); SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
aio->info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */
while (!r) while (!r)
{ {

View File

@ -368,8 +368,8 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
{ {
/* Remember old statistics for key */ /* Remember old statistics for key */
memcpy((char*) rec_per_key_part, memcpy((char*) rec_per_key_part,
(char*) share->state.rec_per_key_part+ (char*) (share->state.rec_per_key_part +
(uint) (rec_per_key_part - param->rec_per_key_part), (uint) (rec_per_key_part - param->rec_per_key_part)),
keyinfo->keysegs*sizeof(*rec_per_key_part)); keyinfo->keysegs*sizeof(*rec_per_key_part));
continue; continue;
} }
@ -601,7 +601,8 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
if (*keys != 1L) /* not first_key */ if (*keys != 1L) /* not first_key */
{ {
uint diff; uint diff;
ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,SEARCH_FIND, ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
&diff); &diff);
param->unique_count[diff-1]++; param->unique_count[diff-1]++;
} }
@ -1912,8 +1913,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
{ {
/* Remember old statistics for key */ /* Remember old statistics for key */
memcpy((char*) rec_per_key_part, memcpy((char*) rec_per_key_part,
(char*) share->state.rec_per_key_part+ (char*) (share->state.rec_per_key_part +
(uint) (rec_per_key_part - param->rec_per_key_part), (uint) (rec_per_key_part - param->rec_per_key_part)),
sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part)); sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part));
continue; continue;
} }
@ -2272,8 +2273,8 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
{ {
/* Remember old statistics for key */ /* Remember old statistics for key */
memcpy((char*) rec_per_key_part, memcpy((char*) rec_per_key_part,
(char*) share->state.rec_per_key_part+ (char*) (share->state.rec_per_key_part+
(uint) (rec_per_key_part - param->rec_per_key_part), (uint) (rec_per_key_part - param->rec_per_key_part)),
sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part)); sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part));
i--; i--;
continue; continue;
@ -3656,7 +3657,7 @@ void update_key_parts(MI_KEYDEF *keyinfo, ulong *rec_per_key_part,
} }
ha_checksum mi_byte_checksum(const byte *buf, uint length) static ha_checksum mi_byte_checksum(const byte *buf, uint length)
{ {
ha_checksum crc; ha_checksum crc;
const byte *end=buf+length; const byte *end=buf+length;

View File

@ -55,12 +55,17 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
/* /*
Free buffers and reset the following flags: Free buffers and reset the following flags:
EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK
If the row buffer cache is large (for dynamic tables), reduce it
to save memory.
*/ */
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED)) if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
{ {
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
error=end_io_cache(&info->rec_cache); error=end_io_cache(&info->rec_cache);
} }
if (share->base.blobs)
mi_alloc_rec_buff(info, -1, &info->rec_buff);
#if defined(HAVE_MMAP) && defined(HAVE_MADVICE) #if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
if (info->opt_flag & MEMMAP_USED) if (info->opt_flag & MEMMAP_USED)
madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM); madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM);
@ -358,33 +363,6 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
case HA_EXTRA_QUICK: case HA_EXTRA_QUICK:
info->quick_mode=1; info->quick_mode=1;
break; break;
case HA_EXTRA_BULK_INSERT_BEGIN:
error=_mi_init_bulk_insert(info, (extra_arg ? *(ulong*) extra_arg :
myisam_bulk_insert_tree_size));
break;
case HA_EXTRA_BULK_INSERT_FLUSH:
if (info->bulk_insert)
{
uint index_to_flush= *(uint*) extra_arg;
if (is_tree_inited(&info->bulk_insert[index_to_flush]))
reset_tree(&info->bulk_insert[index_to_flush]);
}
break;
case HA_EXTRA_BULK_INSERT_END:
if (info->bulk_insert)
{
uint i;
for (i=0 ; i < share->base.keys ; i++)
{
if (is_tree_inited(& info->bulk_insert[i]))
{
delete_tree(& info->bulk_insert[i]);
}
}
my_free((void *)info->bulk_insert, MYF(0));
info->bulk_insert=0;
}
break;
case HA_EXTRA_NO_ROWS: case HA_EXTRA_NO_ROWS:
if (!share->state.header.uniques) if (!share->state.header.uniques)
info->opt_flag|= OPT_NO_ROWS; info->opt_flag|= OPT_NO_ROWS;

View File

@ -573,18 +573,26 @@ err:
DBUG_RETURN (NULL); DBUG_RETURN (NULL);
} /* mi_open */ } /* mi_open */
byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf) byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf)
{ {
uint extra; uint extra;
uint32 old_length;
LINT_INIT(old_length);
if (! *buf || length > mi_get_rec_buff_len(info, *buf)) if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
{ {
byte *newptr = *buf; byte *newptr = *buf;
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */ /* to simplify initial init of info->rec_buf in mi_open and mi_extra */
if (length == (ulong) -1) if (length == (ulong) -1)
{
length= max(info->s->base.pack_reclength+info->s->base.pack_bits, length= max(info->s->base.pack_reclength+info->s->base.pack_bits,
info->s->base.max_key_length); info->s->base.max_key_length);
/* Avoid unnecessary realloc */
if (newptr && length == old_length)
return newptr;
}
extra= ((info->s->options & HA_OPTION_PACK_RECORD) ? extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+ ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
@ -594,7 +602,7 @@ byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf)
if (!(newptr=(byte*) my_realloc((gptr)newptr, length+extra+8, if (!(newptr=(byte*) my_realloc((gptr)newptr, length+extra+8,
MYF(MY_ALLOW_ZERO_PTR)))) MYF(MY_ALLOW_ZERO_PTR))))
return newptr; return newptr;
*((uint *)newptr)=length; *((uint32 *) newptr)= (uint32) length;
*buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0); *buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
} }
return *buf; return *buf;

View File

@ -260,9 +260,11 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
uchar *key, uint key_len, uint nextflag, uchar **ret_pos, uchar *key, uint key_len, uint nextflag, uchar **ret_pos,
uchar *buff, my_bool *last_key) uchar *buff, my_bool *last_key)
{ {
/* my_flag is raw comparison result to be changed according to /*
my_flag is raw comparison result to be changed according to
SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags. SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
flag is the value returned by ha_key_cmp and as treated as final */ flag is the value returned by ha_key_cmp and as treated as final
*/
int flag=0, my_flag=-1; int flag=0, my_flag=-1;
uint nod_flag, length, len, matched, cmplen, kseg_len; uint nod_flag, length, len, matched, cmplen, kseg_len;
uint prefix_len,suffix_len; uint prefix_len,suffix_len;

View File

@ -57,7 +57,7 @@ int main(int argc,char *argv[])
} }
int run_test(const char *filename) static int run_test(const char *filename)
{ {
MI_INFO *file; MI_INFO *file;
int i,j,error,deleted,rec_length,uniques=0; int i,j,error,deleted,rec_length,uniques=0;

View File

@ -804,26 +804,27 @@ static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
} }
int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size) int mi_init_bulk_insert(MI_INFO *info, ulong cache_size, ha_rows rows)
{ {
MYISAM_SHARE *share=info->s; MYISAM_SHARE *share=info->s;
MI_KEYDEF *key=share->keyinfo; MI_KEYDEF *key=share->keyinfo;
bulk_insert_param *params; bulk_insert_param *params;
uint i, num_keys; uint i, num_keys, total_keylength;
ulonglong key_map=0; ulonglong key_map=0;
DBUG_ENTER("_mi_init_bulk_insert"); DBUG_ENTER("_mi_init_bulk_insert");
DBUG_PRINT("enter",("cache_size: %lu", cache_size)); DBUG_PRINT("enter",("cache_size: %lu", cache_size));
if (info->bulk_insert) if (info->bulk_insert || (rows && rows < MI_MIN_ROWS_TO_USE_BULK_INSERT))
DBUG_RETURN(0); DBUG_RETURN(0);
for (i=num_keys=0 ; i < share->base.keys ; i++) for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
{ {
if (!(key[i].flag & HA_NOSAME) && share->base.auto_key != i+1 if (!(key[i].flag & HA_NOSAME) && share->base.auto_key != i+1
&& test(share->state.key_map & ((ulonglong) 1 << i))) && test(share->state.key_map & ((ulonglong) 1 << i)))
{ {
num_keys++; num_keys++;
key_map |=((ulonglong) 1 << i); key_map |=((ulonglong) 1 << i);
total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
} }
} }
@ -831,6 +832,11 @@ int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size)
num_keys * MI_MIN_SIZE_BULK_INSERT_TREE > cache_size) num_keys * MI_MIN_SIZE_BULK_INSERT_TREE > cache_size)
DBUG_RETURN(0); DBUG_RETURN(0);
if (rows && rows*total_keylength < cache_size)
cache_size=rows;
else
cache_size/=total_keylength*16;
info->bulk_insert=(TREE *) info->bulk_insert=(TREE *)
my_malloc((sizeof(TREE)*share->base.keys+ my_malloc((sizeof(TREE)*share->base.keys+
sizeof(bulk_insert_param)*num_keys),MYF(0)); sizeof(bulk_insert_param)*num_keys),MYF(0));
@ -839,7 +845,7 @@ int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size)
DBUG_RETURN(HA_ERR_OUT_OF_MEM); DBUG_RETURN(HA_ERR_OUT_OF_MEM);
params=(bulk_insert_param *)(info->bulk_insert+share->base.keys); params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
for (i=0 ; i < share->base.keys ; i++,key++) for (i=0 ; i < share->base.keys ; i++)
{ {
if (test(key_map & ((ulonglong) 1 << i))) if (test(key_map & ((ulonglong) 1 << i)))
{ {
@ -847,8 +853,8 @@ int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size)
params->keynr=i; params->keynr=i;
/* Only allocate a 16'th of the buffer at a time */ /* Only allocate a 16'th of the buffer at a time */
init_tree(&info->bulk_insert[i], init_tree(&info->bulk_insert[i],
cache_size / num_keys / 16 + 10, cache_size * key[i].maxlength,
cache_size / num_keys, 0, cache_size * key[i].maxlength, 0,
(qsort_cmp2)keys_compare, 0, (qsort_cmp2)keys_compare, 0,
(tree_element_free) keys_free, (void *)params++); (tree_element_free) keys_free, (void *)params++);
} }
@ -858,3 +864,30 @@ int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
void mi_flush_bulk_insert(MI_INFO *info, uint inx)
{
if (info->bulk_insert)
{
if (is_tree_inited(&info->bulk_insert[inx]))
reset_tree(&info->bulk_insert[inx]);
}
}
void mi_end_bulk_insert(MI_INFO *info)
{
if (info->bulk_insert)
{
uint i;
for (i=0 ; i < info->s->base.keys ; i++)
{
if (is_tree_inited(& info->bulk_insert[i]))
{
delete_tree(& info->bulk_insert[i]);
}
}
my_free((void *)info->bulk_insert, MYF(0));
info->bulk_insert=0;
}
}

View File

@ -385,7 +385,7 @@ typedef struct st_mi_sort_param
#define MI_DYN_ALIGN_SIZE 4 /* Align blocks on this */ #define MI_DYN_ALIGN_SIZE 4 /* Align blocks on this */
#define MI_MAX_DYN_HEADER_BYTE 13 /* max header byte for dynamic rows */ #define MI_MAX_DYN_HEADER_BYTE 13 /* max header byte for dynamic rows */
#define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1))) #define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1)))
#define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint)) #define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint32))
#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */ #define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
@ -400,6 +400,7 @@ typedef struct st_mi_sort_param
#define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */ #define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */
#define MI_MIN_SIZE_BULK_INSERT_TREE 16384 /* this is per key */ #define MI_MIN_SIZE_BULK_INSERT_TREE 16384 /* this is per key */
#define MI_MIN_ROWS_TO_USE_BULK_INSERT 100
/* The UNIQUE check is done with a hashed long key */ /* The UNIQUE check is done with a hashed long key */
@ -553,7 +554,7 @@ extern byte *mi_alloc_rec_buff(MI_INFO *,ulong, byte**);
((((info)->s->options & HA_OPTION_PACK_RECORD) && (buf)) ? \ ((((info)->s->options & HA_OPTION_PACK_RECORD) && (buf)) ? \
(buf) - MI_REC_BUFF_OFFSET : (buf)) (buf) - MI_REC_BUFF_OFFSET : (buf))
#define mi_get_rec_buff_len(info,buf) \ #define mi_get_rec_buff_len(info,buf) \
(*((uint *)(mi_get_rec_buff_ptr(info,buf)))) (*((uint32 *)(mi_get_rec_buff_ptr(info,buf))))
extern ulong _mi_rec_unpack(MI_INFO *info,byte *to,byte *from, extern ulong _mi_rec_unpack(MI_INFO *info,byte *to,byte *from,
ulong reclength); ulong reclength);
@ -683,8 +684,6 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup);
int mi_open_keyfile(MYISAM_SHARE *share); int mi_open_keyfile(MYISAM_SHARE *share);
void mi_setup_functions(register MYISAM_SHARE *share); void mi_setup_functions(register MYISAM_SHARE *share);
int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size);
/* Functions needed by mi_check */ /* Functions needed by mi_check */
volatile bool *killed_ptr(MI_CHECK *param); volatile bool *killed_ptr(MI_CHECK *param);
void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...)); void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));

View File

@ -28,8 +28,6 @@ ulonglong myrg_position(MYRG_INFO *info)
~(ulonglong) 0; ~(ulonglong) 0;
} }
/* If flag != 0 one only gets pos of last record */
int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag) int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag)
{ {
MYRG_TABLE *current_table; MYRG_TABLE *current_table;
@ -64,6 +62,7 @@ int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag)
x->errkey= current_table->table->errkey; x->errkey= current_table->table->errkey;
else else
x->errkey= 0; x->errkey= 0;
x->rec_per_key = info->rec_per_key_part;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
} }

View File

@ -33,7 +33,7 @@
MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
{ {
int save_errno,i,errpos; int save_errno,i,errpos;
uint files,dir_length,length,options; uint files,dir_length,length,options, key_parts;
ulonglong file_offset; ulonglong file_offset;
char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end; char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
MYRG_INFO info,*m_info; MYRG_INFO info,*m_info;
@ -89,24 +89,39 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
} }
info.reclength=isam->s->base.reclength; info.reclength=isam->s->base.reclength;
} }
key_parts=(isam ? isam->s->base.key_parts : 0);
if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO)+ if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO)+
files*sizeof(MYRG_TABLE), files*sizeof(MYRG_TABLE)+
sizeof(long)*key_parts,
MYF(MY_WME)))) MYF(MY_WME))))
goto err; goto err;
*m_info=info; *m_info=info;
m_info->open_tables=(files) ? (MYRG_TABLE *) (m_info+1) : 0;
m_info->tables=files; m_info->tables=files;
if (files)
{
m_info->open_tables=(MYRG_TABLE *) (m_info+1);
m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files);
bzero((char*) m_info->rec_per_key_part,sizeof(long)*key_parts);
}
else
{
m_info->open_tables=0;
m_info->rec_per_key_part=0;
}
errpos=2; errpos=2;
options= (uint) ~0; options= (uint) ~0;
for (i=files ; i-- > 0 ; ) for (i=files ; i-- > 0 ; )
{ {
uint j;
m_info->open_tables[i].table=isam; m_info->open_tables[i].table=isam;
m_info->options|=isam->s->options; m_info->options|=isam->s->options;
options&=isam->s->options; options&=isam->s->options;
m_info->records+=isam->state->records; m_info->records+=isam->state->records;
m_info->del+=isam->state->del; m_info->del+=isam->state->del;
m_info->data_file_length+=isam->state->data_file_length; m_info->data_file_length+=isam->state->data_file_length;
for (j=0; j < key_parts; j++)
m_info->rec_per_key_part[j]+=isam->s->state.rec_per_key_part[j] / files;
if (i) if (i)
isam=(MI_INFO*) (isam->open_list.next->data); isam=(MI_INFO*) (isam->open_list.next->data);
} }

View File

@ -7,12 +7,16 @@ connection slave;
!stop slave; !stop slave;
@r/slave-stopped.result show status like 'Slave_running'; @r/slave-stopped.result show status like 'Slave_running';
connection master; connection master;
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
reset master; reset master;
connection slave; connection slave;
reset slave; reset slave;
# Clean up old test tables # Clean up old test tables
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
start slave; start slave;
@r/slave-running.result show status like 'Slave_running'; @r/slave-running.result show status like 'Slave_running';

View File

@ -88,6 +88,7 @@ sleep_until_file_created ()
wait_for_pid() wait_for_pid()
{ {
pid=$1 pid=$1
#$WAIT_PID pid $SLEEP_TIME_FOR_DELETE
} }
# No paths below as we can't be sure where the program is! # No paths below as we can't be sure where the program is!
@ -347,9 +348,9 @@ while test $# -gt 0; do
;; ;;
--debug) --debug)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \ EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \
--debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/master.trace" --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/master.trace"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \ EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \
--debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/slave.trace" --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/slave.trace"
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT --debug" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT --debug"
;; ;;
--fast) --fast)
@ -423,6 +424,7 @@ if [ x$SOURCE_DIST = x1 ] ; then
fi fi
MYSQLADMIN="$BASEDIR/client/mysqladmin" MYSQLADMIN="$BASEDIR/client/mysqladmin"
WAIT_PID="$BASEDIR/extra/mysql_waitpid"
MYSQL_MANAGER_CLIENT="$BASEDIR/client/mysqlmanagerc" MYSQL_MANAGER_CLIENT="$BASEDIR/client/mysqlmanagerc"
MYSQL_MANAGER="$BASEDIR/tools/mysqlmanager" MYSQL_MANAGER="$BASEDIR/tools/mysqlmanager"
MYSQL_MANAGER_PWGEN="$BASEDIR/client/mysqlmanager-pwgen" MYSQL_MANAGER_PWGEN="$BASEDIR/client/mysqlmanager-pwgen"
@ -439,6 +441,7 @@ else
fi fi
MYSQL_TEST="$BASEDIR/bin/mysqltest" MYSQL_TEST="$BASEDIR/bin/mysqltest"
MYSQLADMIN="$BASEDIR/bin/mysqladmin" MYSQLADMIN="$BASEDIR/bin/mysqladmin"
WAIT_PID="$BASEDIR/bin/mysql_waitpid"
MYSQL_MANAGER="$BASEDIR/bin/mysqlmanager" MYSQL_MANAGER="$BASEDIR/bin/mysqlmanager"
MYSQL_MANAGER_CLIENT="$BASEDIR/bin/mysqlmanagerc" MYSQL_MANAGER_CLIENT="$BASEDIR/bin/mysqlmanagerc"
MYSQL_MANAGER_PWGEN="$BASEDIR/bin/mysqlmanager-pwgen" MYSQL_MANAGER_PWGEN="$BASEDIR/bin/mysqlmanager-pwgen"
@ -753,9 +756,9 @@ manager_term()
{ {
pid=$1 pid=$1
ident=$2 ident=$2
shift
if [ $USE_MANAGER = 0 ] ; then if [ $USE_MANAGER = 0 ] ; then
$MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=5 --shutdown_timeout=20 shutdown >> $MYSQL_MANAGER_LOG 2>&1 # Shutdown time must be high as slave may be in reconnect
$MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=5 --shutdown_timeout=70 shutdown >> $MYSQL_MANAGER_LOG 2>&1
res=$? res=$?
# Some systems require an extra connect # Some systems require an extra connect
$MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=1 ping >> $MYSQL_MANAGER_LOG 2>&1 $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=1 ping >> $MYSQL_MANAGER_LOG 2>&1
@ -778,8 +781,6 @@ start_master()
if [ x$MASTER_RUNNING = x1 ] || [ x$LOCAL_MASTER = x1 ] ; then if [ x$MASTER_RUNNING = x1 ] || [ x$LOCAL_MASTER = x1 ] ; then
return return
fi fi
# Remove old berkeley db log files that can confuse the server
$RM -f $MASTER_MYDDIR/log.*
# Remove stale binary logs # Remove stale binary logs
$RM -f $MYSQL_TEST_DIR/var/log/master-bin.* $RM -f $MYSQL_TEST_DIR/var/log/master-bin.*
# Remove old master.info files # Remove old master.info files
@ -877,7 +878,7 @@ start_slave()
[ x$SKIP_SLAVE = x1 ] && return [ x$SKIP_SLAVE = x1 ] && return
eval "this_slave_running=\$SLAVE$1_RUNNING" eval "this_slave_running=\$SLAVE$1_RUNNING"
[ x$this_slave_running = 1 ] && return [ x$this_slave_running = 1 ] && return
#when testing fail-safe replication, we will have more than one slave # When testing fail-safe replication, we will have more than one slave
# in this case, we start secondary slaves with an argument # in this case, we start secondary slaves with an argument
slave_ident="slave$1" slave_ident="slave$1"
if [ -n "$1" ] ; if [ -n "$1" ] ;
@ -986,9 +987,12 @@ EOF
mysql_start () mysql_start ()
{ {
$ECHO "Starting MySQL daemon" # We should not start the deamon here as we don't know the argumens
start_master # for the test. Better to let the test start the deamon
start_slave
# $ECHO "Starting MySQL daemon"
# start_master
# start_slave
cd $MYSQL_TEST_DIR cd $MYSQL_TEST_DIR
return 1 return 1
} }
@ -1089,8 +1093,6 @@ run_testcase ()
slave_init_script=$TESTDIR/$tname-slave.sh slave_init_script=$TESTDIR/$tname-slave.sh
slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt
echo $tname > $CURRENT_TEST echo $tname > $CURRENT_TEST
echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0` SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0`
if [ $USE_MANAGER = 1 ] ; then if [ $USE_MANAGER = 1 ] ; then
many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0` many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0`
@ -1127,13 +1129,17 @@ run_testcase ()
then then
EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"` EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"`
stop_master stop_master
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
start_master start_master
else else
if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] ; if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] ;
then then
EXTRA_MASTER_OPT="" EXTRA_MASTER_OPT=""
stop_master stop_master
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
start_master start_master
else
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
fi fi
fi fi
@ -1163,7 +1169,10 @@ run_testcase ()
if [ x$do_slave_restart = x1 ] ; then if [ x$do_slave_restart = x1 ] ; then
stop_slave stop_slave
echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
start_slave start_slave
else
echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
fi fi
if [ x$many_slaves = x1 ]; then if [ x$many_slaves = x1 ]; then
start_slave 1 start_slave 1
@ -1286,6 +1295,9 @@ then
# Remove files that can cause problems # Remove files that can cause problems
$RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/* $RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/*
# Remove old berkeley db log files that can confuse the server
$RM -f $MASTER_MYDDIR/log.*
wait_for_master=$SLEEP_TIME_FOR_FIRST_MASTER wait_for_master=$SLEEP_TIME_FOR_FIRST_MASTER
wait_for_slave=$SLEEP_TIME_FOR_FIRST_SLAVE wait_for_slave=$SLEEP_TIME_FOR_FIRST_SLAVE
$ECHO "Installing Test Databases" $ECHO "Installing Test Databases"

View File

@ -50,10 +50,10 @@ PRIMARY KEY (GROUP_ID,LANG_ID),
KEY NAME (NAME)); KEY NAME (NAME));
ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null; ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null;
SHOW FULL COLUMNS FROM t1; SHOW FULL COLUMNS FROM t1;
Field Type Null Key Default Extra Privileges Comment Field Type Collation Null Key Default Extra Privileges Comment
GROUP_ID int(10) unsigned PRI 0 select,insert,update,references GROUP_ID int(10) unsigned binary PRI 0 select,insert,update,references
LANG_ID smallint(5) unsigned PRI 0 select,insert,update,references LANG_ID smallint(5) unsigned binary PRI 0 select,insert,update,references
NAME char(80) character set latin1 MUL select,insert,update,references NAME char(80) latin1 MUL select,insert,update,references
DROP TABLE t1; DROP TABLE t1;
create table t1 (n int); create table t1 (n int);
insert into t1 values(9),(3),(12),(10); insert into t1 values(9),(3),(12),(10);
@ -118,7 +118,7 @@ create table t1 (i int unsigned not null auto_increment primary key);
alter table t1 rename t2; alter table t1 rename t2;
alter table t2 rename t1, add c char(10) comment "no comment"; alter table t2 rename t1, add c char(10) comment "no comment";
show columns from t1; show columns from t1;
Field Type Null Key Default Extra Field Type Collation Null Key Default Extra
i int(10) unsigned PRI NULL auto_increment i int(10) unsigned binary PRI NULL auto_increment
c char(10) character set latin1 YES NULL c char(10) latin1 YES NULL
drop table t1; drop table t1;

View File

@ -1,5 +1,5 @@
set SQL_LOG_BIN=0; set SQL_LOG_BIN=0;
drop table if exists t1; drop table if exists t1, t2, t3;
create table t1(n int); create table t1(n int);
backup table t1 to '../bogus'; backup table t1 to '../bogus';
Table Op Msg_type Msg_text Table Op Msg_type Msg_text

View File

@ -797,7 +797,6 @@ select * from t1 where i=1 and j=2;
i j i j
1 2 1 2
drop table t1; drop table t1;
drop table if exists t1, t2, t3, t4, t5, t6, t7;
create table t1 create table t1
( (
branch_id int auto_increment primary key, branch_id int auto_increment primary key,
@ -806,7 +805,6 @@ branch_active int not null default 1,
unique branch_name(branch_name), unique branch_name(branch_name),
index branch_active(branch_active) index branch_active(branch_active)
) type=bdb; ) type=bdb;
drop table if exists t2 ;
create table t2 create table t2
( (
target_id int auto_increment primary key, target_id int auto_increment primary key,
@ -815,7 +813,6 @@ target_active int not null default 1,
unique target_name(target_name), unique target_name(target_name),
index target_active(target_active) index target_active(target_active)
) type=bdb; ) type=bdb;
drop table if exists t3 ;
create table t3 create table t3
( (
platform_id int auto_increment primary key, platform_id int auto_increment primary key,
@ -824,7 +821,6 @@ platform_active int not null default 1,
unique platform_name(platform_name), unique platform_name(platform_name),
index platform_active(platform_active) index platform_active(platform_active)
) type=bdb; ) type=bdb;
drop table if exists t4 ;
create table t4 create table t4
( (
product_id int auto_increment primary key, product_id int auto_increment primary key,
@ -834,7 +830,6 @@ product_active int not null default 1,
unique product_name(product_name), unique product_name(product_name),
index product_active(product_active) index product_active(product_active)
) type=bdb; ) type=bdb;
drop table if exists t5 ;
create table t5 create table t5
( (
product_file_id int auto_increment primary key, product_file_id int auto_increment primary key,
@ -847,7 +842,6 @@ file_included int not null default 1,
unique product_file(product_id,file_name), unique product_file(product_id,file_name),
index file_included(file_included) index file_included(file_included)
) type=bdb; ) type=bdb;
drop table if exists t6 ;
create table t6 create table t6
( (
file_platform_id int auto_increment primary key, file_platform_id int auto_increment primary key,
@ -860,7 +854,6 @@ build_filename varchar(255) not null,
archive_filename varchar(255) not null, archive_filename varchar(255) not null,
unique file_platform(product_file_id,platform_id,branch_id) unique file_platform(product_file_id,platform_id,branch_id)
) type=bdb; ) type=bdb;
drop table if exists t8 ;
create table t8 create table t8
( (
archive_id int auto_increment primary key, archive_id int auto_increment primary key,
@ -872,7 +865,6 @@ status_id int not null default 1,
unique archive(branch_id,target_id,platform_id,product_id), unique archive(branch_id,target_id,platform_id,product_id),
index status_id(status_id) index status_id(status_id)
) type=bdb; ) type=bdb;
drop table if exists t7 ;
create table t7 create table t7
( (
build_id int auto_increment primary key, build_id int auto_increment primary key,
@ -1057,7 +1049,6 @@ KINMU_DATE
select T1.KINMU_DATE from t1 T1 ,t2 T2 where T1.SYAIN_NO = '12345' and T1.KINMU_DATE = '200106' and T2.SYAIN_NO = T1.SYAIN_NO; select T1.KINMU_DATE from t1 T1 ,t2 T2 where T1.SYAIN_NO = '12345' and T1.KINMU_DATE = '200106' and T2.SYAIN_NO = T1.SYAIN_NO;
KINMU_DATE KINMU_DATE
DROP TABLE t1,t2; DROP TABLE t1,t2;
drop table if exists t1;
create table t1 (a int(11) not null, b int(11) not null, unique (a,b)) type=bdb; create table t1 (a int(11) not null, b int(11) not null, unique (a,b)) type=bdb;
insert into t1 values (1,1), (1,2); insert into t1 values (1,1), (1,2);
select * from t1 where a = 1; select * from t1 where a = 1;

View File

@ -1,3 +1,4 @@
drop table if exists t1;
select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296; select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296;
0 256 00000000000000065536 2147483647 -2147483648 2147483648 +4294967296 0 256 00000000000000065536 2147483647 -2147483648 2147483648 +4294967296
0 256 65536 2147483647 -2147483648 2147483648 4294967296 0 256 65536 2147483647 -2147483648 2147483648 4294967296
@ -7,7 +8,6 @@ select 9223372036854775807,-009223372036854775808;
select +9999999999999999999,-9999999999999999999; select +9999999999999999999,-9999999999999999999;
+9999999999999999999 -9999999999999999999 +9999999999999999999 -9999999999999999999
10000000000000000000 -10000000000000000000 10000000000000000000 -10000000000000000000
drop table if exists t1;
create table t1 (a bigint unsigned not null, primary key(a)); create table t1 (a bigint unsigned not null, primary key(a));
insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE); insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE);
select * from t1; select * from t1;

View File

@ -46,10 +46,9 @@ SELECT @a, @b;
@a @b @a @b
0 6 0 6
DROP TABLE t1; DROP TABLE t1;
drop table if exists t; create table t1 (a int, b int);
create table t(a int, b int); insert into t1 values(null, null), (0, null), (1, null), (null, 0), (null, 1), (0, 0), (0, 1), (1, 0), (1, 1);
insert into t values(null, null), (0, null), (1, null), (null, 0), (null, 1), (0, 0), (0, 1), (1, 0), (1, 1); select ifnull(A, 'N') as A, ifnull(B, 'N') as B, ifnull(not A, 'N') as nA, ifnull(not B, 'N') as nB, ifnull(A and B, 'N') as AB, ifnull(not (A and B), 'N') as `n(AB)`, ifnull((not A or not B), 'N') as nAonB, ifnull(A or B, 'N') as AoB, ifnull(not(A or B), 'N') as `n(AoB)`, ifnull(not A and not B, 'N') as nAnB from t1;
select ifnull(A, 'N') as A, ifnull(B, 'N') as B, ifnull(not A, 'N') as nA, ifnull(not B, 'N') as nB, ifnull(A and B, 'N') as AB, ifnull(not (A and B), 'N') as `n(AB)`, ifnull((not A or not B), 'N') as nAonB, ifnull(A or B, 'N') as AoB, ifnull(not(A or B), 'N') as `n(AoB)`, ifnull(not A and not B, 'N') as nAnB from t;
A B nA nB AB n(AB) nAonB AoB n(AoB) nAnB A B nA nB AB n(AB) nAonB AoB n(AoB) nAnB
N N N N N N N N N N N N N N N N N N N N
0 N 1 N 0 1 1 N N N 0 N 1 N 0 1 1 N N N
@ -60,7 +59,7 @@ N 1 N 0 N N N 1 0 0
0 1 1 0 0 1 1 1 0 0 0 1 1 0 0 1 1 1 0 0
1 0 0 1 0 1 1 1 0 0 1 0 0 1 0 1 1 1 0 0
1 1 0 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0
select ifnull(A=1, 'N') as A, ifnull(B=1, 'N') as B, ifnull(not (A=1), 'N') as nA, ifnull(not (B=1), 'N') as nB, ifnull((A=1) and (B=1), 'N') as AB, ifnull(not ((A=1) and (B=1)), 'N') as `n(AB)`, ifnull((not (A=1) or not (B=1)), 'N') as nAonB, ifnull((A=1) or (B=1), 'N') as AoB, ifnull(not((A=1) or (B=1)), 'N') as `n(AoB)`, ifnull(not (A=1) and not (B=1), 'N') as nAnB from t; select ifnull(A=1, 'N') as A, ifnull(B=1, 'N') as B, ifnull(not (A=1), 'N') as nA, ifnull(not (B=1), 'N') as nB, ifnull((A=1) and (B=1), 'N') as AB, ifnull(not ((A=1) and (B=1)), 'N') as `n(AB)`, ifnull((not (A=1) or not (B=1)), 'N') as nAonB, ifnull((A=1) or (B=1), 'N') as AoB, ifnull(not((A=1) or (B=1)), 'N') as `n(AoB)`, ifnull(not (A=1) and not (B=1), 'N') as nAnB from t1;
A B nA nB AB n(AB) nAonB AoB n(AoB) nAnB A B nA nB AB n(AB) nAonB AoB n(AoB) nAnB
N N N N N N N N N N N N N N N N N N N N
0 N 1 N 0 1 1 N N N 0 N 1 N 0 1 1 N N N
@ -71,4 +70,4 @@ N 1 N 0 N N N 1 0 0
0 1 1 0 0 1 1 1 0 0 0 1 1 0 0 1 1 1 0 0
1 0 0 1 0 1 1 1 0 0 1 0 0 1 0 1 1 1 0 0
1 1 0 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0
drop table t; drop table t1;

View File

@ -63,3 +63,11 @@ nothing 2
one 1 one 1
two 1 two 1
drop table t1; drop table t1;
create table t1 (row int not null, col int not null, val varchar(255) not null);
insert into t1 values (1,1,'orange'),(1,2,'large'),(2,1,'yellow'),(2,2,'medium'),(3,1,'green'),(3,2,'small');
select max(case col when 1 then val else null end) as color from t1 group by row;
color
orange
yellow
green
drop table t1;

View File

@ -1,4 +1,4 @@
drop table if exists t1,t2; drop table if exists t1,t2,t3;
create table t1 (b char(0)); create table t1 (b char(0));
insert into t1 values (""),(null); insert into t1 values (""),(null);
select * from t1; select * from t1;
@ -13,12 +13,15 @@ select * from t1;
b b
drop table if exists t1; drop table t1;
create table t2 type=heap select * from t1; create table t2 type=heap select * from t1;
Table 'test.t1' doesn't exist Table 'test.t1' doesn't exist
create table t2 select auto+1 from t1; create table t2 select auto+1 from t1;
Table 'test.t1' doesn't exist Table 'test.t1' doesn't exist
drop table if exists t1,t2; drop table if exists t1,t2;
Warnings:
Note 1051 Unknown table 't1'
Note 1051 Unknown table 't2'
create table t1 (b char(0) not null, index(b)); create table t1 (b char(0) not null, index(b));
The used table handler can't index column 'b' The used table handler can't index column 'b'
create table t1 (a int not null auto_increment,primary key (a)) type=heap; create table t1 (a int not null auto_increment,primary key (a)) type=heap;
@ -48,6 +51,8 @@ drop table 1ea10;
create table t1 (t1.index int); create table t1 (t1.index int);
drop table t1; drop table t1;
drop database if exists test_$1; drop database if exists test_$1;
Warnings:
Note 1008 Can't drop database 'test_$1'. Database doesn't exist
create database test_$1; create database test_$1;
create table test_$1.$test1 (a$1 int, $b int, c$ int); create table test_$1.$test1 (a$1 int, $b int, c$ int);
insert into test_$1.$test1 values (1,2,3); insert into test_$1.$test1 values (1,2,3);
@ -70,47 +75,53 @@ drop table t1,t2;
create table t1(x varchar(50) ); create table t1(x varchar(50) );
create table t2 select x from t1 where 1=2; create table t2 select x from t1 where 1=2;
describe t1; describe t1;
Field Type Null Key Default Extra Field Type Collation Null Key Default Extra
x varchar(50) character set latin1 YES NULL x varchar(50) latin1 YES NULL
describe t2; describe t2;
Field Type Null Key Default Extra Field Type Collation Null Key Default Extra
x char(50) character set latin1 YES NULL x char(50) latin1 YES NULL
drop table t2; drop table t2;
create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f; create table t2 select now() as a , curtime() as b, curdate() as c , 1+1 as d , 1.0 + 1 as e , 33333333333333333 + 3 as f;
describe t2; describe t2;
Field Type Null Key Default Extra Field Type Collation Null Key Default Extra
a datetime 0000-00-00 00:00:00 a datetime latin1 0000-00-00 00:00:00
b time 00:00:00 b time latin1 00:00:00
c date 0000-00-00 c date latin1 0000-00-00
d bigint(17) 0 d bigint(17) binary 0
e double(18,1) 0.0 e double(18,1) binary 0.0
f bigint(17) 0 f bigint(17) binary 0
drop table t2; drop table t2;
create table t2 select CAST("2001-12-29" AS DATE) as d, CAST("20:45:11" AS TIME) as t, CAST("2001-12-29 20:45:11" AS DATETIME) as dt; create table t2 select CAST("2001-12-29" AS DATE) as d, CAST("20:45:11" AS TIME) as t, CAST("2001-12-29 20:45:11" AS DATETIME) as dt;
describe t2; describe t2;
Field Type Null Key Default Extra Field Type Collation Null Key Default Extra
d date 0000-00-00 d date latin1 0000-00-00
t time 00:00:00 t time latin1 00:00:00
dt datetime 0000-00-00 00:00:00 dt datetime latin1 0000-00-00 00:00:00
drop table t1,t2; drop table t1,t2;
create table t1 (a tinyint); create table t1 (a tinyint);
create table t2 (a int) select * from t1; create table t2 (a int) select * from t1;
describe t1; describe t1;
Field Type Null Key Default Extra Field Type Collation Null Key Default Extra
a tinyint(4) YES NULL a tinyint(4) binary YES NULL
describe t2; describe t2;
Field Type Null Key Default Extra Field Type Collation Null Key Default Extra
a int(11) YES NULL a int(11) binary YES NULL
drop table if exists t2; drop table if exists t2;
create table t2 (a int, a float) select * from t1; create table t2 (a int, a float) select * from t1;
Duplicate column name 'a' Duplicate column name 'a'
drop table if exists t2; drop table if exists t2;
Warnings:
Note 1051 Unknown table 't2'
create table t2 (a int) select a as b, a+1 as b from t1; create table t2 (a int) select a as b, a+1 as b from t1;
Duplicate column name 'b' Duplicate column name 'b'
drop table if exists t2; drop table if exists t2;
Warnings:
Note 1051 Unknown table 't2'
create table t2 (b int) select a as b, a+1 as b from t1; create table t2 (b int) select a as b, a+1 as b from t1;
Duplicate column name 'b' Duplicate column name 'b'
drop table if exists t1,t2; drop table if exists t1,t2;
Warnings:
Note 1051 Unknown table 't2'
create table t1 (a int not null, b int, primary key(a), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b)); create table t1 (a int not null, b int, primary key(a), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b), key (b));
show create table t1; show create table t1;
Table Create Table Table Create Table
@ -161,3 +172,75 @@ drop table if exists t1;
create table t1 (a int, key(a)); create table t1 (a int, key(a));
create table t2 (b int, foreign key(b) references t1(a), key(b)); create table t2 (b int, foreign key(b) references t1(a), key(b));
drop table if exists t1,t2; drop table if exists t1,t2;
create table t1(id int not null, name char(20));
insert into t1 values(10,'mysql'),(20,'monty- the creator');
create table t2(id int not null);
insert into t2 values(10),(20);
create table t3 like t1;
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`id` int(11) NOT NULL default '0',
`name` char(20) default NULL
) TYPE=MyISAM CHARSET=latin1
select * from t3;
id name
create table if not exists t3 like t1;
Warnings:
Warning 1050 Table 't3' already exists
select @@warning_count;
@@warning_count
1
create temporary table t3 like t2;
show create table t3;
Table Create Table
t3 CREATE TEMPORARY TABLE `t3` (
`id` int(11) NOT NULL default '0'
) TYPE=MyISAM CHARSET=latin1
select * from t3;
id
drop table t3;
show create table t3;
Table Create Table
t3 CREATE TABLE `t3` (
`id` int(11) NOT NULL default '0',
`name` char(20) default NULL
) TYPE=MyISAM CHARSET=latin1
select * from t3;
id name
drop table t2, t3;
drop database if exists test_$1;
Warnings:
Note 1008 Can't drop database 'test_$1'. Database doesn't exist
create database test_$1;
create table test_$1.t3 like t1;
create temporary table t3 like test_$1.t3;
show create table t3;
Table Create Table
t3 CREATE TEMPORARY TABLE `t3` (
`id` int(11) NOT NULL default '0',
`name` char(20) default NULL
) TYPE=MyISAM CHARSET=latin1
create table t2 like t3;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL default '0',
`name` char(20) default NULL
) TYPE=MyISAM CHARSET=latin1
select * from t2;
id name
create table t3 like t1;
create table t3 like test_$1.t3;
Table 't3' already exists
create table non_existing_database.t1 like t1;
Got one of the listed errors
create table t3 like non_existing_table;
Unknown table 'non_existing_table'
create temporary table t3 like t1;
Table 't3' already exists
create table t3 like `a/a`;
Incorrect table name 'a/a'
drop table t1, t2, t3;
drop table t3;
drop database test_$1;

View File

@ -1,45 +1,45 @@
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
CREATE TABLE t1 ( CREATE TABLE t1 (
comment CHAR(32) ASCII NOT NULL, comment CHAR(32) ASCII NOT NULL,
koi8_ru_f CHAR(32) CHARACTER SET koi8_ru NOT NULL koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL
) CHARSET=latin5; ) CHARSET=latin5;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`comment` char(32) character set latin1 NOT NULL default '', `comment` char(32) character set latin1 NOT NULL default '',
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default '' `koi8_ru_f` char(32) character set koi8r NOT NULL default ''
) TYPE=MyISAM CHARSET=latin5 ) TYPE=MyISAM CHARSET=latin5
ALTER TABLE t1 CHANGE comment comment CHAR(32) CHARACTER SET latin2 NOT NULL; ALTER TABLE t1 CHANGE comment comment CHAR(32) CHARACTER SET latin2 NOT NULL;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`comment` char(32) character set latin2 NOT NULL default '', `comment` char(32) character set latin2 NOT NULL default '',
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default '' `koi8_ru_f` char(32) character set koi8r NOT NULL default ''
) TYPE=MyISAM CHARSET=latin5 ) TYPE=MyISAM CHARSET=latin5
ALTER TABLE t1 ADD latin5_f CHAR(32) NOT NULL; ALTER TABLE t1 ADD latin5_f CHAR(32) NOT NULL;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`comment` char(32) character set latin2 NOT NULL default '', `comment` char(32) character set latin2 NOT NULL default '',
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default '', `koi8_ru_f` char(32) character set koi8r NOT NULL default '',
`latin5_f` char(32) character set latin5 NOT NULL default '' `latin5_f` char(32) NOT NULL default ''
) TYPE=MyISAM CHARSET=latin5 ) TYPE=MyISAM CHARSET=latin5
ALTER TABLE t1 CHARSET=latin2; ALTER TABLE t1 CHARSET=latin2;
ALTER TABLE t1 ADD latin2_f CHAR(32) NOT NULL; ALTER TABLE t1 ADD latin2_f CHAR(32) NOT NULL;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`comment` char(32) character set latin2 NOT NULL default '', `comment` char(32) NOT NULL default '',
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default '', `koi8_ru_f` char(32) character set koi8r NOT NULL default '',
`latin5_f` char(32) character set latin5 NOT NULL default '', `latin5_f` char(32) character set latin5 NOT NULL default '',
`latin2_f` char(32) character set latin2 NOT NULL default '' `latin2_f` char(32) NOT NULL default ''
) TYPE=MyISAM CHARSET=latin2 ) TYPE=MyISAM CHARSET=latin2
ALTER TABLE t1 DROP latin2_f, DROP latin5_f; ALTER TABLE t1 DROP latin2_f, DROP latin5_f;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`comment` char(32) character set latin2 NOT NULL default '', `comment` char(32) NOT NULL default '',
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default '' `koi8_ru_f` char(32) character set koi8r NOT NULL default ''
) TYPE=MyISAM CHARSET=latin2 ) TYPE=MyISAM CHARSET=latin2
INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A'); INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A');
INSERT INTO t1 (koi8_ru_f,comment) VALUES ('b','LAT SMALL B'); INSERT INTO t1 (koi8_ru_f,comment) VALUES ('b','LAT SMALL B');
@ -336,6 +336,11 @@ CYR CAPIT SOFT SIGN
CYR CAPIT E <09> Э CYR CAPIT E <09> Э
CYR CAPIT YU <09> Ю CYR CAPIT YU <09> Ю
CYR CAPIT YA <09> Я CYR CAPIT YA <09> Я
ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL;
UPDATE t1 SET bin_f=koi8_ru_f;
SELECT COUNT(DISTINCT bin_f),COUNT(DISTINCT koi8_ru_f),COUNT(DISTINCT utf8_f) FROM t1;
COUNT(DISTINCT bin_f) COUNT(DISTINCT koi8_ru_f) COUNT(DISTINCT utf8_f)
116 58 57
SELECT koi8_ru_f,MIN(comment) FROM t1 GROUP BY 1; SELECT koi8_ru_f,MIN(comment) FROM t1 GROUP BY 1;
koi8_ru_f MIN(comment) koi8_ru_f MIN(comment)
a LAT CAPIT A a LAT CAPIT A
@ -1056,7 +1061,7 @@ CYR SMALL YA CYR CAPIT YA
CYR SMALL YA CYR SMALL YA CYR SMALL YA CYR SMALL YA
SELECT t11.comment,t12.comment SELECT t11.comment,t12.comment
FROM t1 t11,t1 t12 FROM t1 t11,t1 t12
WHERE t11.koi8_ru_f=CONVERT(t12.utf8_f USING koi8_ru) WHERE t11.koi8_ru_f=CONVERT(t12.utf8_f USING koi8r)
ORDER BY t12.utf8_f,t11.comment,t12.comment; ORDER BY t12.utf8_f,t11.comment,t12.comment;
comment comment comment comment
LAT CAPIT A LAT CAPIT A LAT CAPIT A LAT CAPIT A

Some files were not shown because too many files have changed in this diff Show More