mirror of
https://github.com/MariaDB/server.git
synced 2025-07-21 21:22:27 +03:00
resolving conflicts
This commit is contained in:
@ -580,3 +580,5 @@ vio/test-sslclient
|
||||
vio/test-sslserver
|
||||
vio/viotest-ssl
|
||||
libmysqld/protocol.cc
|
||||
test_xml
|
||||
extra/mysql_waitpid
|
||||
|
@ -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
|
||||
# able to backtrace
|
||||
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"
|
||||
|
||||
|
@ -26,6 +26,7 @@ hf@bisonxp.(none)
|
||||
hf@deer.mysql.r18.ru
|
||||
hf@genie.(none)
|
||||
jani@dsl-jkl1657.dial.inet.fi
|
||||
jani@dsl-kpogw4gb5.dial.inet.fi
|
||||
jani@hynda.(none)
|
||||
jani@hynda.mysql.fi
|
||||
jani@janikt.pp.saunalahti.fi
|
||||
@ -69,7 +70,9 @@ peter@mysql.com
|
||||
ram@gw.udmsearch.izhnet.ru
|
||||
ram@mysql.r18.ru
|
||||
ram@ram.(none)
|
||||
ranger@regul.home.lan
|
||||
root@x3.internalnet
|
||||
salle@banica.(none)
|
||||
salle@geopard.(none)
|
||||
salle@geopard.online.bg
|
||||
sasha@mysql.sashanet.com
|
||||
@ -95,6 +98,7 @@ venu@myvenu.com
|
||||
venu@work.mysql.com
|
||||
vva@eagle.mysql.r18.ru
|
||||
vva@genie.(none)
|
||||
walrus@kishkin.ru
|
||||
walrus@mysql.com
|
||||
wax@mysql.com
|
||||
worm@altair.is.lan
|
||||
|
@ -8,7 +8,7 @@ use Getopt::Long;
|
||||
$opt_distribution=$opt_user=$opt_config_env="";
|
||||
$opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_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;
|
||||
|
||||
GetOptions(
|
||||
@ -30,7 +30,9 @@ GetOptions(
|
||||
"no-crash-me",
|
||||
"no-perl",
|
||||
"no-strip",
|
||||
"no-test|no-mysqltest",
|
||||
"no-test",
|
||||
"no-mysqltest",
|
||||
"no-benchmark",
|
||||
"perl-files=s",
|
||||
"perl-options=s",
|
||||
"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";
|
||||
$slave_port=$mysql_tcp_port+16;
|
||||
$manager_port=$mysql_tcp_port+1;
|
||||
$mysqladmin_args="--no-defaults -u root --connect_timeout=5 --shutdown_timeout=20";
|
||||
|
||||
if ($opt_stage == 0)
|
||||
{
|
||||
@ -148,19 +151,26 @@ select STDOUT;
|
||||
$|=1;
|
||||
|
||||
info("Compiling MySQL$opt_version_suffix at $host$opt_suffix, stage: $opt_stage\n");
|
||||
log_timestamp();
|
||||
|
||||
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 --no-defaults -u root -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 --no-defaults -u root -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 -S $mysql_unix_port -s shutdown");
|
||||
log_system("$host/bin/mysqladmin $mysqladmin_args -P $mysql_tcp_port -h $host -s shutdown");
|
||||
log_system("$host/bin/mysqladmin $mysqladmin_args -P $slave_port -h $host -s shutdown");
|
||||
log_system("$host/bin/mysqladmin $mysqladmin_args -P 9306 -h $host -s shutdown");
|
||||
log_system("$host/bin/mysqladmin $mysqladmin_args -P 9307 -h $host -s shutdown");
|
||||
}
|
||||
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)
|
||||
{
|
||||
log_timestamp();
|
||||
print "$host: Removing old distribution\n" if ($opt_debug);
|
||||
if (!$opt_use_old_distribution)
|
||||
{
|
||||
@ -209,6 +219,7 @@ safe_cd("$pwd/$host/$ver");
|
||||
if ($opt_stage <= 1)
|
||||
{
|
||||
# Fix files if this is in another timezone than the build host
|
||||
log_timestamp();
|
||||
unlink("config.cache");
|
||||
unlink("bdb/build_unix/config.cache");
|
||||
unlink("innobase/config.cache");
|
||||
@ -252,6 +263,7 @@ if ($opt_stage <= 1)
|
||||
if ($opt_stage <= 2)
|
||||
{
|
||||
my ($command);
|
||||
log_timestamp();
|
||||
unlink($opt_distribution) if ($opt_delete && !$opt_use_old_distribution);
|
||||
$command=$make;
|
||||
$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)
|
||||
{
|
||||
my $flags= "";
|
||||
log_timestamp();
|
||||
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");
|
||||
|
||||
@ -292,6 +305,7 @@ if (!defined($tar_file))
|
||||
#
|
||||
if ($opt_stage <= 4 && !$opt_no_test)
|
||||
{
|
||||
log_timestamp();
|
||||
rm_all(<$pwd/$host/test/*>);
|
||||
safe_cd("$pwd/$host/test");
|
||||
safe_system("gunzip < $tar_file | $tar xf -");
|
||||
@ -300,13 +314,15 @@ if ($opt_stage <= 4 && !$opt_no_test)
|
||||
$tar_file =~ /(mysql[^\/]*)\.tar/;
|
||||
$ver=$1;
|
||||
$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
|
||||
#
|
||||
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);
|
||||
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");
|
||||
@ -315,11 +331,11 @@ if ($opt_stage <= 5 && !$opt_no_test)
|
||||
#
|
||||
# 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;
|
||||
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);
|
||||
log_system("rm -f ./data/mysql/*");
|
||||
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
|
||||
#
|
||||
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);
|
||||
rm_all("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)
|
||||
{
|
||||
log_timestamp();
|
||||
safe_cd("$test_dir/sql-bench");
|
||||
log_system("rm -f limits/mysql.cfg");
|
||||
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
|
||||
#
|
||||
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");
|
||||
log_system("rm -f output/*");
|
||||
$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("$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";
|
||||
close LOG;
|
||||
print "$host: ok\n";
|
||||
@ -416,7 +436,7 @@ exit 0;
|
||||
sub usage
|
||||
{
|
||||
print <<EOF;
|
||||
$0 version 1.4
|
||||
$0 version 1.5
|
||||
|
||||
$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
|
||||
|
||||
--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
|
||||
Compile and install the given perl modules.
|
||||
@ -532,6 +558,7 @@ sub abort
|
||||
my($mail_header_file);
|
||||
print LOG "\n$message\n";
|
||||
print "$host: $message\n" if ($opt_debug);
|
||||
print LOG "Aborting\n";
|
||||
close LOG;
|
||||
|
||||
if ($opt_user)
|
||||
@ -547,7 +574,6 @@ sub abort
|
||||
unlink($mail_header_file);
|
||||
unlink("$log.mail");
|
||||
}
|
||||
print LOG "Aborting\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
@ -689,9 +715,10 @@ sub rm_all
|
||||
sub kill_all
|
||||
{
|
||||
my ($pattern) = @_;
|
||||
my ($USER,$BSD,$LINUX, $pscmd, $user, $pid);
|
||||
my ($USER,$BSD,$LINUX, $pscmd, $user, $os, $pid);
|
||||
$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';
|
||||
$pscmd = $BSD ? "/bin/ps -auxww" : $LINUX ? "/bin/ps axuw" : "/bin/ps -ef";
|
||||
|
||||
@ -707,7 +734,7 @@ sub kill_all
|
||||
{
|
||||
chop($cand);
|
||||
($pid_user, $pid) = split(' ', $cand);
|
||||
next if $pid == $$;
|
||||
next if $pid eq $$;
|
||||
next process if (! ($cand =~ $pattern) || $pid_user ne $user);
|
||||
print LOG "Killing $_\n";
|
||||
&killpid($pid);
|
||||
@ -730,3 +757,14 @@ sub killpid
|
||||
}
|
||||
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
861
Docs/gis.txt
Normal 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.
|
@ -96,13 +96,84 @@ cached for each user/database combination.
|
||||
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.)
|
||||
|
||||
@item Join Row Cache
|
||||
@item Join buffer Cache
|
||||
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),
|
||||
the found rows are cached in a join cache. One @code{SELECT} query can
|
||||
use many join caches in the worst case.
|
||||
@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
|
||||
@chapter How MySQL Handles @code{FLUSH TABLES}
|
||||
@ -1585,7 +1656,7 @@ fe 00 . .
|
||||
@node 4.1 protocol changes,,,
|
||||
@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.
|
||||
|
||||
The new things that we support with 4.1 are:
|
||||
@ -1596,7 +1667,7 @@ Warnings
|
||||
@item
|
||||
Prepared statements
|
||||
@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)
|
||||
@end itemize
|
||||
|
||||
@ -1617,15 +1688,15 @@ results will sent as binary (low-byte-first).
|
||||
@end itemize
|
||||
|
||||
|
||||
@node 4.1 field package,,,
|
||||
@section 4.1 field description package
|
||||
@node 4.1 field packet,,,
|
||||
@section 4.1 field description packet
|
||||
|
||||
The field description package is sent as a response to a query that
|
||||
contains a result set. It can be distinguished from a ok package by
|
||||
the fact that the first byte can't be 0 for a field package.
|
||||
@xref {4.1 ok package}.
|
||||
The field description packet is sent as a response to a query that
|
||||
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 packet.
|
||||
@xref {4.1 ok packet}.
|
||||
|
||||
The header package has the following structure:
|
||||
The header packet has the following structure:
|
||||
|
||||
@multitable @columnfractions .10 .90
|
||||
@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)
|
||||
@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}.
|
||||
|
||||
@node 4.1 field desc,,,
|
||||
@ -1655,17 +1726,17 @@ The field description result set contains the meta info for a result set.
|
||||
@end multitable
|
||||
|
||||
|
||||
@node 4.1 ok package,,,
|
||||
@section 4.1 ok package
|
||||
@node 4.1 ok packet,,,
|
||||
@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.
|
||||
|
||||
The ok package has the following structure:
|
||||
The ok packet has the following structure:
|
||||
|
||||
@multitable @columnfractions .10 .90
|
||||
@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 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
|
||||
@ -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.
|
||||
|
||||
|
||||
@node 4.1 end package,,,
|
||||
@section 4.1 end package
|
||||
@node 4.1 end packet,,,
|
||||
@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
|
||||
@item
|
||||
@ -1695,41 +1766,42 @@ End of parameter type information
|
||||
End of result set
|
||||
@end itemize
|
||||
|
||||
The end package has the following structure:
|
||||
The end packet has the following structure:
|
||||
|
||||
@multitable @columnfractions .10 .90
|
||||
@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 Status flags (For flags like SERVER_STATUS_MORE_RESULTS)
|
||||
@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
|
||||
by checking the packet length < 9 bytes (in which case it's and end
|
||||
packet).
|
||||
|
||||
|
||||
@node 4.1 error package
|
||||
@section 4.1 error package.
|
||||
@node 4.1 error packet
|
||||
@section 4.1 error packet.
|
||||
|
||||
The error package is sent when something goes wrong.
|
||||
The error package has the following structure:
|
||||
The error packet is sent when something goes wrong.
|
||||
The error packet has the following structure:
|
||||
|
||||
@multitable @columnfractions .10 .90
|
||||
@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
|
||||
@end multitable
|
||||
|
||||
The client/server protocol is designed in such a way that a package
|
||||
can only start with 255 if it's an error package.
|
||||
The client/server protocol is designed in such a way that a packet
|
||||
can only start with 255 if it's an error packet.
|
||||
|
||||
|
||||
@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.
|
||||
|
||||
@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
|
||||
able to provide the optimal information for all parameters.
|
||||
|
||||
If number of columns, in the header package, is not 0 then the
|
||||
prepared statement will contain a result set. In this case the package
|
||||
If number of columns, in the header packet, is not 0 then the
|
||||
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}.
|
||||
|
||||
|
||||
@ -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
|
||||
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
|
||||
has been sent. (Ie; That the last call to mysql_send_long_data() has
|
||||
the 'last_data' flag set).
|
||||
|
||||
This package is sent from client -> server:
|
||||
This packet is sent from client -> server:
|
||||
|
||||
@multitable @columnfractions .10 .90
|
||||
@item Size @tab Comment
|
||||
@item 4 @tab Statement handler
|
||||
@item 2 @tab Parameter number
|
||||
@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
|
||||
|
||||
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
|
||||
will get the error when calling execute.
|
||||
|
||||
@ -1791,13 +1863,13 @@ will get the error when calling execute.
|
||||
@section 4.1 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
|
||||
@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
|
||||
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)
|
||||
@ -1813,7 +1885,7 @@ The parameters are stored the following ways:
|
||||
|
||||
@multitable @columnfractions .20 .10 .70
|
||||
@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 int @tab 4 @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
|
||||
@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.
|
||||
|
||||
@node 4.1 binary result,,,
|
||||
@ -1836,11 +1908,11 @@ For each result row:
|
||||
@item
|
||||
null bit map with first two bits set to 01 (bit 0,1 value 1)
|
||||
@item
|
||||
parameter data, repeated for each not null parameter.
|
||||
parameter data, repeated for each not null result column.
|
||||
@end itemize
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
@chapter Fulltext Search in MySQL
|
||||
|
||||
|
@ -300,7 +300,7 @@
|
||||
#define ER_NOT_ALLOWED_COMMAND 1148
|
||||
"The used command is not allowed with this MySQL version",
|
||||
#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
|
||||
"Delayed insert thread couldn't get requested lock for table %-.64s",
|
||||
#define ER_TOO_MANY_DELAYED_THREADS 1151
|
||||
@ -358,7 +358,7 @@
|
||||
#define ER_CHECK_NO_SUCH_TABLE 1177
|
||||
"Can't open table",
|
||||
#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
|
||||
"You are not allowed to execute this command in a transaction",
|
||||
#define ER_ERROR_DURING_COMMIT 1180
|
||||
@ -454,4 +454,24 @@
|
||||
#define ER_DUP_ARGUMENT 1225
|
||||
"Option '%s' used twice in statement",
|
||||
#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
1422
Docs/prepare.texi
Executable file
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,8 @@ RSC=rc.exe
|
||||
# PROP Intermediate_Dir "debug"
|
||||
# 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 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 RSC /l 0x416 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -66,7 +67,8 @@ LIB32=link.exe -lib
|
||||
# PROP Intermediate_Dir "release"
|
||||
# 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 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 RSC /l 0x416 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -89,7 +91,8 @@ LIB32=link.exe -lib
|
||||
# PROP Intermediate_Dir "innobase___Win32_nt"
|
||||
# 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 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 RSC /l 0x416 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -112,7 +115,8 @@ LIB32=link.exe -lib
|
||||
# PROP Intermediate_Dir "innobase___Win32_Max_nt"
|
||||
# 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 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 RSC /l 0x416 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
@ -122,6 +122,10 @@ SOURCE=.\myrg_queue.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\myrg_range.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\myrg_rfirst.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -42,7 +42,7 @@ RSC=rc.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# 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 RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -67,7 +67,7 @@ LINK32=link.exe
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# 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 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 RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -88,7 +88,7 @@ LINK32=link.exe
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mysqlbinlog.cpp
|
||||
SOURCE=..\client\mysqlbinlog.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
@ -41,7 +41,8 @@ RSC=rc.exe
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# 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 RSC /l 0x416 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -64,7 +65,8 @@ LIB32=link.exe -lib
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# 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 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 RSC /l 0x416 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# 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 RSC /l 0x416 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -64,7 +64,7 @@ LIB32=link.exe -lib
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# 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 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 RSC /l 0x416 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
@ -80,13 +80,5 @@ LIB32=link.exe -lib
|
||||
|
||||
# Name "mysqlserver - Win32 Release"
|
||||
# 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 Project
|
||||
|
@ -218,7 +218,7 @@ SOURCE=.\derror.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\client\errmsg.c
|
||||
SOURCE=..\libmysql\errmsg.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
11
acinclude.m4
11
acinclude.m4
@ -623,7 +623,7 @@ main()
|
||||
FILE *file=fopen("conftestval", "w");
|
||||
f = (float) ll;
|
||||
fprintf(file,"%g\n",f);
|
||||
close(file);
|
||||
fclose(file);
|
||||
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
|
||||
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]*)
|
||||
changequote([, ])dnl
|
||||
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
|
||||
;;
|
||||
# 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
|
||||
# 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)
|
||||
|
||||
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 exit (int) throw ();' \
|
||||
'extern "C" void exit (int);' \
|
||||
'void exit (int);'
|
||||
'void exit (int);' \
|
||||
'#include <stdlib.h>'
|
||||
do
|
||||
_AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include <stdlib.h>
|
||||
$ac_declaration],
|
||||
|
@ -536,11 +536,9 @@ swap_retry:
|
||||
* 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 == -1) {
|
||||
if (ret == -1)
|
||||
__db_err(dbenv,
|
||||
"%s: metadata page checksum error", name);
|
||||
ret = EINVAL;
|
||||
}
|
||||
goto bad_format;
|
||||
}
|
||||
|
||||
@ -577,7 +575,7 @@ swap_retry:
|
||||
|
||||
bad_format:
|
||||
__db_err(dbenv, "%s: unexpected file type or format", name);
|
||||
return (ret);
|
||||
return (ret == 0 ? EINVAL : ret);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -268,6 +268,8 @@ __log_txn_lsn(dbenv, lsnp, mbytesp, bytesp)
|
||||
if (mbytesp != NULL) {
|
||||
*mbytesp = lp->stat.st_wc_mbytes;
|
||||
*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);
|
||||
|
@ -344,6 +344,23 @@ __memp_fopen_int(dbmfp, mfp, path, flags, mode, pagesize)
|
||||
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
|
||||
* 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);
|
||||
if (LF_ISSET(DB_EXTENT))
|
||||
F_SET(mfp, MP_EXTENT);
|
||||
F_SET(mfp, MP_CAN_MMAP);
|
||||
|
||||
if (path == NULL)
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
@ -582,7 +585,7 @@ check_map:
|
||||
* compiler will perpetrate, doing the comparison in a portable way is
|
||||
* 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 (path == NULL)
|
||||
F_CLR(mfp, MP_CAN_MMAP);
|
||||
|
@ -1198,6 +1198,9 @@ gap_check: lp->wait_recs = 0;
|
||||
* replica get flushed now and again.
|
||||
*/
|
||||
ret = dbenv->log_flush(dbenv, &ckp_lsn);
|
||||
/* Update the last_ckp in the txn region. */
|
||||
if (ret == 0)
|
||||
__txn_updateckp(dbenv, &rp->lsn);
|
||||
break;
|
||||
case DB___txn_regop:
|
||||
if (!F_ISSET(dbenv, DB_ENV_REP_LOGSONLY))
|
||||
|
@ -1209,18 +1209,7 @@ do_ckp: /* Look through the active transactions for the lowest begin LSN. */
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(®ion->last_ckp, &ckp_lsn) < 0) {
|
||||
region->last_ckp = ckp_lsn;
|
||||
(void)time(®ion->time_ckp);
|
||||
}
|
||||
R_UNLOCK(dbenv, &mgr->reginfo);
|
||||
__txn_updateckp(dbenv, &ckp_lsn);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -1404,3 +1393,36 @@ __txn_reset(dbenv)
|
||||
return (__txn_recycle_log(dbenv,
|
||||
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(®ion->last_ckp, lsnp) < 0) {
|
||||
region->last_ckp = *lsnp;
|
||||
(void)time(®ion->time_ckp);
|
||||
}
|
||||
R_UNLOCK(dbenv, &mgr->reginfo);
|
||||
}
|
||||
|
142
client/mysql.cc
142
client/mysql.cc
@ -40,7 +40,7 @@
|
||||
#include <signal.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 */
|
||||
#define MAX_COLUMN_LENGTH 1024
|
||||
@ -195,7 +195,7 @@ static void end_pager();
|
||||
static int init_tee(char *);
|
||||
static void end_tee();
|
||||
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 add_int_to_prompt(int toadd);
|
||||
|
||||
@ -280,7 +280,8 @@ static void initialize_readline (char *name);
|
||||
#endif
|
||||
|
||||
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 print_table_data(MYSQL_RES *result);
|
||||
static void print_table_data_html(MYSQL_RES *result);
|
||||
@ -388,9 +389,11 @@ int main(int argc,char *argv[])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sprintf(buff, "%s%s",
|
||||
"Type 'help;' or '\\h' for help. Type '\\c' to clear the buffer.\n",
|
||||
sprintf(buff, "%s",
|
||||
"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");
|
||||
#endif
|
||||
put_info(buff,INFO_INFO);
|
||||
status.exit_status=read_lines(1); // read lines and execute them
|
||||
if (opt_outfile)
|
||||
@ -662,7 +665,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
opt_nopager= 1;
|
||||
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);
|
||||
exit(1);
|
||||
@ -805,6 +809,7 @@ static int read_lines(bool execute_commands)
|
||||
char *line;
|
||||
char in_string=0;
|
||||
ulong line_number=0;
|
||||
bool ml_comment= 0;
|
||||
COMMANDS *com;
|
||||
status.exit_status=1;
|
||||
|
||||
@ -873,7 +878,7 @@ static int read_lines(bool execute_commands)
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (add_line(glob_buffer,line,&in_string))
|
||||
if (add_line(glob_buffer,line,&in_string,&ml_comment))
|
||||
break;
|
||||
}
|
||||
/* 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;
|
||||
char buff[80],*pos,*out;
|
||||
@ -965,7 +971,7 @@ static bool add_line(String &buffer,char *line,char *in_string)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (inchar == '\\')
|
||||
if (!*ml_comment && inchar == '\\')
|
||||
{ // mSQL or postgreSQL style command ?
|
||||
if (!(inchar = (uchar) *++pos))
|
||||
break; // readline adds one '\'
|
||||
@ -999,7 +1005,7 @@ static bool add_line(String &buffer,char *line,char *in_string)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (inchar == ';' && !*in_string)
|
||||
else if (!*ml_comment && inchar == ';' && !*in_string)
|
||||
{ // ';' is end of command
|
||||
if (out != 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);
|
||||
out=line;
|
||||
}
|
||||
else if (!*in_string && (inchar == '#' ||
|
||||
else if (!*ml_comment && (!*in_string && (inchar == '#' ||
|
||||
inchar == '-' && pos[1] == '-' &&
|
||||
my_isspace(system_charset_info,pos[2])))
|
||||
my_isspace(system_charset_info,pos[2]))))
|
||||
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
|
||||
{ // Add found char to buffer
|
||||
if (inchar == *in_string)
|
||||
*in_string=0;
|
||||
else if (!*in_string && (inchar == '\'' || inchar == '"'))
|
||||
*in_string=(char) inchar;
|
||||
if (!(*ml_comment))
|
||||
*out++ = (char) inchar;
|
||||
}
|
||||
}
|
||||
@ -1038,7 +1060,7 @@ static bool add_line(String &buffer,char *line,char *in_string)
|
||||
uint length=(uint) (out-line);
|
||||
if (buffer.length() + length >= buffer.alloced_length())
|
||||
buffer.realloc(buffer.length()+length+IO_SIZE);
|
||||
if (buffer.append(line,length))
|
||||
if (!(*ml_comment) && buffer.append(line,length))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -1280,7 +1302,7 @@ You can turn off this feature to get a quicker startup with -A\n\n");
|
||||
sizeof(char *) *
|
||||
(num_fields*2+1))))
|
||||
break;
|
||||
field_names[i][num_fields*2]='\0';
|
||||
field_names[i][num_fields*2]= '\0';
|
||||
j=0;
|
||||
while ((sql_field=mysql_fetch_field(fields)))
|
||||
{
|
||||
@ -1300,7 +1322,7 @@ You can turn off this feature to get a quicker startup with -A\n\n");
|
||||
{
|
||||
tee_fprintf(stdout,
|
||||
"Didn't find any fields in table '%s'\n",table_row[0]);
|
||||
field_names[i]=0;
|
||||
field_names[i]= 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -1388,18 +1410,15 @@ static int com_server_help(String *buffer __attribute__((unused)),
|
||||
MYSQL_ROW cur;
|
||||
const char *server_cmd= buffer->ptr();
|
||||
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;
|
||||
}
|
||||
|
||||
char buff[16], time_buf[32];
|
||||
MYSQL_RES *result;
|
||||
ulong timer;
|
||||
uint error= 0;
|
||||
|
||||
if (!status.batch)
|
||||
{
|
||||
old_buffer= *buffer;
|
||||
@ -1409,26 +1428,24 @@ static int com_server_help(String *buffer __attribute__((unused)),
|
||||
if (!connected && reconnect())
|
||||
return 1;
|
||||
|
||||
timer= start_timer();
|
||||
|
||||
error= mysql_real_query_for_lazy(server_cmd,strlen(server_cmd));
|
||||
if (error)
|
||||
if ((error= mysql_real_query_for_lazy(server_cmd,strlen(server_cmd))))
|
||||
return error;
|
||||
|
||||
error= mysql_store_result_for_lazy(&result);
|
||||
if (error)
|
||||
if ((error= mysql_store_result_for_lazy(&result)))
|
||||
return error;
|
||||
|
||||
if (result)
|
||||
{
|
||||
int num_rows= mysql_num_rows(result);
|
||||
if (num_rows==1)
|
||||
if (num_rows == 1)
|
||||
{
|
||||
if (!(cur= mysql_fetch_row(result)))
|
||||
return -1;
|
||||
{
|
||||
error= -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
init_pager();
|
||||
if (cur[1][0]=='Y')
|
||||
if (cur[1][0] == 'Y')
|
||||
{
|
||||
tee_fprintf(PAGER, "\nHelp topic \'%s\'\n", cur[0]);
|
||||
tee_fprintf(PAGER, "%s\n", cur[2]);
|
||||
@ -1442,17 +1459,19 @@ static int com_server_help(String *buffer __attribute__((unused)),
|
||||
}
|
||||
end_pager();
|
||||
}
|
||||
else if (num_rows>1)
|
||||
else if (num_rows > 1)
|
||||
{
|
||||
put_info("\nMany help items for your request exist", INFO_INFO);
|
||||
put_info("For more specific request please type 'help <item>' where item is one of next :", INFO_INFO);
|
||||
|
||||
init_pager();
|
||||
char last_char= '_';
|
||||
while ((cur= mysql_fetch_row(result))){
|
||||
if (cur[1][0]!=last_char){
|
||||
while ((cur= mysql_fetch_row(result)))
|
||||
{
|
||||
if (cur[1][0]!=last_char)
|
||||
{
|
||||
put_info("-------------------------------------------", INFO_INFO);
|
||||
put_info(cur[1][0]=='Y' ?
|
||||
put_info(cur[1][0] == 'Y' ?
|
||||
"categories:" : "functions:", INFO_INFO);
|
||||
put_info("-------------------------------------------", INFO_INFO);
|
||||
}
|
||||
@ -1468,6 +1487,7 @@ static int com_server_help(String *buffer __attribute__((unused)),
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
mysql_free_result(result);
|
||||
return error;
|
||||
}
|
||||
@ -2212,23 +2232,21 @@ com_print(String *buffer,char *line __attribute__((unused)))
|
||||
static int
|
||||
com_connect(String *buffer, char *line)
|
||||
{
|
||||
char *tmp,buff[256];
|
||||
char *tmp, buff[256];
|
||||
bool save_rehash= rehash;
|
||||
int error;
|
||||
|
||||
bzero(buff, sizeof(buff));
|
||||
if (buffer)
|
||||
{
|
||||
while (my_isspace(system_charset_info,*line))
|
||||
line++;
|
||||
strnmov(buff,line,sizeof(buff)-1); // Don't destroy history
|
||||
if (buff[0] == '\\') // Short command
|
||||
buff[1]=' ';
|
||||
tmp=(char *) strtok(buff," \t"); // Skip connect command
|
||||
if (tmp && (tmp=(char *) strtok(NullS," \t;")))
|
||||
strmov(buff, line);
|
||||
tmp= get_arg(buff, 0);
|
||||
if (tmp && *tmp)
|
||||
{
|
||||
my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
|
||||
current_db=my_strdup(tmp,MYF(MY_WME));
|
||||
if ((tmp=(char *) strtok(NullS," \t;")))
|
||||
my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
|
||||
current_db= my_strdup(tmp, MYF(MY_WME));
|
||||
tmp= get_arg(buff, 1);
|
||||
if (tmp)
|
||||
{
|
||||
my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
|
||||
current_host=my_strdup(tmp,MYF(MY_WME));
|
||||
@ -2314,8 +2332,9 @@ com_use(String *buffer __attribute__((unused)), char *line)
|
||||
char *tmp;
|
||||
char buff[256];
|
||||
|
||||
bzero(buff, sizeof(buff));
|
||||
strmov(buff, line);
|
||||
tmp= get_arg(buff);
|
||||
tmp= get_arg(buff, 0);
|
||||
if (!tmp || !*tmp)
|
||||
{
|
||||
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 };
|
||||
|
||||
char *get_arg(char *line)
|
||||
char *get_arg(char *line, my_bool get_next_arg)
|
||||
{
|
||||
char *ptr;
|
||||
my_bool quoted= 0, valid_arg= 0;
|
||||
@ -2367,6 +2397,14 @@ char *get_arg(char *line)
|
||||
enum quote_type qtype= NO_QUOTE;
|
||||
|
||||
ptr= line;
|
||||
if (get_next_arg)
|
||||
{
|
||||
for (; ptr && *ptr; ptr++);
|
||||
if ((ptr + 1) && *(ptr + 1))
|
||||
ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skip leading white spaces */
|
||||
while (my_isspace(system_charset_info, *ptr))
|
||||
ptr++;
|
||||
@ -2374,6 +2412,7 @@ char *get_arg(char *line)
|
||||
ptr+= 2;
|
||||
while (!my_isspace(system_charset_info, *ptr)) // skip command
|
||||
ptr++;
|
||||
}
|
||||
while (my_isspace(system_charset_info, *ptr))
|
||||
ptr++;
|
||||
if ((*ptr == '\'' && (qtype= SQUOTE)) ||
|
||||
@ -2396,9 +2435,8 @@ char *get_arg(char *line)
|
||||
ptr= line;
|
||||
ptr+= count;
|
||||
}
|
||||
else if (!quoted && *ptr == ' ')
|
||||
*(ptr + 1) = 0;
|
||||
else if ((*ptr == '\'' && qtype == SQUOTE) ||
|
||||
else if ((!quoted && *ptr == ' ') ||
|
||||
(*ptr == '\'' && qtype == SQUOTE) ||
|
||||
(*ptr == '\"' && qtype == DQUOTE) ||
|
||||
(*ptr == '`' && qtype == BTICK))
|
||||
{
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#define ADMIN_VERSION "8.38"
|
||||
#define ADMIN_VERSION "8.39"
|
||||
#define MAX_MYSQL_VAR 128
|
||||
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
|
||||
#define MAX_TRUNC_LENGTH 3
|
||||
@ -76,7 +76,7 @@ static void print_relative_header();
|
||||
static void print_relative_line();
|
||||
static void truncate_names();
|
||||
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);
|
||||
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");
|
||||
|
||||
/* Wait until pid file is gone */
|
||||
wait_pidfile(pidfile, last_modified, &pidfile_status);
|
||||
if (wait_pidfile(pidfile, last_modified, &pidfile_status))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1150,34 +1151,51 @@ static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
|
||||
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)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
int fd = -1;
|
||||
uint count=0;
|
||||
int error= 1;
|
||||
uint count= 0;
|
||||
DBUG_ENTER("wait_pidfile");
|
||||
|
||||
system_filename(buff, pidfile);
|
||||
while (count++ <= opt_shutdown_timeout && !interrupted &&
|
||||
(!last_modified || (last_modified == pidfile_status->st_mtime)) &&
|
||||
(fd= my_open(buff, O_RDONLY, MYF(0))) >= 0)
|
||||
do
|
||||
{
|
||||
if (!my_close(fd,MYF(0)))
|
||||
fd= -1;
|
||||
sleep(1);
|
||||
if (last_modified && stat(pidfile, pidfile_status))
|
||||
last_modified= 0;
|
||||
int fd;
|
||||
if ((fd= my_open(buff, O_RDONLY, MYF(0))) < 0)
|
||||
{
|
||||
error= 0;
|
||||
break;
|
||||
}
|
||||
if (opt_verbose && last_modified &&
|
||||
last_modified != pidfile_status->st_mtime)
|
||||
printf("Warning; pid file '%s' changed while waiting for it to disappear!\n",
|
||||
buff);
|
||||
if (fd >= 0)
|
||||
(void) my_close(fd,MYF(0));
|
||||
if (last_modified && !stat(pidfile, pidfile_status))
|
||||
{
|
||||
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,
|
||||
"Warning; Aborted waiting on pid file: '%s' after %d seconds\n",
|
||||
buff, count-1);
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#define MTEST_VERSION "1.25"
|
||||
#define MTEST_VERSION "1.26"
|
||||
|
||||
#include <my_global.h>
|
||||
#include <mysql_embed.h>
|
||||
@ -166,7 +166,8 @@ typedef struct
|
||||
VAR var_reg[10];
|
||||
/*Perl/shell-like variable registers */
|
||||
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* 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_WAIT_FOR_SLAVE_TO_STOP,
|
||||
Q_REQUIRE_VERSION,
|
||||
Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
|
||||
Q_ENABLE_INFO, Q_DISABLE_INFO,
|
||||
Q_UNKNOWN, /* Unknown command. */
|
||||
Q_COMMENT, /* Comments, ignored. */
|
||||
Q_COMMENT_WITH_COMMAND
|
||||
@ -253,6 +256,10 @@ const char *command_names[]=
|
||||
"require_manager",
|
||||
"wait_for_slave_to_stop",
|
||||
"require_version",
|
||||
"enable_warnings",
|
||||
"disable_warnings",
|
||||
"enable_info",
|
||||
"diable_info",
|
||||
0
|
||||
};
|
||||
|
||||
@ -1803,10 +1810,8 @@ int read_query(struct st_query** q_ptr)
|
||||
|
||||
static struct my_option my_long_options[] =
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'",
|
||||
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
|
||||
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"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) {
|
||||
case '#':
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace");
|
||||
#endif
|
||||
break;
|
||||
case 'r':
|
||||
record = 1;
|
||||
@ -1977,7 +1984,7 @@ int parse_args(int argc, char **argv)
|
||||
default_argv= argv;
|
||||
|
||||
if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
|
||||
exit(ho_error);
|
||||
exit(1);
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
@ -2191,7 +2198,9 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!disable_result_log && res)
|
||||
if (!disable_result_log)
|
||||
{
|
||||
if (res)
|
||||
{
|
||||
int num_fields= mysql_num_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 */
|
||||
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)
|
||||
verbose_msg("Warning count is %d but didn't get any warnings\n",
|
||||
mysql_warning_count(mysql));
|
||||
verbose_msg("Warning count is %u but didn't get any warnings\n",
|
||||
count);
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
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)
|
||||
free_replace();
|
||||
|
||||
@ -2427,6 +2449,10 @@ int main(int argc, char** argv)
|
||||
case Q_DISABLE_QUERY_LOG: disable_query_log=1; break;
|
||||
case Q_ENABLE_RESULT_LOG: disable_result_log=0; 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_SLEEP: do_sleep(q, 0); break;
|
||||
case Q_REAL_SLEEP: do_sleep(q, 1); break;
|
||||
|
27
configure.in
27
configure.in
@ -10,7 +10,7 @@ AM_CONFIG_HEADER(config.h)
|
||||
PROTOCOL_VERSION=10
|
||||
DOT_FRM_VERSION=6
|
||||
# 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 ?
|
||||
# Remember that regexps needs to quote [ and ] since this is run through m4
|
||||
@ -130,18 +130,24 @@ AC_PROG_CXX
|
||||
AC_PROG_CPP
|
||||
|
||||
# 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"
|
||||
then
|
||||
AC_MSG_CHECKING("C Compiler version");
|
||||
AC_MSG_RESULT("$CC $CC_VERSION")
|
||||
else
|
||||
CC_VERSION=""
|
||||
fi
|
||||
CXX_VERSION=`$CXX --version`
|
||||
CXX_VERSION=`$CXX --version | sed 1q`
|
||||
if test $? -eq "0"
|
||||
then
|
||||
AC_MSG_CHECKING("C++ compiler version");
|
||||
AC_MSG_RESULT("$CXX $CXX_VERSION")
|
||||
else
|
||||
CXX_VERSION=""
|
||||
fi
|
||||
AC_SUBST(CXX_VERSION)
|
||||
AC_SUBST(CC_VERSION)
|
||||
|
||||
# Fix for sgi gcc / sgiCC which tries to emulate gcc
|
||||
if test "$CC" = "sgicc"
|
||||
@ -876,6 +882,7 @@ int main()
|
||||
#
|
||||
|
||||
MAX_C_OPTIMIZE="-O3"
|
||||
MAX_CXX_OPTIMIZE="-O3"
|
||||
|
||||
case $SYSTEM_TYPE in
|
||||
*solaris2.7*)
|
||||
@ -943,6 +950,8 @@ case $SYSTEM_TYPE in
|
||||
then
|
||||
CFLAGS="$CFLAGS +DD64 -DHAVE_BROKEN_INLINE"
|
||||
CXXFLAGS="$CXXFLAGS +DD64 +O2"
|
||||
MAX_C_OPTIMIZE=""
|
||||
MAX_CXX_OPTIMIZE=""
|
||||
fi
|
||||
;;
|
||||
*rhapsody*)
|
||||
@ -960,8 +969,8 @@ case $SYSTEM_TYPE in
|
||||
*darwin5*)
|
||||
if test "$ac_cv_prog_gcc" = "yes"
|
||||
then
|
||||
CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH"
|
||||
CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ"
|
||||
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 -DFN_NO_CASE_SENCE"
|
||||
MAX_C_OPTIMIZE="-O"
|
||||
with_named_curses=""
|
||||
fi
|
||||
@ -969,8 +978,8 @@ case $SYSTEM_TYPE in
|
||||
*darwin6*)
|
||||
if test "$ac_cv_prog_gcc" = "yes"
|
||||
then
|
||||
CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH"
|
||||
CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ"
|
||||
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 -DFN_NO_CASE_SENCE"
|
||||
MAX_C_OPTIMIZE="-O"
|
||||
fi
|
||||
;;
|
||||
@ -1231,7 +1240,7 @@ then
|
||||
# CC="$CC -Kthread -DOpenUNIX8";
|
||||
# CXX="$CXX -Kthread -DOpenUNIX8";
|
||||
CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK";
|
||||
CXX="$CXX -Kthread -DUNIXWARE_7";
|
||||
CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"
|
||||
fi
|
||||
AC_MSG_RESULT("yes")
|
||||
else
|
||||
@ -1401,7 +1410,7 @@ if test "$ac_cv_prog_cxx_g" = "yes"
|
||||
then
|
||||
DEBUG_CXXFLAGS="-g"
|
||||
DEBUG_OPTIMIZE_CXX="-O"
|
||||
OPTIMIZE_CXXFLAGS="-O3"
|
||||
OPTIMIZE_CXXFLAGS="$MAX_CXX_OPTIMIZE"
|
||||
else
|
||||
DEBUG_CXXFLAGS="-g"
|
||||
DEBUG_OPTIMIZE_CXX=""
|
||||
|
@ -18,7 +18,7 @@ INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
|
||||
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \
|
||||
../dbug/libdbug.a ../strings/libmystrings.a
|
||||
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
|
||||
%::SCCS/s.%
|
||||
|
86
extra/mysql_waitpid.c
Normal file
86
extra/mysql_waitpid.c
Normal 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);
|
||||
}
|
@ -80,6 +80,7 @@ static HA_ERRORS ha_errlist[]=
|
||||
{ 147,"Lock table is full; Restart program with a larger locktable"},
|
||||
{ 148,"Updates are not allowed under a read only transactions"},
|
||||
{ 149,"Lock deadlock; Retry transaction"},
|
||||
{ 150,"Foreign key constraint is incorrectly formed"},
|
||||
{ -30999, "DB_INCOMPLETE: Sync didn't finish"},
|
||||
{ -30998, "DB_KEYEMPTY: Key/data deleted or never created"},
|
||||
{ -30997, "DB_KEYEXIST: The key/data pair already exists"},
|
||||
|
@ -16,7 +16,7 @@
|
||||
# MA 02111-1307, USA
|
||||
|
||||
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 \
|
||||
my_semaphore.h my_pthread.h my_no_pthread.h raid.h \
|
||||
errmsg.h my_global.h my_net.h my_alloc.h \
|
||||
|
@ -27,6 +27,13 @@ extern "C" {
|
||||
#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 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_LOADED 8 /* sets that are currently loaded */
|
||||
#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_CURRENT (default_charset_info->number)
|
||||
@ -65,6 +73,7 @@ typedef struct charset_info_st
|
||||
{
|
||||
uint number;
|
||||
uint state;
|
||||
const char *csname;
|
||||
const char *name;
|
||||
const char *comment;
|
||||
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 (*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);
|
||||
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);
|
||||
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;
|
||||
|
||||
@ -142,7 +152,8 @@ extern CHARSET_INFO *default_charset_info;
|
||||
extern CHARSET_INFO *system_charset_info;
|
||||
extern CHARSET_INFO *all_charsets[256];
|
||||
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 */
|
||||
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);
|
||||
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);
|
||||
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_ll10tostr_8bit(CHARSET_INFO *, char *to, uint l, int radix, longlong val);
|
||||
|
@ -31,6 +31,9 @@
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/* need by my_vsnprintf */
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Correct some things for UNIXWARE7 */
|
||||
#ifdef HAVE_UNIXWARE7_THREADS
|
||||
#undef HAVE_STRINGS_H
|
||||
@ -238,6 +241,12 @@ extern ulonglong strtoull(const char *str, char **ptr, int base);
|
||||
#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)
|
||||
}
|
||||
#endif
|
||||
|
@ -107,9 +107,6 @@ enum ha_extra_function {
|
||||
HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/
|
||||
HA_EXTRA_NO_IGNORE_DUP_KEY,
|
||||
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_UPDATE /* Remove read cache if problems */
|
||||
};
|
||||
@ -267,6 +264,7 @@ enum ha_base_keytype {
|
||||
#define MBR_EQUAL 8192
|
||||
#define MBR_DATA 16384
|
||||
#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 */
|
||||
#define QUICK_USED 1
|
||||
|
@ -206,6 +206,7 @@ extern const char *get_charset_name(uint cs_number);
|
||||
extern CHARSET_INFO *get_charset(uint cs_number, 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_csname(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 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 gptr my_once_alloc(uint Size,myf MyFlags);
|
||||
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 File my_open(const char *FileName,int Flags,myf MyFlags);
|
||||
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,
|
||||
myf MyFlags, ...)
|
||||
__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_no_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
61
include/my_xml.h
Normal 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 */
|
@ -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 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
|
||||
}
|
||||
#endif
|
||||
|
@ -51,6 +51,7 @@ typedef struct st_mymerge_info /* Struct from h_info */
|
||||
uint reclength; /* Recordlength */
|
||||
int errkey; /* With key was dupplicated on err */
|
||||
uint options; /* HA_OPTION_... used */
|
||||
ulong *rec_per_key; /* for sql optimizing */
|
||||
} MYMERGE_INFO;
|
||||
|
||||
typedef struct st_myrg_table_info
|
||||
@ -71,6 +72,7 @@ typedef struct st_myrg_info
|
||||
my_bool cache_in_use;
|
||||
LIST open_list;
|
||||
QUEUE by_key;
|
||||
ulong *rec_per_key_part; /* for sql optimizing */
|
||||
} MYRG_INFO;
|
||||
|
||||
|
||||
|
@ -130,6 +130,7 @@ struct st_mysql_options {
|
||||
char *ssl_ca; /* PEM CA file */
|
||||
char *ssl_capath; /* PEM directory of CA-s? */
|
||||
char *ssl_cipher; /* cipher to use */
|
||||
unsigned long max_allowed_packet;
|
||||
my_bool use_ssl; /* if to use SSL or not */
|
||||
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_store_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,
|
||||
const char *arg);
|
||||
void STDCALL mysql_free_result(MYSQL_RES *result);
|
||||
@ -473,13 +473,12 @@ typedef struct st_mysql_bind
|
||||
{
|
||||
long *length; /* output length pointer */
|
||||
gptr buffer; /* buffer */
|
||||
unsigned long buffer_length; /* buffer length */
|
||||
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_long_data; /* long data indicator */
|
||||
|
||||
/* The following are for internal use. Set by mysql_bind_param */
|
||||
unsigned long buffer_length; /* buffer length */
|
||||
long bind_length; /* Default length of data */
|
||||
my_bool long_ended; /* All data supplied for long */
|
||||
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);
|
||||
MYSQL_RES *STDCALL mysql_next_result(MYSQL *mysql);
|
||||
MYSQL_RES *STDCALL mysql_prepare_result(MYSQL_STMT *stmt);
|
||||
my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt);
|
||||
|
||||
|
||||
/* new status messages */
|
||||
#define MYSQL_SUCCESS 0
|
||||
#define MYSQL_WARNING 1
|
||||
#define MYSQL_STATUS_ERROR 2
|
||||
#define MYSQL_STATUS_ERROR 1
|
||||
#define MYSQL_NO_DATA 100
|
||||
#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)
|
||||
|
||||
|
@ -42,7 +42,8 @@ enum enum_server_command
|
||||
COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING,
|
||||
COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP,
|
||||
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);
|
||||
void create_random_string(int length,struct rand_struct *rand_st,char* target);
|
||||
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_stage2(char *to,const char *salt);
|
||||
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);
|
||||
void get_salt_from_password(unsigned long *res,const char *password);
|
||||
void create_key_from_old_password(const char* password,char* key);
|
||||
|
@ -265,4 +265,5 @@
|
||||
#define ER_DERIVED_MUST_HAVE_ALIAS 1246
|
||||
#define ER_SELECT_REDUCED 1247
|
||||
#define ER_TABLENAME_NOT_ALLOWED_HERE 1248
|
||||
#define ER_ERROR_MESSAGES 249
|
||||
#define ER_NOT_SUPPORTED_AUTH_MODE 1249
|
||||
#define ER_ERROR_MESSAGES 250
|
||||
|
@ -291,6 +291,7 @@ btr_cur_search_to_nth_level(
|
||||
&& latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
|
||||
&& !estimate
|
||||
&& mode != PAGE_CUR_LE_OR_EXTENDS
|
||||
&& srv_use_adaptive_hash_indexes
|
||||
&& btr_search_guess_on_hash(index, info, tuple, mode,
|
||||
latch_mode, cursor,
|
||||
has_search_latch, mtr)) {
|
||||
@ -495,9 +496,11 @@ retry_page_get:
|
||||
cursor->up_bytes = up_bytes;
|
||||
|
||||
#ifdef BTR_CUR_ADAPT
|
||||
btr_search_info_update(index, cursor);
|
||||
#endif
|
||||
if (srv_use_adaptive_hash_indexes) {
|
||||
|
||||
btr_search_info_update(index, cursor);
|
||||
}
|
||||
#endif
|
||||
ut_ad(cursor->up_match != ULINT_UNDEFINED
|
||||
|| mode != PAGE_CUR_GE);
|
||||
ut_ad(cursor->up_match != ULINT_UNDEFINED
|
||||
|
@ -95,7 +95,9 @@ btr_pcur_store_position(
|
||||
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
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
|
||||
&& btr_page_get_prev(page, mtr) == FIL_NULL);
|
||||
@ -134,6 +136,7 @@ btr_pcur_store_position(
|
||||
&(cursor->old_rec_buf),
|
||||
&(cursor->buf_size));
|
||||
|
||||
cursor->block_when_stored = buf_block_align(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
|
||||
|| 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) {
|
||||
from_left = TRUE;
|
||||
} else {
|
||||
@ -214,6 +220,10 @@ btr_pcur_restore_position(
|
||||
btr_cur_open_at_index_side(from_left,
|
||||
btr_pcur_get_btr_cur(cursor)->index, latch_mode,
|
||||
btr_pcur_get_btr_cur(cursor), mtr);
|
||||
|
||||
cursor->block_when_stored =
|
||||
buf_block_align(btr_pcur_get_page(cursor));
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
@ -224,7 +234,8 @@ btr_pcur_restore_position(
|
||||
if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) {
|
||||
/* 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->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,
|
||||
mode, latch_mode, cursor, 0, mtr);
|
||||
|
||||
cursor->old_stored = BTR_PCUR_OLD_STORED;
|
||||
|
||||
/* Restore the old search mode */
|
||||
cursor->search_mode = old_mode;
|
||||
|
||||
@ -281,10 +290,17 @@ btr_pcur_restore_position(
|
||||
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor))) {
|
||||
|
||||
/* 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);
|
||||
|
||||
return(TRUE);
|
||||
@ -292,6 +308,12 @@ btr_pcur_restore_position(
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,9 @@ Created 2/17/1996 Heikki Tuuri
|
||||
#include "btr0btr.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_hash_fail = 0;
|
||||
|
||||
@ -56,14 +59,18 @@ before hash index building is started */
|
||||
|
||||
/************************************************************************
|
||||
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
|
||||
void
|
||||
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 */
|
||||
ulint n_fields, /* in: hash this many full fields */
|
||||
ulint n_bytes, /* in: hash this many bytes from the next
|
||||
ulint n_fields,/* in: hash this many full fields */
|
||||
ulint n_bytes,/* in: hash this many bytes from the next
|
||||
field */
|
||||
ulint side); /* in: hash for searches from this side */
|
||||
|
||||
@ -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
|
||||
void
|
||||
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
|
||||
ibool
|
||||
btr_search_update_block_hash_info(
|
||||
@ -425,12 +436,19 @@ btr_search_info_update_slow(
|
||||
{
|
||||
buf_block_t* block;
|
||||
ibool build_index;
|
||||
ulint* params;
|
||||
ulint* params2;
|
||||
|
||||
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)
|
||||
&& !rw_lock_own(&btr_search_latch, RW_LOCK_EX));
|
||||
|
||||
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);
|
||||
|
||||
build_index = btr_search_update_block_hash_info(info, block, cursor);
|
||||
@ -453,12 +471,30 @@ btr_search_info_update_slow(
|
||||
}
|
||||
|
||||
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,
|
||||
block->n_fields,
|
||||
block->n_bytes,
|
||||
block->side);
|
||||
params = mem_alloc(3 * sizeof(ulint));
|
||||
params[0] = block->n_fields;
|
||||
params[1] = block->n_bytes;
|
||||
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,14 +1012,18 @@ btr_search_drop_page_hash_when_freed(
|
||||
|
||||
/************************************************************************
|
||||
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
|
||||
void
|
||||
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 */
|
||||
ulint n_fields, /* in: hash this many full fields */
|
||||
ulint n_bytes, /* in: hash this many bytes from the next
|
||||
ulint n_fields,/* in: hash this many full fields */
|
||||
ulint n_bytes,/* in: hash this many bytes from the next
|
||||
field */
|
||||
ulint side) /* in: hash for searches from this side */
|
||||
{
|
||||
@ -1028,7 +1068,18 @@ btr_search_build_page_hash_index(
|
||||
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
|
||||
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);
|
||||
|
||||
btr_search_build_page_hash_index(new_page, n_fields, n_bytes,
|
||||
side);
|
||||
btr_search_build_page_hash_index(NULL, new_page, n_fields,
|
||||
n_bytes, side);
|
||||
ut_a(n_fields == block->curr_n_fields);
|
||||
ut_a(n_bytes == block->curr_n_bytes);
|
||||
ut_a(side == block->curr_side);
|
||||
|
@ -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
|
||||
in a tablespace) have recently been referenced, we may predict
|
||||
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 */
|
||||
|
||||
@ -346,12 +368,15 @@ void
|
||||
buf_block_init(
|
||||
/*===========*/
|
||||
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->frame = frame;
|
||||
|
||||
block->awe_info = NULL;
|
||||
|
||||
block->modify_clock = ut_dulint_zero;
|
||||
|
||||
block->file_page_was_freed = FALSE;
|
||||
@ -361,32 +386,46 @@ buf_block_init(
|
||||
rw_lock_create(&(block->lock));
|
||||
ut_ad(rw_lock_validate(&(block->lock)));
|
||||
|
||||
rw_lock_create(&(block->read_lock));
|
||||
rw_lock_set_level(&(block->read_lock), SYNC_NO_ORDER_CHECK);
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
rw_lock_create(&(block->debug_latch));
|
||||
rw_lock_set_level(&(block->debug_latch), SYNC_NO_ORDER_CHECK);
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Creates a buffer buf_pool object. */
|
||||
static
|
||||
Creates the buffer pool. */
|
||||
|
||||
buf_pool_t*
|
||||
buf_pool_create(
|
||||
/*============*/
|
||||
buf_pool_init(
|
||||
/*==========*/
|
||||
/* 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
|
||||
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 */
|
||||
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;
|
||||
ulint i;
|
||||
buf_block_t* block;
|
||||
|
||||
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));
|
||||
|
||||
@ -397,7 +436,37 @@ buf_pool_create(
|
||||
|
||||
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) {
|
||||
|
||||
@ -414,19 +483,58 @@ buf_pool_create(
|
||||
buf_pool->max_size = max_size;
|
||||
buf_pool->curr_size = curr_size;
|
||||
|
||||
buf_pool->n_frames = n_frames;
|
||||
|
||||
/* Align pointer to the first frame */
|
||||
|
||||
frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE);
|
||||
|
||||
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++) {
|
||||
|
||||
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);
|
||||
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);
|
||||
@ -438,12 +546,14 @@ buf_pool_create(
|
||||
buf_pool->n_pages_read = 0;
|
||||
buf_pool->n_pages_written = 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_old = 0;
|
||||
buf_pool->n_pages_read_old = 0;
|
||||
buf_pool->n_pages_written_old = 0;
|
||||
buf_pool->n_pages_created_old = 0;
|
||||
buf_pool->n_pages_awe_remapped_old = 0;
|
||||
|
||||
/* 2. Initialize flushing fields
|
||||
---------------------------- */
|
||||
@ -466,40 +576,120 @@ buf_pool_create(
|
||||
|
||||
buf_pool->LRU_old = NULL;
|
||||
|
||||
UT_LIST_INIT(buf_pool->awe_LRU_free_mapped);
|
||||
|
||||
/* Add control blocks to the free list */
|
||||
UT_LIST_INIT(buf_pool->free);
|
||||
|
||||
for (i = 0; i < curr_size; 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);
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
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
|
||||
buf_pool_init(
|
||||
/*==========*/
|
||||
ulint max_size, /* in: maximum size of the buf_pool in blocks */
|
||||
ulint curr_size) /* in: current size to use, must be <=
|
||||
max_size */
|
||||
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 */
|
||||
{
|
||||
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_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;
|
||||
|
||||
@ -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
|
||||
buf_block_buf_fix_inc_debug(block, file, line);
|
||||
#else
|
||||
@ -900,8 +1105,26 @@ loop:
|
||||
} else if (rw_latch == RW_NO_LATCH) {
|
||||
|
||||
if (must_read) {
|
||||
rw_lock_x_lock(&(block->read_lock));
|
||||
rw_lock_x_unlock(&(block->read_lock));
|
||||
/* Let us wait until the read operation
|
||||
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;
|
||||
@ -940,28 +1163,27 @@ buf_page_optimistic_get_func(
|
||||
/*=========================*/
|
||||
/* out: TRUE if success */
|
||||
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
|
||||
..._GUESS_ON_CLOCK */
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line where called */
|
||||
mtr_t* mtr) /* in: mini-transaction */
|
||||
{
|
||||
buf_block_t* block;
|
||||
ibool accessed;
|
||||
ibool success;
|
||||
ulint fix_type;
|
||||
|
||||
ut_ad(mtr && guess);
|
||||
ut_ad(mtr && block);
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
@ -1054,12 +1276,15 @@ buf_page_optimistic_get_func(
|
||||
#ifdef UNIV_IBUF_DEBUG
|
||||
ut_a(ibuf_count_get(block->space, block->offset) == 0);
|
||||
#endif
|
||||
buf_pool->n_page_gets++;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
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
|
||||
buf_page_get_known_nowait(
|
||||
@ -1079,12 +1304,10 @@ buf_page_get_known_nowait(
|
||||
ut_ad(mtr);
|
||||
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);
|
||||
|
||||
mutex_enter(&(buf_pool->mutex));
|
||||
|
||||
if (block->state == BUF_BLOCK_REMOVE_HASH) {
|
||||
/* Another thread is just freeing the block from the LRU list
|
||||
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)
|
||||
|| (ibuf_count_get(block->space, block->offset) == 0));
|
||||
#endif
|
||||
buf_pool->n_page_gets++;
|
||||
|
||||
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->read_lock), BUF_IO_READ);
|
||||
|
||||
mutex_exit(&(buf_pool->mutex));
|
||||
|
||||
if (mode == BUF_READ_IBUF_PAGES_ONLY) {
|
||||
@ -1546,9 +1769,7 @@ buf_page_io_complete(
|
||||
buf_pool->n_pend_reads--;
|
||||
buf_pool->n_pages_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) {
|
||||
printf("Has read ");
|
||||
@ -1732,7 +1953,7 @@ buf_print(void)
|
||||
|
||||
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);
|
||||
counts = mem_alloc(sizeof(ulint) * size);
|
||||
@ -1847,7 +2068,7 @@ buf_print_io(
|
||||
return;
|
||||
}
|
||||
|
||||
size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE;
|
||||
size = buf_pool->curr_size;
|
||||
|
||||
mutex_enter(&(buf_pool->mutex));
|
||||
|
||||
@ -1866,6 +2087,15 @@ buf_print_io(
|
||||
buf += sprintf(buf,
|
||||
"Modified db pages %lu\n",
|
||||
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);
|
||||
|
||||
@ -1891,6 +2121,13 @@ buf_print_io(
|
||||
(buf_pool->n_pages_written - buf_pool->n_pages_written_old)
|
||||
/ 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) {
|
||||
buf += sprintf(buf, "Buffer pool hit rate %lu / 1000\n",
|
||||
1000
|
||||
@ -1906,6 +2143,7 @@ buf_print_io(
|
||||
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_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));
|
||||
}
|
||||
@ -1922,6 +2160,7 @@ buf_refresh_io_stats(void)
|
||||
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_written_old = buf_pool->n_pages_written;
|
||||
buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -24,6 +24,7 @@ Created 11/11/1995 Heikki Tuuri
|
||||
#include "log0log.h"
|
||||
#include "os0file.h"
|
||||
#include "trx0sys.h"
|
||||
#include "srv0srv.h"
|
||||
|
||||
/* When flushed, dirty blocks are searched in neigborhoods of this size, and
|
||||
flushed along with the original page. */
|
||||
@ -103,7 +104,7 @@ buf_flush_ready_for_replace(
|
||||
/*========================*/
|
||||
/* out: TRUE if can replace immediately */
|
||||
buf_block_t* block) /* in: buffer control block, must be in state
|
||||
BUF_BLOCK_FILE_PAGE and in the LRU list*/
|
||||
BUF_BLOCK_FILE_PAGE and in the LRU list */
|
||||
{
|
||||
ut_ad(mutex_own(&(buf_pool->mutex)));
|
||||
ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
|
||||
@ -134,7 +135,6 @@ buf_flush_ready_for_flush(
|
||||
|
||||
if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
|
||||
&& (block->io_fix == 0)) {
|
||||
|
||||
if (flush_type != BUF_FLUSH_LRU) {
|
||||
|
||||
return(TRUE);
|
||||
@ -436,6 +436,20 @@ buf_flush_try_page(
|
||||
&& block && buf_flush_ready_for_flush(block, flush_type)) {
|
||||
|
||||
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;
|
||||
|
||||
if (buf_pool->n_flush[flush_type] == 0) {
|
||||
@ -486,6 +500,20 @@ buf_flush_try_page(
|
||||
..._ready_for_flush). */
|
||||
|
||||
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;
|
||||
|
||||
if (buf_pool->n_flush[flush_type] == 0) {
|
||||
@ -511,6 +539,20 @@ buf_flush_try_page(
|
||||
&& buf_flush_ready_for_flush(block, flush_type)) {
|
||||
|
||||
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;
|
||||
|
||||
if (buf_pool->n_flush[block->flush_type] == 0) {
|
||||
|
@ -132,7 +132,13 @@ buf_LRU_search_and_free_block(
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
mutex_enter(&(buf_pool->mutex));
|
||||
|
||||
@ -196,7 +202,9 @@ list. */
|
||||
buf_block_t*
|
||||
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;
|
||||
ibool freed;
|
||||
@ -257,6 +265,22 @@ loop:
|
||||
|
||||
block = UT_LIST_GET_FIRST(buf_pool->free);
|
||||
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;
|
||||
|
||||
mutex_exit(&(buf_pool->mutex));
|
||||
@ -429,6 +453,13 @@ buf_LRU_remove_block(
|
||||
/* Remove the block from the LRU list */
|
||||
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 (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);
|
||||
|
||||
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) {
|
||||
|
||||
buf_pool->LRU_old_len++;
|
||||
@ -518,6 +556,15 @@ buf_LRU_add_block_low(
|
||||
block->old = old;
|
||||
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)) {
|
||||
|
||||
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);
|
||||
#endif
|
||||
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_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,
|
||||
buf_page_address_fold(block->space, block->offset),
|
||||
|
@ -576,7 +576,7 @@ buf_read_recv_pages(
|
||||
|
||||
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_thread_sleep(500000);
|
||||
|
@ -1113,6 +1113,7 @@ dict_index_add_to_cache(
|
||||
ulint n_ord;
|
||||
ibool success;
|
||||
ulint i;
|
||||
ulint j;
|
||||
|
||||
ut_ad(index);
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
@ -1143,6 +1144,28 @@ dict_index_add_to_cache(
|
||||
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,
|
||||
containing also the added system fields */
|
||||
|
||||
@ -2212,6 +2235,9 @@ dict_create_foreign_constraints(
|
||||
ulint error;
|
||||
ulint i;
|
||||
ulint j;
|
||||
ibool is_on_delete;
|
||||
ulint n_on_deletes;
|
||||
ulint n_on_updates;
|
||||
dict_col_t* columns[500];
|
||||
char* column_names[500];
|
||||
ulint column_name_lens[500];
|
||||
@ -2371,6 +2397,12 @@ col_loop2:
|
||||
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);
|
||||
|
||||
if (!success) {
|
||||
@ -2381,23 +2413,58 @@ col_loop2:
|
||||
ptr = dict_accept(ptr, "DELETE", &success);
|
||||
|
||||
if (!success) {
|
||||
ptr = dict_accept(ptr, "UPDATE", &success);
|
||||
|
||||
if (!success) {
|
||||
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
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);
|
||||
|
||||
if (success) {
|
||||
goto try_find_index;
|
||||
goto scan_on_conditions;
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, "CASCADE", &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);
|
||||
@ -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:
|
||||
/* We check that there are no superfluous words like 'ON UPDATE ...'
|
||||
which we do not support yet. */
|
||||
if (n_on_deletes > 1 || n_on_updates > 1) {
|
||||
/* It is an error to define more than 1 action */
|
||||
|
||||
ptr = dict_accept(ptr, (char *) "ON", &success);
|
||||
|
||||
if (success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
@ -3265,7 +3335,8 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||
/*=============================================*/
|
||||
char* buf, /* in: auxiliary buffer */
|
||||
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 */
|
||||
{
|
||||
|
||||
@ -3335,14 +3406,30 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
no_space:
|
||||
@ -3434,6 +3521,22 @@ dict_print_info_on_foreign_keys(
|
||||
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);
|
||||
}
|
||||
no_space:
|
||||
|
@ -2479,20 +2479,20 @@ try_again:
|
||||
n_free = n_free_list_ext + n_free_up;
|
||||
|
||||
if (alloc_type == FSP_NORMAL) {
|
||||
/* We reserve 1 extent + 4 % of the space size to undo logs
|
||||
and 1 extent + 1 % to cleaning operations; NOTE: this source
|
||||
/* We reserve 1 extent + 0.5 % of the space size to undo logs
|
||||
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
|
||||
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) {
|
||||
|
||||
goto try_to_extend;
|
||||
}
|
||||
} 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) {
|
||||
|
||||
@ -2572,11 +2572,11 @@ fsp_get_available_space_in_free_extents(
|
||||
|
||||
n_free = n_free_list_ext + n_free_up;
|
||||
|
||||
/* We reserve 1 extent + 4 % of the space size to undo logs
|
||||
and 1 extent + 1 % to cleaning operations; NOTE: this source
|
||||
/* We reserve 1 extent + 0.5 % of the space size to undo logs
|
||||
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
|
||||
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) {
|
||||
return(0);
|
||||
|
@ -2658,9 +2658,6 @@ reset_bit:
|
||||
}
|
||||
}
|
||||
|
||||
ibuf_data->n_merges++;
|
||||
ibuf_data->n_merged_recs += n_inserts;
|
||||
|
||||
#ifdef UNIV_IBUF_DEBUG
|
||||
/* printf("Ibuf merge %lu records volume %lu to page no %lu\n",
|
||||
n_inserts, volume, page_no); */
|
||||
@ -2670,6 +2667,14 @@ reset_bit:
|
||||
|
||||
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();
|
||||
#ifdef UNIV_IBUF_DEBUG
|
||||
ut_a(ibuf_count_get(space, page_no) == 0);
|
||||
|
@ -466,6 +466,9 @@ struct btr_pcur_struct{
|
||||
BTR_PCUR_AFTER, depending on whether
|
||||
cursor was on, before, or after the
|
||||
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
|
||||
buffer block when the cursor position
|
||||
was stored */
|
||||
|
@ -30,6 +30,7 @@ Created 11/5/1995 Heikki Tuuri
|
||||
#include "sync0rw.h"
|
||||
#include "hash0hash.h"
|
||||
#include "ut0byte.h"
|
||||
#include "os0proc.h"
|
||||
|
||||
/* Flags for flush types */
|
||||
#define BUF_FLUSH_LRU 1
|
||||
@ -58,23 +59,34 @@ extern ibool buf_debug_prints;/* If this is set TRUE, the program
|
||||
occurs */
|
||||
|
||||
/************************************************************************
|
||||
Initializes the buffer pool of the database. */
|
||||
Creates the buffer pool. */
|
||||
|
||||
void
|
||||
buf_pool_t*
|
||||
buf_pool_init(
|
||||
/*==========*/
|
||||
ulint max_size, /* in: maximum size of the pool in blocks */
|
||||
ulint curr_size); /* in: current size to use, must be <=
|
||||
/* out, own: buf_pool object, NULL if not
|
||||
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 */
|
||||
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
|
||||
ulint
|
||||
buf_pool_get_curr_size(void);
|
||||
/*========================*/
|
||||
/* 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
|
||||
ulint
|
||||
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
|
||||
buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and
|
||||
RW_X_LATCH are allowed as LA! */
|
||||
#define buf_page_optimistic_get(LA, G, MC, MTR) buf_page_optimistic_get_func(\
|
||||
LA, G, MC, IB__FILE__, __LINE__, MTR)
|
||||
#define buf_page_optimistic_get(LA, BL, G, MC, MTR) buf_page_optimistic_get_func(\
|
||||
LA, BL, G, MC, IB__FILE__, __LINE__, MTR)
|
||||
/************************************************************************
|
||||
This is the general function used to get optimistic access to a database
|
||||
page. */
|
||||
@ -149,7 +161,9 @@ buf_page_optimistic_get_func(
|
||||
/*=========================*/
|
||||
/* out: TRUE if success */
|
||||
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
|
||||
..._GUESS_ON_CLOCK */
|
||||
char* file, /* in: file name */
|
||||
@ -350,6 +364,16 @@ buf_frame_modify_clock_inc(
|
||||
/* out: new value */
|
||||
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
|
||||
or x-lock on the block. */
|
||||
UNIV_INLINE
|
||||
@ -428,7 +452,7 @@ UNIV_INLINE
|
||||
buf_frame_t*
|
||||
buf_frame_align(
|
||||
/*============*/
|
||||
/* out: pointer to block */
|
||||
/* out: pointer to frame */
|
||||
byte* ptr); /* in: pointer to a frame */
|
||||
/***********************************************************************
|
||||
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 -------------------------
|
||||
=========================================================================*/
|
||||
|
||||
/************************************************************************
|
||||
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
|
||||
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
|
||||
is of size UNIV_PAGE_SIZE, and
|
||||
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 offset; /* page number within the space */
|
||||
ulint lock_hash_val; /* hashed value of the page address
|
||||
@ -647,14 +693,6 @@ struct buf_block_struct{
|
||||
record lock hash table */
|
||||
rw_lock_t lock; /* read-write lock of the buffer
|
||||
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
|
||||
hash table */
|
||||
ibool check_index_page_at_flush;
|
||||
@ -691,6 +729,10 @@ struct buf_block_struct{
|
||||
/* node of the free block list */
|
||||
UT_LIST_NODE_T(buf_block_t) LRU;
|
||||
/* 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
|
||||
decreases (or may stay constant if
|
||||
the block is in the old blocks) toward
|
||||
@ -728,8 +770,8 @@ struct buf_block_struct{
|
||||
bufferfixed, or (2) the thread has an
|
||||
x-latch on the block */
|
||||
|
||||
/* 5. Hash search fields: NOTE that these fields are protected by
|
||||
btr_search_mutex */
|
||||
/* 5. Hash search fields: NOTE that the first 4 fields are NOT
|
||||
protected by any semaphore! */
|
||||
|
||||
ulint n_hash_helps; /* counter which controls building
|
||||
of a new hash index for the page */
|
||||
@ -742,6 +784,9 @@ struct buf_block_struct{
|
||||
whether the leftmost record of several
|
||||
records with the same prefix should be
|
||||
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
|
||||
built on this page; note that it does
|
||||
not guarantee that the index is
|
||||
@ -755,11 +800,12 @@ struct buf_block_struct{
|
||||
BTR_SEARCH_RIGHT_SIDE in hash
|
||||
indexing */
|
||||
/* 6. Debug fields */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
rw_lock_t debug_latch; /* in the debug version, each thread
|
||||
which bufferfixes the block acquires
|
||||
an s-latch here; so we can use the
|
||||
debug utilities in sync0rw */
|
||||
#endif
|
||||
ibool file_page_was_freed;
|
||||
/* this is set to TRUE when fsp
|
||||
frees a page in buffer pool */
|
||||
@ -778,16 +824,36 @@ struct buf_pool_struct{
|
||||
struct and control blocks, except the
|
||||
read-write lock in them */
|
||||
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:
|
||||
this may differ from frame_mem, because
|
||||
this is aligned by the frame size */
|
||||
byte* high_end; /* pointer to the end of the
|
||||
buffer pool */
|
||||
byte* high_end; /* pointer to the end of the buffer
|
||||
frames */
|
||||
ulint n_frames; /* number of frames */
|
||||
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 ==
|
||||
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 */
|
||||
|
||||
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
|
||||
with no read */
|
||||
ulint n_page_gets; /* number of page gets performed;
|
||||
also successful seraches through
|
||||
also successful searches through
|
||||
the adaptive hash index are
|
||||
counted as page gets; this field
|
||||
is NOT protected by the buffer
|
||||
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
|
||||
last time called: used to calculate
|
||||
hit rate */
|
||||
@ -812,6 +881,7 @@ struct buf_pool_struct{
|
||||
ulint n_pages_written_old;/* number write operations */
|
||||
ulint n_pages_created_old;/* number of pages created in
|
||||
the pool with no read */
|
||||
ulint n_pages_awe_remapped_old;
|
||||
/* 2. Page flushing algorithm fields */
|
||||
|
||||
UT_LIST_BASE_NODE_T(buf_block_t) flush_list;
|
||||
@ -844,7 +914,10 @@ struct buf_pool_struct{
|
||||
/* 3. LRU replacement algorithm fields */
|
||||
|
||||
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;
|
||||
/* base node of the LRU list */
|
||||
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
|
||||
on this value; not defined if
|
||||
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 */
|
||||
|
@ -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
|
||||
ulint
|
||||
buf_pool_get_curr_size(void)
|
||||
/*========================*/
|
||||
/* 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
|
||||
ulint
|
||||
buf_pool_get_max_size(void)
|
||||
/*=======================*/
|
||||
/* 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;
|
||||
|
||||
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) {
|
||||
if ((ulint)ptr < (ulint)frame_zero
|
||||
|| (ulint)ptr > (ulint)(buf_pool->high_end)) {
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
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);
|
||||
}
|
||||
|
||||
return(block);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
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);
|
||||
" InnoDB: Error: trying to access a stray pointer %lx\n"
|
||||
"InnoDB: buf pool start is at %lx, end at %lx\n"
|
||||
"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)frame_zero,
|
||||
(ulint)(buf_pool->high_end));
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
block = *(buf_pool->blocks_of_frames + (((ulint)(ptr - frame_zero))
|
||||
>> UNIV_PAGE_SIZE_SHIFT));
|
||||
return(block);
|
||||
}
|
||||
|
||||
@ -264,7 +236,7 @@ UNIV_INLINE
|
||||
buf_frame_t*
|
||||
buf_frame_align(
|
||||
/*============*/
|
||||
/* out: pointer to block */
|
||||
/* out: pointer to frame */
|
||||
byte* ptr) /* in: pointer to a frame */
|
||||
{
|
||||
buf_frame_t* frame;
|
||||
@ -273,14 +245,19 @@ buf_frame_align(
|
||||
|
||||
frame = ut_align_down(ptr, UNIV_PAGE_SIZE);
|
||||
|
||||
if (((ulint)frame
|
||||
< (ulint)(buf_pool->frame_zero))
|
||||
|| ((ulint)frame > (ulint)(buf_pool_get_nth_block(buf_pool,
|
||||
buf_pool->max_size - 1)->frame))) {
|
||||
if (((ulint)frame < (ulint)(buf_pool->frame_zero))
|
||||
|| (ulint)frame >= (ulint)(buf_pool->high_end)) {
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
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)(buf_pool->frame_zero), buf_pool->max_size);
|
||||
" InnoDB: Error: trying to access a stray pointer %lx\n"
|
||||
"InnoDB: buf pool start is at %lx, end at %lx\n"
|
||||
"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);
|
||||
}
|
||||
|
||||
@ -469,7 +446,7 @@ buf_frame_modify_clock_inc(
|
||||
|
||||
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))
|
||||
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
|
||||
@ -479,6 +456,25 @@ buf_frame_modify_clock_inc(
|
||||
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
|
||||
or x-lock on the block. */
|
||||
@ -508,15 +504,16 @@ void
|
||||
buf_block_buf_fix_inc_debug(
|
||||
/*========================*/
|
||||
buf_block_t* block, /* in: block to bufferfix */
|
||||
char* file, /* in: file name */
|
||||
ulint line) /* in: line */
|
||||
char* file __attribute__ ((unused)), /* in: file name */
|
||||
ulint line __attribute__ ((unused))) /* in: line */
|
||||
{
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ibool ret;
|
||||
|
||||
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line);
|
||||
|
||||
ut_ad(ret == TRUE);
|
||||
|
||||
#endif
|
||||
block->buf_fix_count++;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,9 @@ LRU list to the free list. */
|
||||
buf_block_t*
|
||||
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. */
|
||||
|
||||
|
@ -42,6 +42,8 @@ Created 5/24/1996 Heikki Tuuri
|
||||
#define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint
|
||||
to a table failed */
|
||||
#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 */
|
||||
#define DB_FAIL 1000
|
||||
|
@ -280,8 +280,15 @@ struct dict_foreign_struct{
|
||||
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_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
|
||||
|
||||
|
@ -355,12 +355,7 @@ in the debug version: spaces with an odd number as the id are replicate
|
||||
spaces */
|
||||
#define RECV_REPLICA_SPACE_ADD 1
|
||||
|
||||
/* This many blocks 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 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))
|
||||
extern ulint recv_n_pool_free_frames;
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "log0recv.ic"
|
||||
|
@ -127,16 +127,18 @@ mem_heap_create_func(
|
||||
ulint line /* in: line where created */
|
||||
);
|
||||
/*********************************************************************
|
||||
NOTE: Use the corresponding macro instead of this function.
|
||||
Frees the space occupied by a memory heap. */
|
||||
NOTE: Use the corresponding macro instead of this function. Frees the space
|
||||
occupied by a memory heap. In the debug version erases the heap memory
|
||||
blocks. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
mem_heap_free_func(
|
||||
/*===============*/
|
||||
mem_heap_t* heap, /* in, own: heap to be freed */
|
||||
char* file_name, /* in: file name where freed */
|
||||
ulint line /* in: line where freed */
|
||||
);
|
||||
char* file_name __attribute__((unused)),
|
||||
/* in: file name where freed */
|
||||
ulint line __attribute__((unused)));
|
||||
/* in: line where freed */
|
||||
/*******************************************************************
|
||||
Allocates n bytes of memory from a memory heap. */
|
||||
UNIV_INLINE
|
||||
|
@ -440,9 +440,10 @@ void
|
||||
mem_heap_free_func(
|
||||
/*===============*/
|
||||
mem_heap_t* heap, /* in, own: heap to be freed */
|
||||
char* file_name, /* in: file name where freed */
|
||||
ulint line /* in: line where freed */
|
||||
)
|
||||
char* file_name __attribute__((unused)),
|
||||
/* in: file name where freed */
|
||||
ulint line __attribute__((unused)))
|
||||
/* in: line where freed */
|
||||
{
|
||||
mem_block_t* block;
|
||||
mem_block_t* prev_block;
|
||||
|
@ -19,6 +19,8 @@ typedef struct mem_pool_struct mem_pool_t;
|
||||
/* The common memory pool */
|
||||
extern mem_pool_t* mem_comm_pool;
|
||||
|
||||
extern ulint mem_out_of_mem_err_msg_count;
|
||||
|
||||
/* Memory area header */
|
||||
|
||||
struct mem_area_struct{
|
||||
|
@ -15,6 +15,76 @@ Created 9/30/1995 Heikki Tuuri
|
||||
typedef void* os_process_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
|
||||
number is unique. In Linux returns the 'process number' of the current
|
||||
|
@ -52,6 +52,14 @@ row_mysql_read_var_ref_noninline(
|
||||
ulint* len, /* out: variable-length field length */
|
||||
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. */
|
||||
|
||||
void
|
||||
@ -492,7 +500,11 @@ struct row_prebuilt_struct {
|
||||
fetch many rows from the same cursor:
|
||||
it saves CPU time to fetch them in a
|
||||
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
|
||||
fetched row in fetch_cache */
|
||||
ulint n_fetch_cached; /* number of not yet fetched rows
|
||||
@ -501,8 +513,12 @@ struct row_prebuilt_struct {
|
||||
to this heap */
|
||||
mem_heap_t* old_vers_heap; /* memory heap where a previous
|
||||
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_REC_FIELDS 1
|
||||
#define ROW_MYSQL_NO_TEMPLATE 2
|
||||
|
@ -115,7 +115,8 @@ row_search_for_mysql(
|
||||
/*=================*/
|
||||
/* out: DB_SUCCESS,
|
||||
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
|
||||
row in the MySQL format */
|
||||
ulint mode, /* in: search mode PAGE_CUR_L, ... */
|
||||
|
@ -312,8 +312,11 @@ struct upd_node_struct{
|
||||
ibool in_mysql_interface;
|
||||
/* TRUE if the update node was created
|
||||
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
|
||||
is used to implement ON DELETE CASCADE
|
||||
is used to implement ON DELETE/UPDATE CASCADE
|
||||
or ... SET NULL for foreign keys */
|
||||
mem_heap_t* cascade_heap;/* NULL or a mem heap where the cascade
|
||||
node is created */
|
||||
|
@ -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
|
||||
character set */
|
||||
extern ulint srv_pool_size;
|
||||
extern ulint srv_awe_window_size;
|
||||
extern ulint srv_mem_pool_size;
|
||||
extern ulint srv_lock_table_size;
|
||||
|
||||
@ -86,6 +87,8 @@ extern ibool srv_use_doublewrite_buf;
|
||||
extern ibool srv_set_thread_priorities;
|
||||
extern int srv_query_thread_priority;
|
||||
|
||||
extern ibool srv_use_awe;
|
||||
extern ibool srv_use_adaptive_hash_indexes;
|
||||
/*-------------------------------------------*/
|
||||
|
||||
extern ulint srv_n_rows_inserted;
|
||||
|
@ -9,7 +9,8 @@ Created 1/20/1994 Heikki Tuuri
|
||||
#ifndef 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__
|
||||
|
||||
#include <windows.h>
|
||||
@ -56,6 +57,7 @@ of the 32-bit x86 assembler in mutex operations. */
|
||||
Microsoft Visual C++ */
|
||||
|
||||
#if !defined(__GNUC__) && !defined(__WIN__)
|
||||
#undef UNIV_MUST_NOT_INLINE /* Remove compiler warning */
|
||||
#define UNIV_MUST_NOT_INLINE
|
||||
#endif
|
||||
|
||||
|
@ -50,6 +50,16 @@ ut_malloc(
|
||||
/* out, own: allocated memory */
|
||||
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. */
|
||||
|
||||
void
|
||||
|
@ -438,24 +438,28 @@ log_group_calc_lsn_offset(
|
||||
log_group_t* group) /* in: log group */
|
||||
{
|
||||
dulint gr_lsn;
|
||||
ulint gr_lsn_size_offset;
|
||||
ulint difference;
|
||||
ulint group_size;
|
||||
ulint offset;
|
||||
ib_longlong gr_lsn_size_offset;
|
||||
ib_longlong difference;
|
||||
ib_longlong group_size;
|
||||
ib_longlong offset;
|
||||
|
||||
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_size_offset = log_group_calc_size_offset(group->lsn_offset,
|
||||
group);
|
||||
group_size = log_group_get_capacity(group);
|
||||
gr_lsn_size_offset = (ib_longlong)
|
||||
log_group_calc_size_offset(group->lsn_offset, group);
|
||||
|
||||
group_size = (ib_longlong) log_group_get_capacity(group);
|
||||
|
||||
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 {
|
||||
difference = ut_dulint_minus(gr_lsn, lsn);
|
||||
difference = (ib_longlong) ut_dulint_minus(gr_lsn, lsn);
|
||||
|
||||
difference = difference % group_size;
|
||||
|
||||
@ -464,7 +468,13 @@ log_group_calc_lsn_offset(
|
||||
|
||||
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);
|
||||
|
||||
recv_scan_log_recs(TRUE,
|
||||
buf_pool_get_curr_size() -
|
||||
RECV_POOL_N_FREE_BLOCKS * UNIV_PAGE_SIZE,
|
||||
(buf_pool->n_frames -
|
||||
recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
|
||||
FALSE, scan_buf, end - start,
|
||||
ut_dulint_align_down(buf_start_lsn,
|
||||
OS_FILE_LOG_BLOCK_SIZE),
|
||||
|
@ -71,6 +71,14 @@ ulint recv_previous_parsed_rec_is_multi = 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. */
|
||||
|
||||
@ -1018,10 +1026,10 @@ recv_recover_page(
|
||||
block = buf_block_align(page);
|
||||
|
||||
if (just_read_in) {
|
||||
/* Move the ownership of the x-latch on the page to this OS
|
||||
thread, so that we can acquire a second x-latch on it. This
|
||||
is needed for the operations to the page to pass the debug
|
||||
checks. */
|
||||
/* Move the ownership of the x-latch on the page to
|
||||
this OS thread, so that we can acquire a second
|
||||
x-latch on it. This is needed for the operations to
|
||||
the page to pass the debug checks. */
|
||||
|
||||
rw_lock_x_lock_move_ownership(&(block->lock));
|
||||
}
|
||||
@ -2362,8 +2370,8 @@ recv_group_scan_log_recs(
|
||||
group, start_lsn, end_lsn);
|
||||
|
||||
finished = recv_scan_log_recs(TRUE,
|
||||
buf_pool_get_curr_size()
|
||||
- RECV_POOL_N_FREE_BLOCKS * UNIV_PAGE_SIZE,
|
||||
(buf_pool->n_frames
|
||||
- recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
|
||||
TRUE, log_sys->buf,
|
||||
RECV_SCAN_SIZE, start_lsn,
|
||||
contiguous_lsn, group_scanned_lsn);
|
||||
@ -3001,8 +3009,8 @@ ask_again:
|
||||
read_offset % UNIV_PAGE_SIZE, len, buf, NULL);
|
||||
|
||||
ret = recv_scan_log_recs(TRUE,
|
||||
buf_pool_get_curr_size() -
|
||||
RECV_POOL_N_FREE_BLOCKS * UNIV_PAGE_SIZE,
|
||||
(buf_pool->n_frames -
|
||||
recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
|
||||
TRUE, buf, len, start_lsn,
|
||||
&dummy_lsn, &scanned_lsn);
|
||||
|
||||
|
@ -15,6 +15,7 @@ Created 5/12/1997 Heikki Tuuri
|
||||
#include "ut0mem.h"
|
||||
#include "ut0lst.h"
|
||||
#include "ut0byte.h"
|
||||
#include "mem0mem.h"
|
||||
|
||||
/* We would like to use also the buffer frames to allocate memory. This
|
||||
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* area2;
|
||||
ibool ret;
|
||||
char err_buf[500];
|
||||
|
||||
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
|
||||
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++;
|
||||
|
||||
return(FALSE);
|
||||
@ -300,11 +287,8 @@ mem_pool_fill_free_list(
|
||||
}
|
||||
|
||||
if (UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0) {
|
||||
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100);
|
||||
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);
|
||||
mem_analyze_corruption((byte*)area);
|
||||
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
@ -340,7 +324,6 @@ mem_area_alloc(
|
||||
mem_area_t* area;
|
||||
ulint n;
|
||||
ibool ret;
|
||||
char err_buf[500];
|
||||
|
||||
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)) {
|
||||
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100);
|
||||
fprintf(stderr,
|
||||
"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",
|
||||
n, err_buf);
|
||||
"InnoDB: element is not marked free!\n",
|
||||
n);
|
||||
|
||||
mem_analyze_corruption((byte*)area);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) {
|
||||
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100);
|
||||
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",
|
||||
n, err_buf);
|
||||
"InnoDB: though the list length is 0!\n",
|
||||
n);
|
||||
mem_analyze_corruption((byte*)area);
|
||||
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
@ -451,7 +436,6 @@ mem_area_free(
|
||||
void* new_ptr;
|
||||
ulint size;
|
||||
ulint n;
|
||||
char err_buf[500];
|
||||
|
||||
if (mem_out_of_mem_err_msg_count > 0) {
|
||||
/* 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);
|
||||
|
||||
if (mem_area_get_free(area)) {
|
||||
ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100);
|
||||
fprintf(stderr,
|
||||
"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",
|
||||
err_buf);
|
||||
"InnoDB: element is marked free!\n");
|
||||
|
||||
mem_analyze_corruption((byte*)area);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
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
|
||||
if (((byte*)area) + size < pool->buf + pool->size) {
|
||||
@ -488,7 +479,15 @@ mem_area_free(
|
||||
|
||||
next_size = mem_area_get_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
|
||||
buddy = mem_area_get_buddy(area, size, pool);
|
||||
|
@ -12,11 +12,469 @@ Created 9/30/1995 Heikki Tuuri
|
||||
#include "os0proc.ic"
|
||||
#endif
|
||||
|
||||
#ifdef __WIN__
|
||||
#include <windows.h>
|
||||
#include "ut0mem.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
|
||||
|
||||
#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
|
||||
|
@ -322,13 +322,129 @@ row_ins_clust_index_entry_by_modify(
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Either deletes or sets the referencing columns SQL NULL in a child row.
|
||||
Used in ON DELETE ... clause for foreign keys when a parent row is
|
||||
deleted. */
|
||||
Returns TRUE if in a cascaded update/delete an ancestor node of node
|
||||
updates table. */
|
||||
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
|
||||
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,
|
||||
or error code */
|
||||
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);
|
||||
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) {
|
||||
/* According to SQL-92 an UPDATE with respect to FOREIGN
|
||||
KEY constraints is not semantically equivalent to a
|
||||
DELETE + INSERT. Therefore we do not perform any action
|
||||
here and consequently the child rows would be left
|
||||
orphaned if we would let the UPDATE happen. Thus we return
|
||||
an error. */
|
||||
/* No action is defined: return a foreign key error if
|
||||
NO ACTION is not specified */
|
||||
|
||||
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -411,7 +546,10 @@ row_ins_foreign_delete_or_set_null(
|
||||
|
||||
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;
|
||||
} else {
|
||||
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;
|
||||
|
||||
ut_a(index == foreign->foreign_index);
|
||||
|
||||
rec = btr_pcur_get_rec(pcur);
|
||||
|
||||
if (index->type & DICT_CLUSTERED) {
|
||||
@ -520,7 +680,11 @@ row_ins_foreign_delete_or_set_null(
|
||||
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
|
||||
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
|
||||
pcur stored position */
|
||||
|
||||
@ -629,6 +813,7 @@ row_ins_check_foreign_constraint(
|
||||
dtuple_t* entry, /* in: index entry for index */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
upd_node_t* upd_node;
|
||||
dict_table_t* check_table;
|
||||
dict_index_t* check_index;
|
||||
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) {
|
||||
check_table = foreign->referenced_table;
|
||||
check_index = foreign->referenced_index;
|
||||
@ -774,8 +983,12 @@ run_again:
|
||||
|
||||
break;
|
||||
} else if (foreign->type != 0) {
|
||||
/* There is an ON UPDATE or ON DELETE
|
||||
condition: check them in a separate
|
||||
function */
|
||||
|
||||
err =
|
||||
row_ins_foreign_delete_or_set_null(
|
||||
row_ins_foreign_check_on_constraint(
|
||||
thr, foreign, &pcur, &mtr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
@ -58,6 +58,19 @@ row_mysql_read_var_ref_noninline(
|
||||
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. */
|
||||
|
||||
@ -313,6 +326,7 @@ row_create_prebuilt(
|
||||
prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
|
||||
|
||||
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
|
||||
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
|
||||
|
||||
prebuilt->table = table;
|
||||
|
||||
@ -378,11 +392,12 @@ row_prebuilt_free(
|
||||
{
|
||||
ulint i;
|
||||
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|
||||
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
"InnoDB: table handle. Magic n %lu, table name %s\n",
|
||||
prebuilt->magic_n, prebuilt->table->name);
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
"InnoDB: table handle. Magic n %lu, magic n2 %lu, table name %s\n",
|
||||
prebuilt->magic_n, prebuilt->magic_n2, prebuilt->table->name);
|
||||
|
||||
mem_analyze_corruption((byte*)prebuilt);
|
||||
|
||||
@ -390,6 +405,7 @@ row_prebuilt_free(
|
||||
}
|
||||
|
||||
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->clust_pcur);
|
||||
@ -420,7 +436,23 @@ row_prebuilt_free(
|
||||
|
||||
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
|
||||
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(
|
||||
/*=======================*/
|
||||
/* 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 */
|
||||
{
|
||||
ind_node_t* node;
|
||||
@ -1444,6 +1476,8 @@ row_create_index_for_mysql(
|
||||
ulint namelen;
|
||||
ulint keywordlen;
|
||||
ulint err;
|
||||
ulint i;
|
||||
ulint j;
|
||||
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
@ -1465,6 +1499,31 @@ row_create_index_for_mysql(
|
||||
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);
|
||||
|
||||
trx->dict_operation = TRUE;
|
||||
@ -1479,9 +1538,11 @@ row_create_index_for_mysql(
|
||||
|
||||
err = trx->error_state;
|
||||
|
||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||
|
||||
error_handling:
|
||||
if (err != DB_SUCCESS) {
|
||||
/* We have special error handling here */
|
||||
ut_a(err == DB_OUT_OF_FILE_SPACE);
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
|
||||
@ -1492,8 +1553,6 @@ row_create_index_for_mysql(
|
||||
trx->error_state = DB_SUCCESS;
|
||||
}
|
||||
|
||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||
|
||||
trx->op_info = (char *) "";
|
||||
|
||||
return((int) err);
|
||||
|
@ -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
|
||||
be needed in the query. */
|
||||
static
|
||||
void
|
||||
ibool
|
||||
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 */
|
||||
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
|
||||
rec_t* rec) /* in: Innobase record in the index
|
||||
@ -2093,6 +2096,18 @@ row_sel_store_mysql_rec(
|
||||
|
||||
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
|
||||
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 */
|
||||
rec_t* rec) /* in: record to push */
|
||||
{
|
||||
byte* buf;
|
||||
ulint i;
|
||||
|
||||
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 */
|
||||
|
||||
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,
|
||||
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
|
||||
row in the MySQL format */
|
||||
ulint mode, /* in: search mode PAGE_CUR_L, ... */
|
||||
@ -2747,7 +2776,12 @@ row_search_for_mysql(
|
||||
#ifdef UNIV_SEARCH_DEBUG
|
||||
ut_a(0 == cmp_dtuple_rec(search_tuple, rec));
|
||||
#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);
|
||||
|
||||
@ -3189,7 +3223,11 @@ rec_loop:
|
||||
rec_get_size(rec));
|
||||
mach_write_to_4(buf, rec_get_extra_size(rec) + 4);
|
||||
} 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) {
|
||||
|
@ -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
|
||||
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
|
||||
key constraint. */
|
||||
@ -132,6 +146,7 @@ ulint
|
||||
row_upd_check_references_constraints(
|
||||
/*=================================*/
|
||||
/* 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
|
||||
cursor position is lost in this function! */
|
||||
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);
|
||||
|
||||
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) {
|
||||
dict_table_get(foreign->foreign_table_name,
|
||||
trx);
|
||||
@ -189,10 +213,9 @@ row_upd_check_references_constraints(
|
||||
}
|
||||
|
||||
/* NOTE that if the thread ends up waiting for a lock
|
||||
we will release dict_operation_lock
|
||||
temporarily! But the counter on the table
|
||||
protects 'foreign' from being dropped while the check
|
||||
is running. */
|
||||
we will release dict_operation_lock temporarily!
|
||||
But the counter on the table protects 'foreign' from
|
||||
being dropped while the check is running. */
|
||||
|
||||
err = row_ins_check_foreign_constraint(FALSE, foreign,
|
||||
table, index, entry, thr);
|
||||
@ -255,6 +278,7 @@ upd_node_create(
|
||||
node->index = NULL;
|
||||
node->update = NULL;
|
||||
|
||||
node->foreign = NULL;
|
||||
node->cascade_heap = NULL;
|
||||
node->cascade_node = NULL;
|
||||
|
||||
@ -953,6 +977,53 @@ row_upd_changes_some_index_ord_field_binary(
|
||||
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. */
|
||||
UNIV_INLINE
|
||||
@ -1106,9 +1177,11 @@ row_upd_sec_index_entry(
|
||||
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
|
||||
thr, &mtr);
|
||||
if (err == DB_SUCCESS && check_ref) {
|
||||
|
||||
/* NOTE that the following call loses
|
||||
the position of pcur ! */
|
||||
err = row_upd_check_references_constraints(
|
||||
node,
|
||||
&pcur, index->table,
|
||||
index, thr, &mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
@ -1224,7 +1297,7 @@ row_upd_clust_rec_by_insert(
|
||||
if (check_ref) {
|
||||
/* NOTE that the following call loses
|
||||
the position of pcur ! */
|
||||
err = row_upd_check_references_constraints(
|
||||
err = row_upd_check_references_constraints(node,
|
||||
pcur, table,
|
||||
index, thr, mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
@ -1392,7 +1465,8 @@ row_upd_del_mark_clust_rec(
|
||||
if (err == DB_SUCCESS && check_ref) {
|
||||
/* 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);
|
||||
if (err != DB_SUCCESS) {
|
||||
mtr_commit(mtr);
|
||||
|
@ -140,9 +140,14 @@ byte srv_latin1_ordering[256] /* The sort order table of the latin1
|
||||
, 0xD8, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0xFF
|
||||
};
|
||||
|
||||
ulint srv_pool_size = ULINT_MAX; /* size in database pages;
|
||||
MySQL originally sets this
|
||||
value in megabytes */
|
||||
ulint srv_pool_size = ULINT_MAX; /* size in pages; MySQL inits
|
||||
this to size in kilobytes but
|
||||
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_lock_table_size = ULINT_MAX;
|
||||
|
||||
@ -218,6 +223,13 @@ ibool srv_use_doublewrite_buf = TRUE;
|
||||
|
||||
ibool srv_set_thread_priorities = TRUE;
|
||||
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_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_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);
|
||||
}
|
||||
@ -2323,6 +2345,18 @@ srv_sprintf_innodb_monitor(
|
||||
"Total memory allocated %lu; in additional pool allocated %lu\n",
|
||||
ut_total_allocated_memory,
|
||||
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 = buf + strlen(buf);
|
||||
ut_a(buf < buf_end + 1500);
|
||||
|
@ -529,6 +529,9 @@ open_or_create_log_file(
|
||||
new database */
|
||||
ibool* log_file_created, /* out: TRUE if new log file
|
||||
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 i) /* in: log file number in group */
|
||||
{
|
||||
@ -587,6 +590,11 @@ open_or_create_log_file(
|
||||
fprintf(stderr,
|
||||
" InnoDB: Log file %s did not exist: new to be created\n",
|
||||
name);
|
||||
if (log_file_has_been_opened) {
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
fprintf(stderr, "InnoDB: Setting log file %s size to %lu MB\n",
|
||||
name, srv_log_file_size
|
||||
>> (20 - UNIV_PAGE_SIZE_SHIFT));
|
||||
@ -927,6 +935,7 @@ innobase_start_or_create_for_mysql(void)
|
||||
/*====================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
{
|
||||
buf_pool_t* ret;
|
||||
ibool create_new_db;
|
||||
ibool log_file_created;
|
||||
ibool log_created = FALSE;
|
||||
@ -962,6 +971,11 @@ innobase_start_or_create_for_mysql(void)
|
||||
#ifdef UNIV_MEM_DEBUG
|
||||
fprintf(stderr,
|
||||
"InnoDB: !!!!!!!!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!!!!!!!\n");
|
||||
#endif
|
||||
|
||||
#ifdef UNIV_SIMULATE_AWE
|
||||
fprintf(stderr,
|
||||
"InnoDB: !!!!!!!!!!!!!! UNIV_SIMULATE_AWE switched on !!!!!!!!!!!!!!!!!\n");
|
||||
#endif
|
||||
|
||||
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;
|
||||
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__
|
||||
if (os_get_os_version() == OS_WIN95
|
||||
|| os_get_os_version() == OS_WIN31
|
||||
@ -1049,6 +1074,9 @@ innobase_start_or_create_for_mysql(void)
|
||||
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();
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
@ -1080,7 +1108,26 @@ innobase_start_or_create_for_mysql(void)
|
||||
|
||||
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();
|
||||
log_init();
|
||||
@ -1160,7 +1207,8 @@ innobase_start_or_create_for_mysql(void)
|
||||
for (i = 0; i < srv_n_log_files; i++) {
|
||||
|
||||
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) {
|
||||
|
||||
return((int) err);
|
||||
|
@ -77,8 +77,9 @@ ut_malloc_low(
|
||||
ret = malloc(n + sizeof(ut_mem_block_t));
|
||||
|
||||
if (ret == NULL) {
|
||||
ut_print_timestamp(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: by InnoDB %lu bytes. Operating system errno: %d\n"
|
||||
"InnoDB: Cannot continue operation!\n"
|
||||
@ -134,6 +135,40 @@ ut_malloc(
|
||||
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. */
|
||||
|
||||
|
@ -262,7 +262,7 @@ ut_print_buf(
|
||||
data = buf;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (isprint((char)(*data))) {
|
||||
if (isprint((int)(*data))) {
|
||||
printf("%c", (char)*data);
|
||||
}
|
||||
data++;
|
||||
@ -302,7 +302,7 @@ ut_sprintf_buf(
|
||||
data = buf;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (isprint((char)(*data))) {
|
||||
if (isprint((int)(*data))) {
|
||||
n += sprintf(str + n, "%c", (char)*data);
|
||||
} else {
|
||||
n += sprintf(str + n, ".");
|
||||
|
@ -37,12 +37,12 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \
|
||||
int2str.lo str2int.lo strinstr.lo strcont.lo \
|
||||
strcend.lo bcmp.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-big5.lo ctype-czech.lo ctype-euc_kr.lo \
|
||||
ctype-win1250ch.lo ctype-utf8.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
|
||||
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 \
|
||||
charset.lo hash.lo mf_iocache.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
|
||||
sqlobjects = net.lo
|
||||
|
||||
|
@ -61,7 +61,7 @@ static my_bool mysql_client_init=0;
|
||||
uint mysql_port=0;
|
||||
my_string mysql_unix_port=0;
|
||||
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_write_timeout= NET_WRITE_TIMEOUT;
|
||||
|
||||
@ -928,7 +928,8 @@ static const char *default_options[]=
|
||||
"character-sets-dir", "default-character-set", "interactive-timeout",
|
||||
"connect-timeout", "local-infile", "disable-local-infile",
|
||||
"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
|
||||
};
|
||||
|
||||
@ -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))) ||
|
||||
insert_dynamic(options->init_commands, (byte*)&tmp))
|
||||
insert_dynamic(options->init_commands, (gptr)&tmp))
|
||||
{
|
||||
my_free(tmp, MYF(MY_ALLOW_ZERO_PTR));
|
||||
return 1;
|
||||
@ -1099,14 +1100,17 @@ static void mysql_read_default_options(struct st_mysql_options *options,
|
||||
case 25: /* repl-parse-query */
|
||||
options->rpl_parse= 1;
|
||||
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)
|
||||
{
|
||||
fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 28: /*shared_memory_base_name*/
|
||||
case 29: /* shared_memory_base_name */
|
||||
#ifdef HAVE_SMEM
|
||||
if (options->shared_memory_base_name != def_shared_memory_base_name)
|
||||
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
|
||||
{
|
||||
cur->data[field] = to;
|
||||
if (to+len > end_to)
|
||||
if (len > (ulong) (end_to - to))
|
||||
{
|
||||
free_rows(result);
|
||||
net->last_errno=CR_MALFORMED_PACKET;
|
||||
@ -1315,7 +1319,7 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
|
||||
{
|
||||
uint field;
|
||||
ulong pkt_len,len;
|
||||
uchar *pos,*prev_pos;
|
||||
uchar *pos,*prev_pos, *end_pos;
|
||||
|
||||
if ((pkt_len=net_safe_read(mysql)) == packet_error)
|
||||
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] */
|
||||
pos=mysql->net.read_pos;
|
||||
end_pos=pos+pkt_len;
|
||||
for (field=0 ; field < fields ; field++)
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
pos+=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_capath= strdup_if_not_null(capath);
|
||||
mysql->options.ssl_cipher= strdup_if_not_null(cipher);
|
||||
#endif
|
||||
#endif /* HAVE_OPENSSL */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1763,10 +1774,10 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
|
||||
NB! Errors are not reported until you do mysql_real_connect.
|
||||
**************************************************************************/
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
static void
|
||||
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_cert, 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.use_ssl = FALSE;
|
||||
mysql->connector_fd = 0;
|
||||
#endif /* HAVE_OPENSLL */
|
||||
}
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
/**************************************************************************
|
||||
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",
|
||||
mysql->server_version,mysql->server_capabilities,
|
||||
mysql->server_status, client_flag));
|
||||
/* This needs to be changed as it's not useful with big packets */
|
||||
int3store(buff+2,max_allowed_packet);
|
||||
if (user && user[0])
|
||||
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 */
|
||||
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))
|
||||
goto error;
|
||||
|
||||
@ -2623,8 +2637,13 @@ mysql_close(MYSQL *mysql)
|
||||
my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
|
||||
if (mysql->options.init_commands)
|
||||
{
|
||||
delete_dynamic(mysql->options.init_commands);
|
||||
my_free((char*)mysql->options.init_commands,MYF(MY_WME));
|
||||
DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
|
||||
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
|
||||
mysql_ssl_free(mysql);
|
||||
@ -2841,7 +2860,7 @@ mysql_real_query(MYSQL *mysql, const char *query, ulong length)
|
||||
{
|
||||
DBUG_ENTER("mysql_real_query");
|
||||
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))
|
||||
DBUG_RETURN(1);
|
||||
@ -3503,18 +3522,6 @@ uint STDCALL mysql_thread_safe(void)
|
||||
#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
|
||||
****************************************************************************/
|
||||
@ -3819,12 +3826,13 @@ static my_bool my_realloc_str(NET *net, ulong length)
|
||||
1 error
|
||||
*/
|
||||
|
||||
static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
|
||||
static my_bool read_prepare_result(MYSQL_STMT *stmt)
|
||||
{
|
||||
uchar *pos;
|
||||
uint field_count;
|
||||
ulong length, param_count;
|
||||
MYSQL_DATA *fields_data;
|
||||
ulong length;
|
||||
MYSQL *mysql= stmt->mysql;
|
||||
DBUG_ENTER("read_prepare_result");
|
||||
|
||||
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;
|
||||
stmt->stmt_id= uint4korr(pos); pos+=4;
|
||||
field_count= uint2korr(pos); pos+=2;
|
||||
stmt->param_count=uint2korr(pos); pos+=2;
|
||||
param_count= uint2korr(pos); pos+=2;
|
||||
|
||||
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->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);
|
||||
}
|
||||
|
||||
@ -3903,13 +3912,13 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length)
|
||||
}
|
||||
|
||||
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);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
stmt->state= MY_ST_PREPARE;
|
||||
stmt->mysql= mysql;
|
||||
mysql->stmts= list_add(mysql->stmts, &stmt->list);
|
||||
stmt->list.data= stmt;
|
||||
DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count));
|
||||
@ -3928,10 +3937,14 @@ mysql_prepare_result(MYSQL_STMT *stmt)
|
||||
MYSQL_RES *result;
|
||||
DBUG_ENTER("mysql_prepare_result");
|
||||
|
||||
if (!stmt->fields)
|
||||
if (!stmt->field_count || !stmt->fields)
|
||||
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->fields= stmt->fields;
|
||||
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,
|
||||
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);
|
||||
else
|
||||
{
|
||||
@ -4096,7 +4110,6 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -4184,7 +4190,7 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt)
|
||||
for (param= stmt->params; param < param_end; param++)
|
||||
{
|
||||
/* 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)
|
||||
DBUG_RETURN(MYSQL_NEED_DATA);
|
||||
@ -4219,6 +4225,14 @@ ulong STDCALL mysql_param_count(MYSQL_STMT * stmt)
|
||||
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
|
||||
@ -4252,7 +4266,7 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
|
||||
param++)
|
||||
{
|
||||
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_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 */
|
||||
switch (param->buffer_type) {
|
||||
case MYSQL_TYPE_NULL:
|
||||
param->is_null=1;
|
||||
param->bind_length= MYSQL_NULL_DATA;
|
||||
break;
|
||||
case MYSQL_TYPE_TINY:
|
||||
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)
|
||||
****************************************************************************/
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@ -4415,31 +4741,31 @@ static void fetch_result_tinyint(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);
|
||||
*row+=2;
|
||||
*row+= 2;
|
||||
}
|
||||
|
||||
static void fetch_result_int32(MYSQL_BIND *param, uchar **row)
|
||||
{
|
||||
int32 value= *(int32 *)row;
|
||||
int32 value= (int32)sint4korr(*row);
|
||||
int4store(param->buffer, value);
|
||||
*row+=4;
|
||||
*row+= 4;
|
||||
}
|
||||
|
||||
static void fetch_result_int64(MYSQL_BIND *param, uchar **row)
|
||||
{
|
||||
longlong value= *(longlong *)row;
|
||||
longlong value= (longlong)sint8korr(*row);
|
||||
int8store(param->buffer, value);
|
||||
*row+=8;
|
||||
*row+= 8;
|
||||
}
|
||||
|
||||
static void fetch_result_float(MYSQL_BIND *param, uchar **row)
|
||||
{
|
||||
float value;
|
||||
float4get(value,*row);
|
||||
float4store(param->buffer, *row);
|
||||
*row+=4;
|
||||
float4store(param->buffer, value);
|
||||
*row+= 4;
|
||||
}
|
||||
|
||||
static void fetch_result_double(MYSQL_BIND *param, uchar **row)
|
||||
@ -4447,15 +4773,16 @@ static void fetch_result_double(MYSQL_BIND *param, uchar **row)
|
||||
double value;
|
||||
float8get(value,*row);
|
||||
float8store(param->buffer, value);
|
||||
*row+=8;
|
||||
*row+= 8;
|
||||
}
|
||||
|
||||
static void fetch_result_str(MYSQL_BIND *param, uchar **row)
|
||||
{
|
||||
ulong length= net_field_length(row);
|
||||
memcpy(param->buffer, (char *)*row, length);
|
||||
*(param->buffer+length)= '\0';
|
||||
*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);
|
||||
|
||||
#ifdef CHECK_EXTRA_ARGUMENTS
|
||||
if (stmt->state == MY_ST_UNKNOWN)
|
||||
{
|
||||
set_stmt_error(stmt, CR_NO_PREPARE_STMT);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (!bind)
|
||||
{
|
||||
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 */
|
||||
switch (param->buffer_type) {
|
||||
case MYSQL_TYPE_TINY:
|
||||
param->bind_length= 1;
|
||||
param->fetch_result= fetch_result_tinyint;
|
||||
break;
|
||||
case MYSQL_TYPE_SHORT:
|
||||
param->bind_length= 2;
|
||||
param->fetch_result= fetch_result_short;
|
||||
break;
|
||||
case MYSQL_TYPE_LONG:
|
||||
param->bind_length= 4;
|
||||
param->fetch_result= fetch_result_int32;
|
||||
break;
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
param->bind_length= 8;
|
||||
param->fetch_result= fetch_result_int64;
|
||||
break;
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
param->bind_length= 4;
|
||||
param->fetch_result= fetch_result_float;
|
||||
break;
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
param->bind_length= 8;
|
||||
param->fetch_result= fetch_result_double;
|
||||
break;
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_STRING:
|
||||
param->length= ¶m->buffer_length;
|
||||
param->fetch_result= fetch_result_str;
|
||||
break;
|
||||
default:
|
||||
@ -4523,6 +4849,7 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
|
||||
}
|
||||
if (!param->length)
|
||||
param->length= ¶m->bind_length;
|
||||
*param->length= (long)get_binary_length(param->buffer_type);
|
||||
}
|
||||
stmt->res_buffers= 1;
|
||||
DBUG_RETURN(0);
|
||||
@ -4532,41 +4859,51 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
|
||||
Fetch row data to bind buffers
|
||||
*/
|
||||
|
||||
static my_bool
|
||||
stmt_fetch_row(MYSQL_STMT *stmt, uchar **row)
|
||||
static void
|
||||
stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
|
||||
{
|
||||
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;
|
||||
bit= 4; /* First 2 bits are reserved */
|
||||
null_ptr= row;
|
||||
row+= (stmt->field_count+9)/8; /* skip null bits */
|
||||
bit= 4; /* first 2 bits are reserved */
|
||||
|
||||
/* Copy complete row to application buffers */
|
||||
for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count;
|
||||
bind < end;
|
||||
bind++)
|
||||
for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count,
|
||||
field= stmt->fields,
|
||||
field_end= (MYSQL_FIELD *)stmt->fields+stmt->field_count;
|
||||
bind < end && field < field_end;
|
||||
bind++, field++)
|
||||
{
|
||||
if (*null_ptr & bit)
|
||||
bind->is_null= 1;
|
||||
*bind->length= MYSQL_NULL_DATA;
|
||||
else
|
||||
{
|
||||
bind->is_null= 0;
|
||||
(*bind->fetch_result)(bind, row);
|
||||
if (field->type == bind->buffer_type)
|
||||
(*bind->fetch_result)(bind, &row);
|
||||
else if (fetch_results(stmt, bind, field->type, &row))
|
||||
break;
|
||||
}
|
||||
if (! (bit<<=1) & 255)
|
||||
{
|
||||
bit=1; /* To next byte */
|
||||
bit= 1; /* To next byte */
|
||||
null_ptr++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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))
|
||||
return -1;
|
||||
if (mysql->net.read_pos[0])
|
||||
if (mysql->net.read_pos[0] == 254)
|
||||
return 1; /* End of data */
|
||||
return 0;
|
||||
}
|
||||
@ -4579,29 +4916,24 @@ static int read_binary_data(MYSQL *mysql)
|
||||
int STDCALL mysql_fetch(MYSQL_STMT *stmt)
|
||||
{
|
||||
MYSQL *mysql= stmt->mysql;
|
||||
int res;
|
||||
DBUG_ENTER("mysql_fetch");
|
||||
|
||||
if (stmt->res_buffers)
|
||||
{
|
||||
int res;
|
||||
if (!(res= read_binary_data(mysql)))
|
||||
{
|
||||
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_PRINT("info", ("end of data"));
|
||||
mysql->status= MYSQL_STATUS_READY;
|
||||
|
||||
if (res < 0) /* Network error */
|
||||
{
|
||||
set_stmt_errmsg(stmt,(char *)mysql->net.last_error,
|
||||
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(0); //?? do we need to set MYSQL_STATUS_READY ?
|
||||
}
|
||||
|
||||
|
||||
|
@ -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))) ||
|
||||
insert_dynamic(options->init_commands, (byte*)&tmp))
|
||||
insert_dynamic(options->init_commands, (gptr)&tmp))
|
||||
{
|
||||
my_free(tmp, MYF(MY_ALLOW_ZERO_PTR));
|
||||
return 1;
|
||||
@ -630,8 +630,13 @@ mysql_close(MYSQL *mysql)
|
||||
my_free(mysql->options.charset_name,MYF(MY_ALLOW_ZERO_PTR));
|
||||
if (mysql->options.init_commands)
|
||||
{
|
||||
delete_dynamic(mysql->options.init_commands);
|
||||
my_free((char*)mysql->options.init_commands,MYF(MY_WME));
|
||||
DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
|
||||
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 */
|
||||
bzero((char*) &mysql->options,sizeof(mysql->options));
|
||||
|
@ -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,
|
||||
SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
|
||||
aio->info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */
|
||||
|
||||
while (!r)
|
||||
{
|
||||
|
@ -368,8 +368,8 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
|
||||
{
|
||||
/* Remember old statistics for key */
|
||||
memcpy((char*) rec_per_key_part,
|
||||
(char*) share->state.rec_per_key_part+
|
||||
(uint) (rec_per_key_part - param->rec_per_key_part),
|
||||
(char*) (share->state.rec_per_key_part +
|
||||
(uint) (rec_per_key_part - param->rec_per_key_part)),
|
||||
keyinfo->keysegs*sizeof(*rec_per_key_part));
|
||||
continue;
|
||||
}
|
||||
@ -601,7 +601,8 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
|
||||
if (*keys != 1L) /* not first_key */
|
||||
{
|
||||
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);
|
||||
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 */
|
||||
memcpy((char*) rec_per_key_part,
|
||||
(char*) share->state.rec_per_key_part+
|
||||
(uint) (rec_per_key_part - param->rec_per_key_part),
|
||||
(char*) (share->state.rec_per_key_part +
|
||||
(uint) (rec_per_key_part - param->rec_per_key_part)),
|
||||
sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part));
|
||||
continue;
|
||||
}
|
||||
@ -2272,8 +2273,8 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
||||
{
|
||||
/* Remember old statistics for key */
|
||||
memcpy((char*) rec_per_key_part,
|
||||
(char*) share->state.rec_per_key_part+
|
||||
(uint) (rec_per_key_part - param->rec_per_key_part),
|
||||
(char*) (share->state.rec_per_key_part+
|
||||
(uint) (rec_per_key_part - param->rec_per_key_part)),
|
||||
sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part));
|
||||
i--;
|
||||
continue;
|
||||
@ -2435,7 +2436,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
|
||||
got_error=0;
|
||||
|
||||
if (&share->state.state != info->state)
|
||||
memcpy( &share->state.state, info->state, sizeof(*info->state));
|
||||
memcpy(&share->state.state, info->state, sizeof(*info->state));
|
||||
|
||||
err:
|
||||
got_error|= flush_blocks(param,share->kfile);
|
||||
@ -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;
|
||||
const byte *end=buf+length;
|
||||
|
@ -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:
|
||||
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))
|
||||
{
|
||||
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
|
||||
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 (info->opt_flag & MEMMAP_USED)
|
||||
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:
|
||||
info->quick_mode=1;
|
||||
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:
|
||||
if (!share->state.header.uniques)
|
||||
info->opt_flag|= OPT_NO_ROWS;
|
||||
|
@ -573,28 +573,36 @@ err:
|
||||
DBUG_RETURN (NULL);
|
||||
} /* mi_open */
|
||||
|
||||
|
||||
byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf)
|
||||
{
|
||||
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;
|
||||
|
||||
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */
|
||||
if (length == (ulong) -1)
|
||||
{
|
||||
length= max(info->s->base.pack_reclength+info->s->base.pack_bits,
|
||||
info->s->base.max_key_length);
|
||||
/* Avoid unnecessary realloc */
|
||||
if (newptr && length == old_length)
|
||||
return newptr;
|
||||
}
|
||||
|
||||
extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
|
||||
ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
|
||||
MI_REC_BUFF_OFFSET : 0);
|
||||
if (extra && newptr)
|
||||
newptr-=MI_REC_BUFF_OFFSET;
|
||||
newptr-= MI_REC_BUFF_OFFSET;
|
||||
if (!(newptr=(byte*) my_realloc((gptr)newptr, length+extra+8,
|
||||
MYF(MY_ALLOW_ZERO_PTR))))
|
||||
return newptr;
|
||||
*((uint *)newptr)=length;
|
||||
*((uint32 *) newptr)= (uint32) length;
|
||||
*buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
|
||||
}
|
||||
return *buf;
|
||||
|
@ -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 *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.
|
||||
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;
|
||||
uint nod_flag, length, len, matched, cmplen, kseg_len;
|
||||
uint prefix_len,suffix_len;
|
||||
|
@ -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;
|
||||
int i,j,error,deleted,rec_length,uniques=0;
|
||||
|
@ -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;
|
||||
MI_KEYDEF *key=share->keyinfo;
|
||||
bulk_insert_param *params;
|
||||
uint i, num_keys;
|
||||
uint i, num_keys, total_keylength;
|
||||
ulonglong key_map=0;
|
||||
DBUG_ENTER("_mi_init_bulk_insert");
|
||||
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);
|
||||
|
||||
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
|
||||
&& test(share->state.key_map & ((ulonglong) 1 << i)))
|
||||
{
|
||||
num_keys++;
|
||||
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)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (rows && rows*total_keylength < cache_size)
|
||||
cache_size=rows;
|
||||
else
|
||||
cache_size/=total_keylength*16;
|
||||
|
||||
info->bulk_insert=(TREE *)
|
||||
my_malloc((sizeof(TREE)*share->base.keys+
|
||||
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);
|
||||
|
||||
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)))
|
||||
{
|
||||
@ -847,8 +853,8 @@ int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size)
|
||||
params->keynr=i;
|
||||
/* Only allocate a 16'th of the buffer at a time */
|
||||
init_tree(&info->bulk_insert[i],
|
||||
cache_size / num_keys / 16 + 10,
|
||||
cache_size / num_keys, 0,
|
||||
cache_size * key[i].maxlength,
|
||||
cache_size * key[i].maxlength, 0,
|
||||
(qsort_cmp2)keys_compare, 0,
|
||||
(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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ typedef struct st_mi_sort_param
|
||||
#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_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 */
|
||||
|
||||
@ -400,6 +400,7 @@ typedef struct st_mi_sort_param
|
||||
#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_ROWS_TO_USE_BULK_INSERT 100
|
||||
|
||||
/* 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)) ? \
|
||||
(buf) - MI_REC_BUFF_OFFSET : (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,
|
||||
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);
|
||||
void mi_setup_functions(register MYISAM_SHARE *share);
|
||||
|
||||
int _mi_init_bulk_insert(MI_INFO *info, ulong cache_size);
|
||||
|
||||
/* Functions needed by mi_check */
|
||||
volatile bool *killed_ptr(MI_CHECK *param);
|
||||
void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));
|
||||
|
@ -28,8 +28,6 @@ ulonglong myrg_position(MYRG_INFO *info)
|
||||
~(ulonglong) 0;
|
||||
}
|
||||
|
||||
/* If flag != 0 one only gets pos of last record */
|
||||
|
||||
int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag)
|
||||
{
|
||||
MYRG_TABLE *current_table;
|
||||
@ -55,15 +53,16 @@ int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag)
|
||||
DBUG_PRINT("info2",("table: %s, offset: %lu",
|
||||
file->table->filename,(ulong) file->file_offset));
|
||||
}
|
||||
x->records = info->records;
|
||||
x->deleted = info->del;
|
||||
x->data_file_length = info->data_file_length;
|
||||
x->reclength = info->reclength;
|
||||
x->options = info->options;
|
||||
x->records= info->records;
|
||||
x->deleted= info->del;
|
||||
x->data_file_length= info->data_file_length;
|
||||
x->reclength= info->reclength;
|
||||
x->options= info->options;
|
||||
if (current_table)
|
||||
x->errkey = current_table->table->errkey;
|
||||
x->errkey= current_table->table->errkey;
|
||||
else
|
||||
x->errkey=0;
|
||||
x->errkey= 0;
|
||||
x->rec_per_key = info->rec_per_key_part;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
|
||||
{
|
||||
int save_errno,i,errpos;
|
||||
uint files,dir_length,length,options;
|
||||
uint files,dir_length,length,options, key_parts;
|
||||
ulonglong file_offset;
|
||||
char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
|
||||
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;
|
||||
}
|
||||
key_parts=(isam ? isam->s->base.key_parts : 0);
|
||||
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))))
|
||||
goto err;
|
||||
*m_info=info;
|
||||
m_info->open_tables=(files) ? (MYRG_TABLE *) (m_info+1) : 0;
|
||||
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;
|
||||
|
||||
options= (uint) ~0;
|
||||
for (i=files ; i-- > 0 ; )
|
||||
{
|
||||
uint j;
|
||||
m_info->open_tables[i].table=isam;
|
||||
m_info->options|=isam->s->options;
|
||||
options&=isam->s->options;
|
||||
m_info->records+=isam->state->records;
|
||||
m_info->del+=isam->state->del;
|
||||
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)
|
||||
isam=(MI_INFO*) (isam->open_list.next->data);
|
||||
}
|
||||
|
@ -7,12 +7,16 @@ connection slave;
|
||||
!stop slave;
|
||||
@r/slave-stopped.result show status like 'Slave_running';
|
||||
connection master;
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
--enable_warnings
|
||||
reset master;
|
||||
connection slave;
|
||||
reset slave;
|
||||
# Clean up old test tables
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
--enable_warnings
|
||||
start slave;
|
||||
@r/slave-running.result show status like 'Slave_running';
|
||||
|
||||
|
@ -88,6 +88,7 @@ sleep_until_file_created ()
|
||||
wait_for_pid()
|
||||
{
|
||||
pid=$1
|
||||
#$WAIT_PID pid $SLEEP_TIME_FOR_DELETE
|
||||
}
|
||||
|
||||
# No paths below as we can't be sure where the program is!
|
||||
@ -347,9 +348,9 @@ while test $# -gt 0; do
|
||||
;;
|
||||
--debug)
|
||||
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 \
|
||||
--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"
|
||||
;;
|
||||
--fast)
|
||||
@ -423,6 +424,7 @@ if [ x$SOURCE_DIST = x1 ] ; then
|
||||
fi
|
||||
|
||||
MYSQLADMIN="$BASEDIR/client/mysqladmin"
|
||||
WAIT_PID="$BASEDIR/extra/mysql_waitpid"
|
||||
MYSQL_MANAGER_CLIENT="$BASEDIR/client/mysqlmanagerc"
|
||||
MYSQL_MANAGER="$BASEDIR/tools/mysqlmanager"
|
||||
MYSQL_MANAGER_PWGEN="$BASEDIR/client/mysqlmanager-pwgen"
|
||||
@ -439,6 +441,7 @@ else
|
||||
fi
|
||||
MYSQL_TEST="$BASEDIR/bin/mysqltest"
|
||||
MYSQLADMIN="$BASEDIR/bin/mysqladmin"
|
||||
WAIT_PID="$BASEDIR/bin/mysql_waitpid"
|
||||
MYSQL_MANAGER="$BASEDIR/bin/mysqlmanager"
|
||||
MYSQL_MANAGER_CLIENT="$BASEDIR/bin/mysqlmanagerc"
|
||||
MYSQL_MANAGER_PWGEN="$BASEDIR/bin/mysqlmanager-pwgen"
|
||||
@ -753,9 +756,9 @@ manager_term()
|
||||
{
|
||||
pid=$1
|
||||
ident=$2
|
||||
shift
|
||||
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=$?
|
||||
# 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
|
||||
@ -778,8 +781,6 @@ start_master()
|
||||
if [ x$MASTER_RUNNING = x1 ] || [ x$LOCAL_MASTER = x1 ] ; then
|
||||
return
|
||||
fi
|
||||
# Remove old berkeley db log files that can confuse the server
|
||||
$RM -f $MASTER_MYDDIR/log.*
|
||||
# Remove stale binary logs
|
||||
$RM -f $MYSQL_TEST_DIR/var/log/master-bin.*
|
||||
# Remove old master.info files
|
||||
@ -877,8 +878,8 @@ start_slave()
|
||||
[ x$SKIP_SLAVE = x1 ] && return
|
||||
eval "this_slave_running=\$SLAVE$1_RUNNING"
|
||||
[ x$this_slave_running = 1 ] && return
|
||||
#when testing fail-safe replication, we will have more than one slave
|
||||
#in this case, we start secondary slaves with an argument
|
||||
# When testing fail-safe replication, we will have more than one slave
|
||||
# in this case, we start secondary slaves with an argument
|
||||
slave_ident="slave$1"
|
||||
if [ -n "$1" ] ;
|
||||
then
|
||||
@ -986,9 +987,12 @@ EOF
|
||||
|
||||
mysql_start ()
|
||||
{
|
||||
$ECHO "Starting MySQL daemon"
|
||||
start_master
|
||||
start_slave
|
||||
# We should not start the deamon here as we don't know the argumens
|
||||
# for the test. Better to let the test start the deamon
|
||||
|
||||
# $ECHO "Starting MySQL daemon"
|
||||
# start_master
|
||||
# start_slave
|
||||
cd $MYSQL_TEST_DIR
|
||||
return 1
|
||||
}
|
||||
@ -1089,8 +1093,6 @@ run_testcase ()
|
||||
slave_init_script=$TESTDIR/$tname-slave.sh
|
||||
slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt
|
||||
echo $tname > $CURRENT_TEST
|
||||
echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
|
||||
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
|
||||
SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0`
|
||||
if [ $USE_MANAGER = 1 ] ; then
|
||||
many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0`
|
||||
@ -1127,13 +1129,17 @@ run_testcase ()
|
||||
then
|
||||
EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"`
|
||||
stop_master
|
||||
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
|
||||
start_master
|
||||
else
|
||||
if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] ;
|
||||
then
|
||||
EXTRA_MASTER_OPT=""
|
||||
stop_master
|
||||
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
|
||||
start_master
|
||||
else
|
||||
echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -1163,7 +1169,10 @@ run_testcase ()
|
||||
|
||||
if [ x$do_slave_restart = x1 ] ; then
|
||||
stop_slave
|
||||
echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
|
||||
start_slave
|
||||
else
|
||||
echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
|
||||
fi
|
||||
if [ x$many_slaves = x1 ]; then
|
||||
start_slave 1
|
||||
@ -1286,6 +1295,9 @@ then
|
||||
# Remove files that can cause problems
|
||||
$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_slave=$SLEEP_TIME_FOR_FIRST_SLAVE
|
||||
$ECHO "Installing Test Databases"
|
||||
|
@ -50,10 +50,10 @@ PRIMARY KEY (GROUP_ID,LANG_ID),
|
||||
KEY NAME (NAME));
|
||||
ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null;
|
||||
SHOW FULL COLUMNS FROM t1;
|
||||
Field Type Null Key Default Extra Privileges Comment
|
||||
GROUP_ID int(10) unsigned PRI 0 select,insert,update,references
|
||||
LANG_ID smallint(5) unsigned PRI 0 select,insert,update,references
|
||||
NAME char(80) character set latin1 MUL select,insert,update,references
|
||||
Field Type Collation Null Key Default Extra Privileges Comment
|
||||
GROUP_ID int(10) unsigned binary PRI 0 select,insert,update,references
|
||||
LANG_ID smallint(5) unsigned binary PRI 0 select,insert,update,references
|
||||
NAME char(80) latin1 MUL select,insert,update,references
|
||||
DROP TABLE t1;
|
||||
create table t1 (n int);
|
||||
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 t2 rename t1, add c char(10) comment "no comment";
|
||||
show columns from t1;
|
||||
Field Type Null Key Default Extra
|
||||
i int(10) unsigned PRI NULL auto_increment
|
||||
c char(10) character set latin1 YES NULL
|
||||
Field Type Collation Null Key Default Extra
|
||||
i int(10) unsigned binary PRI NULL auto_increment
|
||||
c char(10) latin1 YES NULL
|
||||
drop table t1;
|
||||
|
@ -1,5 +1,5 @@
|
||||
set SQL_LOG_BIN=0;
|
||||
drop table if exists t1;
|
||||
drop table if exists t1, t2, t3;
|
||||
create table t1(n int);
|
||||
backup table t1 to '../bogus';
|
||||
Table Op Msg_type Msg_text
|
||||
|
@ -797,7 +797,6 @@ select * from t1 where i=1 and j=2;
|
||||
i j
|
||||
1 2
|
||||
drop table t1;
|
||||
drop table if exists t1, t2, t3, t4, t5, t6, t7;
|
||||
create table t1
|
||||
(
|
||||
branch_id int auto_increment primary key,
|
||||
@ -806,7 +805,6 @@ branch_active int not null default 1,
|
||||
unique branch_name(branch_name),
|
||||
index branch_active(branch_active)
|
||||
) type=bdb;
|
||||
drop table if exists t2 ;
|
||||
create table t2
|
||||
(
|
||||
target_id int auto_increment primary key,
|
||||
@ -815,7 +813,6 @@ target_active int not null default 1,
|
||||
unique target_name(target_name),
|
||||
index target_active(target_active)
|
||||
) type=bdb;
|
||||
drop table if exists t3 ;
|
||||
create table t3
|
||||
(
|
||||
platform_id int auto_increment primary key,
|
||||
@ -824,7 +821,6 @@ platform_active int not null default 1,
|
||||
unique platform_name(platform_name),
|
||||
index platform_active(platform_active)
|
||||
) type=bdb;
|
||||
drop table if exists t4 ;
|
||||
create table t4
|
||||
(
|
||||
product_id int auto_increment primary key,
|
||||
@ -834,7 +830,6 @@ product_active int not null default 1,
|
||||
unique product_name(product_name),
|
||||
index product_active(product_active)
|
||||
) type=bdb;
|
||||
drop table if exists t5 ;
|
||||
create table t5
|
||||
(
|
||||
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),
|
||||
index file_included(file_included)
|
||||
) type=bdb;
|
||||
drop table if exists t6 ;
|
||||
create table t6
|
||||
(
|
||||
file_platform_id int auto_increment primary key,
|
||||
@ -860,7 +854,6 @@ build_filename varchar(255) not null,
|
||||
archive_filename varchar(255) not null,
|
||||
unique file_platform(product_file_id,platform_id,branch_id)
|
||||
) type=bdb;
|
||||
drop table if exists t8 ;
|
||||
create table t8
|
||||
(
|
||||
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),
|
||||
index status_id(status_id)
|
||||
) type=bdb;
|
||||
drop table if exists t7 ;
|
||||
create table t7
|
||||
(
|
||||
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;
|
||||
KINMU_DATE
|
||||
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;
|
||||
insert into t1 values (1,1), (1,2);
|
||||
select * from t1 where a = 1;
|
||||
|
@ -1,3 +1,4 @@
|
||||
drop table if exists t1;
|
||||
select 0,256,00000000000000065536,2147483647,-2147483648,2147483648,+4294967296;
|
||||
0 256 00000000000000065536 2147483647 -2147483648 2147483648 +4294967296
|
||||
0 256 65536 2147483647 -2147483648 2147483648 4294967296
|
||||
@ -7,7 +8,6 @@ select 9223372036854775807,-009223372036854775808;
|
||||
select +9999999999999999999,-9999999999999999999;
|
||||
+9999999999999999999 -9999999999999999999
|
||||
10000000000000000000 -10000000000000000000
|
||||
drop table if exists t1;
|
||||
create table t1 (a bigint unsigned not null, primary key(a));
|
||||
insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE);
|
||||
select * from t1;
|
||||
|
@ -46,10 +46,9 @@ SELECT @a, @b;
|
||||
@a @b
|
||||
0 6
|
||||
DROP TABLE t1;
|
||||
drop table if exists t;
|
||||
create table t(a int, b int);
|
||||
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 t;
|
||||
create table t1 (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);
|
||||
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;
|
||||
A B nA nB AB n(AB) nAonB AoB n(AoB) nAnB
|
||||
N N N N N N N 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
|
||||
1 0 0 1 0 1 1 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
|
||||
N N N N N N N 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
|
||||
1 0 0 1 0 1 1 1 0 0
|
||||
1 1 0 0 1 0 0 1 0 0
|
||||
drop table t;
|
||||
drop table t1;
|
||||
|
@ -63,3 +63,11 @@ nothing 2
|
||||
one 1
|
||||
two 1
|
||||
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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
drop table if exists t1,t2;
|
||||
drop table if exists t1,t2,t3;
|
||||
create table t1 (b char(0));
|
||||
insert into t1 values (""),(null);
|
||||
select * from t1;
|
||||
@ -13,12 +13,15 @@ select * from t1;
|
||||
b
|
||||
|
||||
|
||||
drop table if exists t1;
|
||||
drop table t1;
|
||||
create table t2 type=heap select * from t1;
|
||||
Table 'test.t1' doesn't exist
|
||||
create table t2 select auto+1 from t1;
|
||||
Table 'test.t1' doesn't exist
|
||||
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));
|
||||
The used table handler can't index column 'b'
|
||||
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);
|
||||
drop table t1;
|
||||
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.$test1 (a$1 int, $b int, c$ int);
|
||||
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 t2 select x from t1 where 1=2;
|
||||
describe t1;
|
||||
Field Type Null Key Default Extra
|
||||
x varchar(50) character set latin1 YES NULL
|
||||
Field Type Collation Null Key Default Extra
|
||||
x varchar(50) latin1 YES NULL
|
||||
describe t2;
|
||||
Field Type Null Key Default Extra
|
||||
x char(50) character set latin1 YES NULL
|
||||
Field Type Collation Null Key Default Extra
|
||||
x char(50) latin1 YES NULL
|
||||
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;
|
||||
describe t2;
|
||||
Field Type Null Key Default Extra
|
||||
a datetime 0000-00-00 00:00:00
|
||||
b time 00:00:00
|
||||
c date 0000-00-00
|
||||
d bigint(17) 0
|
||||
e double(18,1) 0.0
|
||||
f bigint(17) 0
|
||||
Field Type Collation Null Key Default Extra
|
||||
a datetime latin1 0000-00-00 00:00:00
|
||||
b time latin1 00:00:00
|
||||
c date latin1 0000-00-00
|
||||
d bigint(17) binary 0
|
||||
e double(18,1) binary 0.0
|
||||
f bigint(17) binary 0
|
||||
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;
|
||||
describe t2;
|
||||
Field Type Null Key Default Extra
|
||||
d date 0000-00-00
|
||||
t time 00:00:00
|
||||
dt datetime 0000-00-00 00:00:00
|
||||
Field Type Collation Null Key Default Extra
|
||||
d date latin1 0000-00-00
|
||||
t time latin1 00:00:00
|
||||
dt datetime latin1 0000-00-00 00:00:00
|
||||
drop table t1,t2;
|
||||
create table t1 (a tinyint);
|
||||
create table t2 (a int) select * from t1;
|
||||
describe t1;
|
||||
Field Type Null Key Default Extra
|
||||
a tinyint(4) YES NULL
|
||||
Field Type Collation Null Key Default Extra
|
||||
a tinyint(4) binary YES NULL
|
||||
describe t2;
|
||||
Field Type Null Key Default Extra
|
||||
a int(11) YES NULL
|
||||
Field Type Collation Null Key Default Extra
|
||||
a int(11) binary YES NULL
|
||||
drop table if exists t2;
|
||||
create table t2 (a int, a float) select * from t1;
|
||||
Duplicate column name 'a'
|
||||
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;
|
||||
Duplicate column name 'b'
|
||||
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;
|
||||
Duplicate column name 'b'
|
||||
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));
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
@ -161,3 +172,75 @@ drop table if exists t1;
|
||||
create table t1 (a int, key(a));
|
||||
create table t2 (b int, foreign key(b) references t1(a), key(b));
|
||||
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;
|
||||
|
@ -1,45 +1,45 @@
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (
|
||||
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;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`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
|
||||
ALTER TABLE t1 CHANGE comment comment CHAR(32) CHARACTER SET latin2 NOT NULL;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`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
|
||||
ALTER TABLE t1 ADD latin5_f CHAR(32) NOT NULL;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`comment` char(32) character set latin2 NOT NULL default '',
|
||||
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default '',
|
||||
`latin5_f` char(32) character set latin5 NOT NULL default ''
|
||||
`koi8_ru_f` char(32) character set koi8r NOT NULL default '',
|
||||
`latin5_f` char(32) NOT NULL default ''
|
||||
) TYPE=MyISAM CHARSET=latin5
|
||||
ALTER TABLE t1 CHARSET=latin2;
|
||||
ALTER TABLE t1 ADD latin2_f CHAR(32) NOT NULL;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`comment` char(32) character set latin2 NOT NULL default '',
|
||||
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default '',
|
||||
`comment` char(32) NOT NULL default '',
|
||||
`koi8_ru_f` char(32) character set koi8r 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
|
||||
ALTER TABLE t1 DROP latin2_f, DROP latin5_f;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`comment` char(32) character set latin2 NOT NULL default '',
|
||||
`koi8_ru_f` char(32) character set koi8_ru NOT NULL default ''
|
||||
`comment` char(32) NOT NULL default '',
|
||||
`koi8_ru_f` char(32) character set koi8r NOT NULL default ''
|
||||
) TYPE=MyISAM CHARSET=latin2
|
||||
INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A');
|
||||
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 YU <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;
|
||||
koi8_ru_f MIN(comment)
|
||||
a LAT CAPIT A
|
||||
@ -1056,7 +1061,7 @@ CYR SMALL YA CYR CAPIT YA
|
||||
CYR SMALL YA CYR SMALL YA
|
||||
SELECT t11.comment,t12.comment
|
||||
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;
|
||||
comment comment
|
||||
LAT CAPIT A LAT CAPIT A
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user