diff options
123 files changed, 6000 insertions, 1231 deletions
diff --git a/.bzrignore b/.bzrignore index 2c115322cc5..379f5401021 100644 --- a/.bzrignore +++ b/.bzrignore @@ -580,3 +580,4 @@ vio/test-sslclient vio/test-sslserver vio/viotest-ssl libmysqld/protocol.cc +test_xml diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index ad0fa4a4a36..e3da1e2292e 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -70,6 +70,7 @@ 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 diff --git a/Docs/gis.txt b/Docs/gis.txt new file mode 100644 index 00000000000..d80a200d5a6 --- /dev/null +++ b/Docs/gis.txt @@ -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. diff --git a/client/mysql.cc b/client/mysql.cc index 9ee441a7709..680175f2123 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1414,7 +1414,6 @@ static int com_server_help(String *buffer __attribute__((unused)), server_cmd= cmd_buf; } - char buff[16], time_buf[32]; MYSQL_RES *result; ulong timer; uint error= 0; diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 2de4a9b81b5..408a5873589 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -117,7 +117,7 @@ static struct my_option my_long_options[] = {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, - {"protocol", OPT_MYSQL_PROTOCOL,
"The protocol of connection (tcp,socket,pipe,memory)", + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory)", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replace", 'r', "If duplicate unique key was found, replace old row.", (gptr*) &replace, (gptr*) &replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/client/mysqlshow.c b/client/mysqlshow.c index df624a02c55..e6e21f177ef 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -179,7 +179,7 @@ static struct my_option my_long_options[] = {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"protocol", OPT_MYSQL_PROTOCOL,
"The protocol of connection (tcp,socket,pipe,memory)", + {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory)", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_SMEM {"shared_memory_base_name", OPT_SHARED_MEMORY_BASE_NAME, diff --git a/include/Makefile.am b/include/Makefile.am index c88e1ee1e40..652278e8a80 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 \ diff --git a/include/m_ctype.h b/include/m_ctype.h index 09a24201588..85397796e73 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -49,6 +49,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 +66,7 @@ typedef struct charset_info_st { uint number; uint state; + const char *csname; const char *name; const char *comment; uchar *ctype; @@ -127,6 +129,7 @@ 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); diff --git a/include/my_xml.h b/include/my_xml.h new file mode 100644 index 00000000000..0d968ab38c7 --- /dev/null +++ b/include/my_xml.h @@ -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 */ diff --git a/include/mysql.h b/include/mysql.h index f9b8c1ecbb3..a2b48c0c43d 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -509,7 +509,7 @@ MYSQL_RES *STDCALL mysql_prepare_result(MYSQL_STMT *stmt); #define MYSQL_STATUS_ERROR 2 #define MYSQL_NO_DATA 100 #define MYSQL_NEED_DATA 99 -#define MYSQL_LONG_DATA_END 0xFF +#define MYSQL_NULL_DATA (-1) #define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 81a24e89164..377f714bfff 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -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 diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index a2e6fddff0f..4d8b703fb2d 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -58,7 +58,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ mf_loadpath.lo my_pthread.lo my_thr_init.lo \ thr_mutex.lo mulalloc.lo string.lo default.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \ - charset.lo hash.lo mf_iocache.lo \ + charset.lo xml.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_getopt.lo my_gethostbyname.lo my_port.lo diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 8cf59281719..bb0059f8e25 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1760,7 +1760,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; } @@ -1770,10 +1770,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)); @@ -1787,8 +1787,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 @@ -3819,12 +3819,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; @@ -3832,9 +3833,9 @@ static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) DBUG_RETURN(1); 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; + stmt->stmt_id= uint4korr(pos); pos+=4; + field_count= uint2korr(pos); pos+=2; + param_count= uint2korr(pos); pos+=2; if (field_count != 0) { @@ -3857,9 +3858,10 @@ static my_bool read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) set_stmt_error(stmt, CR_OUT_OF_MEMORY); DBUG_RETURN(0); } - stmt->bind= (stmt->params + stmt->param_count); - stmt->field_count= (uint) field_count; - mysql->status= MYSQL_STATUS_READY; + stmt->bind= (stmt->params + stmt->param_count); + stmt->field_count= (uint) field_count; + stmt->param_count= (ulong) param_count; + stmt->mysql->status= MYSQL_STATUS_READY; DBUG_RETURN(0); } @@ -3903,13 +3905,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)); @@ -3927,11 +3929,15 @@ 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; @@ -4083,12 +4089,13 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) DBUG_ENTER("store_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->is_null || param->buffer_type == MYSQL_TYPE_NULL || + *param->length == MYSQL_NULL_DATA) store_param_null(net, param); else { - /* Allocate for worst case (long string) */ + /* Allocate for worst case (long string) */ if ((my_realloc_str(net, 9 + *param->length))) DBUG_RETURN(1); (*param->store_param_func)(net, param); @@ -4096,7 +4103,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 +4126,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); } @@ -4407,6 +4406,327 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, ****************************************************************************/ +static ulong get_field_length(uint type) +{ + ulong length; + + switch (type) { + + case MYSQL_TYPE_TINY: + length= 1; + break; + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_YEAR: + length= 2; + break; + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + length= 4; + break; + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_DOUBLE: + length= 8; + break; + default: + length= 0; + } + return length; +} + +static void send_data_long(MYSQL_BIND *param, longlong value) +{ + char *buffer= param->buffer; + + *param->length= get_field_length(param->buffer_type); + 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'; + } + } +} + +static void send_data_double(MYSQL_BIND *param, double value) +{ + char *buffer= param->buffer; + + *param->length= get_field_length(param->buffer_type); + 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'; + } + } +} + +static void send_data_str(MYSQL_BIND *param, char *value, uint src_length) +{ + char *buffer= param->buffer; + + *param->length= get_field_length(param->buffer_type); + switch(param->buffer_type) { + + case MYSQL_TYPE_TINY: + *buffer= (char)*value; + break; + case MYSQL_TYPE_SHORT: + { + short data= (short)sint2korr(value); + int2store(buffer, data); + break; + } + case MYSQL_TYPE_LONG: + { + int32 data= (int32)sint4korr(value); + int4store(buffer, data); + break; + } + case MYSQL_TYPE_LONGLONG: + { + longlong data= sint8korr(value); + int8store(buffer, data); + break; + } + case MYSQL_TYPE_FLOAT: + { + float data; + float4get(data, value); + float4store(buffer, data); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double data; + float8get(data, value); + float8store(buffer, data); + break; + } + default: + *param->length= src_length; + memcpy(buffer, value, src_length); + buffer[src_length]='\0'; + } +} + +static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, + uint field_type, uchar **row) +{ + ulong length; + + length= get_field_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) { *param->buffer= (uchar) **row; @@ -4415,31 +4735,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 +4767,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; } /* @@ -4511,9 +4832,10 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) 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->bind_length= 0; param->fetch_result= fetch_result_str; break; default: @@ -4532,41 +4854,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; - - row+= (stmt->field_count+9)/8; - bit= 4; /* First 2 bits are reserved */ - + MYSQL_FIELD *field, *field_end; + uchar *null_ptr, bit; + + 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 +4911,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) + if (!(res= read_binary_data(mysql))) { - 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)); - 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(MYSQL_NO_DATA); /* no more data */ + if (stmt->res_buffers) + stmt_fetch_row(stmt, mysql->net.read_pos+1); + DBUG_RETURN(0); + } + 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(0); //?? do we need to set MYSQL_STATUS_READY ? + DBUG_PRINT("info", ("end of data")); + DBUG_RETURN(MYSQL_NO_DATA); /* no more data */ } diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 0be0d624fca..6bfda427f78 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -161,3 +161,74 @@ 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; +drop table if exists t1, t2, t3; +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) character set latin1 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) character set latin1 default NULL +) TYPE=MyISAM CHARSET=latin1 +select * from t3; +id name +drop table t2, t3; +drop database if exists test_$1; +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) character set latin1 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) character set latin1 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; diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 6a3aa328175..e2d2b1cb652 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -130,3 +130,9 @@ SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b; select * from (select 1 as a) b left join (select 2 as a) c using(a); a a 1 NULL +SELECT * FROM (SELECT 1 UNION SELECT a) b; +Unknown column 'a' in 'field list' +SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; +Unknown column 'a' in 'field list' +SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; +Unknown column 'a' in 'field list' diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index ad3a64ccd1d..461ae1e7e09 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -1,6 +1,15 @@ select length(encrypt('foo', 'ff')) <> 0; length(encrypt('foo', 'ff')) <> 0 1 -select old_password('test'),length(password("1")),length(encrypt('test')),encrypt('test','aa'); +select password("a",""), password("a",NULL), password("","a"), password(NULL,"a"); +password("a","") password("a",NULL) password("","a") password(NULL,"a") +*2517f7235d68d4ba2e5019c93420523101157a792c01 NULL NULL +select password("aaaaaaaaaaaaaaaa","a"), password("a","aaaaaaaaaaaaaaaa"); +password("aaaaaaaaaaaaaaaa","a") password("a","aaaaaaaaaaaaaaaa") +*2cd3b9a44e9a9994789a30f935c92f45a96c5472f381 *37c7c5c794ff144819f2531bf03c57772cd84e40db09 +select old_password('test'), length(password("1")), length(encrypt('test')), encrypt('test','aa'); old_password('test') length(password("1")) length(encrypt('test')) encrypt('test','aa') 378b243e220ca493 45 13 aaqPiZY5xR5l. +select old_password(""), old_password(NULL), password(""), password(NULL); +old_password("") old_password(NULL) password("") password(NULL) + NULL NULL diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index d0358aad6ba..429574575f1 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -170,6 +170,9 @@ quote(concat('abc\'', '\\cba')) select quote(1/0), quote('\0\Z'); quote(1/0) quote('\0\Z') NULL '\0\Z' +select length(quote(concat(char(0), "test"))); +length(quote(concat(char(0), "test"))) +8 select reverse(""); reverse("") diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index fe028a4cb95..b037fc87996 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -235,6 +235,21 @@ select * from t2; n d 1 30 1 30 +UPDATE t1 a ,t2 b SET a.d=b.d,b.d=30 WHERE a.n=b.n; +select * from t1; +n d +1 30 +3 2 +select * from t2; +n d +1 30 +1 30 +DELETE t1, t2 FROM t1 a,t2 b where a.n=b.n; +select * from t1; +n d +3 2 +select * from t2; +n d drop table t1,t2; drop table if exists t1,t2,t3; CREATE TABLE t1 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) TYPE=MyISAM; diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index a37313a150a..ad9294e6d3a 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -531,6 +531,7 @@ i show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 2 +update t1 set i=(select distinct 1 from (select * from t2) a); drop table t1, t2, t3; use mysql; select * from db; diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result new file mode 100644 index 00000000000..a628936b600 --- /dev/null +++ b/mysql-test/r/rpl_temporary.result @@ -0,0 +1,74 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop table if exists t1; +create table t1(f int); +drop table if exists t2; +create table t2(f int); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +create temporary table t3(f int); +insert into t3 select * from t1 where f<6; +create temporary table t3(f int); +insert into t2 select count(*) from t3; +insert into t3 select * from t1 where f>=4; +drop temporary table t3; +insert into t2 select count(*) from t3; +drop temporary table t3; +select * from t2; +f +5 +7 +show binlog events; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.000001 4 Start 1 4 Server ver: 4.1.0-alpha-debug-log, Binlog ver: 3 +master-bin.000001 79 Query 1 79 use `test`; create table t1(f int) +master-bin.000001 136 Query 1 136 use `test`; create table t2(f int) +master-bin.000001 193 Query 1 193 use `test`; insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10) +master-bin.000001 290 Query 1 290 use `test`; create temporary table t3(f int) +master-bin.000001 357 Query 1 357 use `test`; insert into t3 select * from t1 where f<6 +master-bin.000001 433 Query 1 433 use `test`; create temporary table t3(f int) +master-bin.000001 500 Query 1 500 use `test`; insert into t2 select count(*) from t3 +master-bin.000001 573 Query 1 573 use `test`; insert into t3 select * from t1 where f>=4 +master-bin.000001 650 Query 1 650 use `test`; drop temporary table t3 +master-bin.000001 708 Query 1 708 use `test`; insert into t2 select count(*) from t3 +master-bin.000001 781 Query 1 781 use `test`; drop temporary table t3 +drop table if exists t1; +drop table if exists t2; +use test; +SET TIMESTAMP=1040323920; +create table t1(f int); +SET TIMESTAMP=1040323931; +create table t2(f int); +SET TIMESTAMP=1040323938; +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +SET TIMESTAMP=1040323945; +SET @@session.pseudo_thread_id=1; +create temporary table t3(f int); +SET TIMESTAMP=1040323952; +SET @@session.pseudo_thread_id=1; +insert into t3 select * from t1 where f<6; +SET TIMESTAMP=1040324145; +SET @@session.pseudo_thread_id=2; +create temporary table t3(f int); +SET TIMESTAMP=1040324186; +SET @@session.pseudo_thread_id=1; +insert into t2 select count(*) from t3; +SET TIMESTAMP=1040324200; +SET @@session.pseudo_thread_id=2; +insert into t3 select * from t1 where f>=4; +SET TIMESTAMP=1040324211; +SET @@session.pseudo_thread_id=1; +drop temporary table t3; +SET TIMESTAMP=1040324219; +SET @@session.pseudo_thread_id=2; +insert into t2 select count(*) from t3; +SET TIMESTAMP=1040324224; +SET @@session.pseudo_thread_id=2; +drop temporary table t3; +select * from t2; +f +5 +7 diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f12e0396694..38a8e0368c6 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1,13 +1,32 @@ select (select 2); (select 2) 2 +explain select (select 2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1247 Select 2 was reduced during optimisation SELECT (SELECT 1) UNION SELECT (SELECT 2); (SELECT 1) 1 2 +explain SELECT (SELECT 1) UNION SELECT (SELECT 2); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1247 Select 2 was reduced during optimisation +Note 1247 Select 4 was reduced during optimisation SELECT (SELECT (SELECT 0 UNION SELECT 0)); (SELECT (SELECT 0 UNION SELECT 0)) 0 +explain SELECT (SELECT (SELECT 0 UNION SELECT 0)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used +3 SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used +4 UNION NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1247 Select 2 was reduced during optimisation SELECT (SELECT 1 FROM (SELECT 1) as b HAVING a=1) as a; Reference 'a' not supported (forward reference in item list) SELECT (SELECT 1 FROM (SELECT 1) as b HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) as c HAVING a=1) as b; @@ -52,6 +71,54 @@ a SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; a 1 +SELECT (SELECT 1,2,3) = ROW(1,2,3); +(SELECT 1,2,3) = ROW(1,2,3) +1 +SELECT (SELECT 1,2,3) = ROW(1,2,1); +(SELECT 1,2,3) = ROW(1,2,1) +0 +SELECT (SELECT 1,2,3) < ROW(1,2,1); +(SELECT 1,2,3) < ROW(1,2,1) +0 +SELECT (SELECT 1,2,3) > ROW(1,2,1); +(SELECT 1,2,3) > ROW(1,2,1) +1 +SELECT (SELECT 1,2,3) = ROW(1,2,NULL); +(SELECT 1,2,3) = ROW(1,2,NULL) +NULL +SELECT ROW(1,2,3) = (SELECT 1,2,3); +ROW(1,2,3) = (SELECT 1,2,3) +1 +SELECT ROW(1,2,3) = (SELECT 1,2,1); +ROW(1,2,3) = (SELECT 1,2,1) +0 +SELECT ROW(1,2,3) < (SELECT 1,2,1); +ROW(1,2,3) < (SELECT 1,2,1) +0 +SELECT ROW(1,2,3) > (SELECT 1,2,1); +ROW(1,2,3) > (SELECT 1,2,1) +1 +SELECT ROW(1,2,3) = (SELECT 1,2,NULL); +ROW(1,2,3) = (SELECT 1,2,NULL) +NULL +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a'); +(SELECT 1.5,2,'a') = ROW(1.5,2,'a') +1 +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b'); +(SELECT 1.5,2,'a') = ROW(1.5,2,'b') +0 +SELECT (SELECT 1.5,2,'a') = ROW('b',2,'b'); +(SELECT 1.5,2,'a') = ROW('b',2,'b') +0 +SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a'); +(SELECT 'b',2,'a') = ROW(1.5,2,'a') +0 +SELECT (SELECT 1.5,2,'a') = ROW(1.5,'c','a'); +(SELECT 1.5,2,'a') = ROW(1.5,'c','a') +0 +SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a'); +(SELECT 1.5,'c','a') = ROW(1.5,2,'a') +0 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8; create table t1 (a int); create table t2 (a int, b int); @@ -86,20 +153,20 @@ select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1); a b 1 7 2 7 -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 order by a limit 2) limit 3; a b 1 7 2 7 3 8 -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); a b 1 7 2 7 3 8 4 8 -explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) +explain (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where @@ -581,12 +648,13 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t ref id id 5 const 1 Using where; Using index 3 SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: +Note 1247 Select 3 was reduced during optimisation Note 1247 Select 2 was reduced during optimisation EXPLAIN SELECT * FROM t WHERE id IN (SELECT 1 UNION SELECT 3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t index NULL id 5 NULL 2 Using where; Using index 2 DEPENDENT SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used -3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used +3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used SELECT * FROM t WHERE id IN (SELECT 5 UNION SELECT 3); id SELECT * FROM t WHERE id IN (SELECT 5 UNION SELECT 2); @@ -602,7 +670,7 @@ CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin INSERT INTO t1 values (1),(1); UPDATE t SET id=(SELECT * FROM t1); Subselect returns more than 1 record -drop table t; +drop table t, t1; create table t (a int); insert into t values (1),(2),(3); select 1 IN (SELECT * from t); @@ -704,6 +772,16 @@ NULL select 10.5 > ANY (SELECT * from t); 10.5 > ANY (SELECT * from t) 1 +explain select (select a+1) from t; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t ALL NULL NULL NULL NULL 3 +Warnings: +Note 1247 Select 2 was reduced during optimisation +select (select a+1) from t; +(select a+1) +2.5 +NULL +4.5 drop table t; create table t (a float); select 10.5 IN (SELECT * from t LIMIT 1); @@ -711,3 +789,65 @@ This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' select 10.5 IN (SELECT * from t LIMIT 1 UNION SELECT 1.5); This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' drop table t; +create table t1 (a int, b int, c varchar(10)); +create table t2 (a int); +insert into t1 values (1,2,'a'),(2,3,'b'),(3,4,'c'); +insert into t2 values (1),(2),(NULL); +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t1 where a=t2.a) from t2; +a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a') (select c from t1 where a=t2.a) +1 1 a +2 0 b +NULL NULL NULL +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2; +a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b') (select c from t1 where a=t2.a) +1 0 a +2 1 b +NULL NULL NULL +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t1 where a=t2.a) from t2; +a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c') (select c from t1 where a=t2.a) +1 0 a +2 0 b +NULL NULL NULL +drop table t1,t2; +drop table if exists t; +create table t (a int, b real, c varchar(10)); +insert into t values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b'); +select ROW(1, 1, 'a') IN (select a,b,c from t); +ROW(1, 1, 'a') IN (select a,b,c from t) +1 +select ROW(1, 2, 'a') IN (select a,b,c from t); +ROW(1, 2, 'a') IN (select a,b,c from t) +NULL +select ROW(1, 1, 'a') IN (select b,a,c from t); +ROW(1, 1, 'a') IN (select b,a,c from t) +1 +select ROW(1, 1, 'a') IN (select a,b,c from t where a is not null); +ROW(1, 1, 'a') IN (select a,b,c from t where a is not null) +1 +select ROW(1, 2, 'a') IN (select a,b,c from t where a is not null); +ROW(1, 2, 'a') IN (select a,b,c from t where a is not null) +0 +select ROW(1, 1, 'a') IN (select b,a,c from t where a is not null); +ROW(1, 1, 'a') IN (select b,a,c from t where a is not null) +1 +select ROW(1, 1, 'a') IN (select a,b,c from t where c='b' or c='a'); +ROW(1, 1, 'a') IN (select a,b,c from t where c='b' or c='a') +1 +select ROW(1, 2, 'a') IN (select a,b,c from t where c='b' or c='a'); +ROW(1, 2, 'a') IN (select a,b,c from t where c='b' or c='a') +NULL +select ROW(1, 1, 'a') IN (select b,a,c from t where c='b' or c='a'); +ROW(1, 1, 'a') IN (select b,a,c from t where c='b' or c='a') +1 +select ROW(1, 1, 'a') IN (select b,a,c from t limit 2); +This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +drop table t; +create table t (a int); +insert into t values (1); +do @a:=(SELECT a from t); +select @a; +@a +1 +drop table t; +do (SELECT a from t); +Table 'test.t' doesn't exist diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index ba5c1c6e28f..60c975b540e 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -106,9 +106,12 @@ create table t1 (a int not null, b int not null); insert into t1 values (1,1),(1,2),(1,3); update t1 set b=4 where a=1 order by b asc limit 1; update t1 set b=4 where a=1 order by b desc limit 1; +create table t2 (a int not null, b int not null); +insert into t2 values (1,1),(1,2),(1,3); select * from t1; a b 1 4 1 2 1 4 -drop table t1; +update t1 set b=(select distinct 1 from (select * from t2) a); +drop table t1,t2; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 3bad053875c..e057ffaebb0 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -113,3 +113,44 @@ 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; + +# +# Test for CREATE TABLE .. LIKE .. +# + +drop table if exists t1, t2, t3; +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; +select * from t3; +create table if not exists t3 like t1; +select @@warning_count; +create temporary table t3 like t2; +show create table t3; +select * from t3; +drop table t3; +show create table t3; +select * from t3; +drop table t2, t3; +drop database if exists test_$1; +create database test_$1; +create table test_$1.t3 like t1; +create temporary table t3 like test_$1.t3; +show create table t3; +create table t2 like t3; +show create table t2; +select * from t2; +create table t3 like t1; +!$1050 create table t3 like test_$1.t3; +--error 1044,1 +create table non_existing_database.t1 like t1; +!$1051 create table t3 like non_existing_table; +!$1050 create temporary table t3 like t1; +!$1103 create table t3 like `a/a`; +drop table t1, t2, t3; +drop table t3; +drop database test_$1; + diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 0c366b65797..8767f9209b3 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -48,3 +48,9 @@ explain select count(*) from t1 as tt1, (select * from t1) as tt2; drop table if exists t1; SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b; select * from (select 1 as a) b left join (select 2 as a) c using(a); +--error 1054 +SELECT * FROM (SELECT 1 UNION SELECT a) b; +--error 1054 +SELECT 1 as a FROM (SELECT a UNION SELECT 1) b; +--error 1054 +SELECT 1 as a FROM (SELECT 1 UNION SELECT a) b; diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index 812bdade39f..af0ef661d06 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -1,3 +1,8 @@ select length(encrypt('foo', 'ff')) <> 0; --replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. -select old_password('test'),length(password("1")),length(encrypt('test')),encrypt('test','aa'); + +# Test new and old password handling functions +select password("a",""), password("a",NULL), password("","a"), password(NULL,"a"); +select password("aaaaaaaaaaaaaaaa","a"), password("a","aaaaaaaaaaaaaaaa"); +select old_password('test'), length(password("1")), length(encrypt('test')), encrypt('test','aa'); +select old_password(""), old_password(NULL), password(""), password(NULL); diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index d355cc95317..97b771e7363 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -69,7 +69,7 @@ select decode(encode("abcdef","monty"),"monty")="abcdef"; select quote('\'\"\\test'); select quote(concat('abc\'', '\\cba')); select quote(1/0), quote('\0\Z'); - +select length(quote(concat(char(0), "test"))); # # Wrong usage of functions # diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 088b355a17c..29239a022ec 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -213,6 +213,12 @@ insert into t2 values(1,10),(1,20); UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; select * from t1; select * from t2; +UPDATE t1 a ,t2 b SET a.d=b.d,b.d=30 WHERE a.n=b.n; +select * from t1; +select * from t2; +DELETE t1, t2 FROM t1 a,t2 b where a.n=b.n; +select * from t1; +select * from t2; drop table t1,t2; drop table if exists t1,t2,t3; CREATE TABLE t1 ( broj int(4) unsigned NOT NULL default '0', naziv char(25) NOT NULL default 'NEPOZNAT', PRIMARY KEY (broj)) TYPE=MyISAM; diff --git a/mysql-test/t/outfile.test b/mysql-test/t/outfile.test index c126d221bd2..a944df01051 100644 --- a/mysql-test/t/outfile.test +++ b/mysql-test/t/outfile.test @@ -21,3 +21,8 @@ #select * into dumpfile "/tmp/select-test.99" from t1; #select load_file("/tmp/select-test.not-exist"); #drop table t1; +#drop table if exists t; +#CREATE TABLE t ( t timestamp NOT NULL, c char(200) character set latin1 NOT NULL default '', i int(11), v varchar(200), b blob, KEY t (t)) TYPE=MyISAM; +#INSERT INTO t VALUES ('2002-12-20 12:01:20','',1,"aaa","bbb"); +#select * from t into outfile "check"; +#drop table if exists t; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 6c3f3d6ac52..eeaf1a83d1a 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -368,6 +368,7 @@ select * from t2; show status like "Qcache_queries_in_cache"; select * from t3; show status like "Qcache_queries_in_cache"; +update t1 set i=(select distinct 1 from (select * from t2) a); drop table t1, t2, t3; # diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test new file mode 100644 index 00000000000..1cb53c77f1f --- /dev/null +++ b/mysql-test/t/rpl_temporary.test @@ -0,0 +1,77 @@ +source include/master-slave.inc; + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +drop table if exists t1; +create table t1(f int); +drop table if exists t2; +create table t2(f int); +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); + +connection con1; +create temporary table t3(f int); +insert into t3 select * from t1 where f<6; +sleep 1; + +connection con2; +create temporary table t3(f int); +sleep 1; + +connection con1; +insert into t2 select count(*) from t3; +sleep 1; + +connection con2; +insert into t3 select * from t1 where f>=4; +sleep 1; + +connection con1; +drop temporary table t3; +sleep 1; + +connection con2; +insert into t2 select count(*) from t3; +drop temporary table t3; + +select * from t2; + +show binlog events; + +drop table if exists t1; +drop table if exists t2; + +use test; +SET TIMESTAMP=1040323920; +create table t1(f int); +SET TIMESTAMP=1040323931; +create table t2(f int); +SET TIMESTAMP=1040323938; +insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); + +SET TIMESTAMP=1040323945; +SET @@session.pseudo_thread_id=1; +create temporary table t3(f int); +SET TIMESTAMP=1040323952; +SET @@session.pseudo_thread_id=1; +insert into t3 select * from t1 where f<6; +SET TIMESTAMP=1040324145; +SET @@session.pseudo_thread_id=2; +create temporary table t3(f int); +SET TIMESTAMP=1040324186; +SET @@session.pseudo_thread_id=1; +insert into t2 select count(*) from t3; +SET TIMESTAMP=1040324200; +SET @@session.pseudo_thread_id=2; +insert into t3 select * from t1 where f>=4; +SET TIMESTAMP=1040324211; +SET @@session.pseudo_thread_id=1; +drop temporary table t3; +SET TIMESTAMP=1040324219; +SET @@session.pseudo_thread_id=2; +insert into t2 select count(*) from t3; +SET TIMESTAMP=1040324224; +SET @@session.pseudo_thread_id=2; +drop temporary table t3; + +select * from t2;
\ No newline at end of file diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 347d6276280..de07df1905b 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1,6 +1,9 @@ select (select 2); +explain select (select 2); SELECT (SELECT 1) UNION SELECT (SELECT 2); +explain SELECT (SELECT 1) UNION SELECT (SELECT 2); SELECT (SELECT (SELECT 0 UNION SELECT 0)); +explain SELECT (SELECT (SELECT 0 UNION SELECT 0)); -- error 1245 SELECT (SELECT 1 FROM (SELECT 1) as b HAVING a=1) as a; -- error 1245 @@ -26,6 +29,22 @@ select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; +SELECT (SELECT 1,2,3) = ROW(1,2,3); +SELECT (SELECT 1,2,3) = ROW(1,2,1); +SELECT (SELECT 1,2,3) < ROW(1,2,1); +SELECT (SELECT 1,2,3) > ROW(1,2,1); +SELECT (SELECT 1,2,3) = ROW(1,2,NULL); +SELECT ROW(1,2,3) = (SELECT 1,2,3); +SELECT ROW(1,2,3) = (SELECT 1,2,1); +SELECT ROW(1,2,3) < (SELECT 1,2,1); +SELECT ROW(1,2,3) > (SELECT 1,2,1); +SELECT ROW(1,2,3) = (SELECT 1,2,NULL); +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a'); +SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b'); +SELECT (SELECT 1.5,2,'a') = ROW('b',2,'b'); +SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a'); +SELECT (SELECT 1.5,2,'a') = ROW(1.5,'c','a'); +SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a'); drop table if exists t1,t2,t3,t4,t5,t6,t7,t8; create table t1 (a int); @@ -44,11 +63,11 @@ select (select a from t3), a from t2; select * from t2 where t2.a=(select a from t1); insert into t3 values (6),(7),(3); select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1); -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 order by a limit 2) limit 3; -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) +(select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); -explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) +explain (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2; select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from @@ -363,7 +382,7 @@ CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin INSERT INTO t1 values (1),(1); -- error 1240 UPDATE t SET id=(SELECT * FROM t1); -drop table t; +drop table t, t1; #NULL test @@ -408,6 +427,8 @@ select 1.5 > ALL (SELECT * from t); select 10.5 > ALL (SELECT * from t); select 1.5 > ANY (SELECT * from t); select 10.5 > ANY (SELECT * from t); +explain select (select a+1) from t; +select (select a+1) from t; drop table t; #LIMIT is not supported now @@ -416,4 +437,37 @@ create table t (a float); select 10.5 IN (SELECT * from t LIMIT 1); -- error 1235 select 10.5 IN (SELECT * from t LIMIT 1 UNION SELECT 1.5); -drop table t;
\ No newline at end of file +drop table t; + +create table t1 (a int, b int, c varchar(10)); +create table t2 (a int); +insert into t1 values (1,2,'a'),(2,3,'b'),(3,4,'c'); +insert into t2 values (1),(2),(NULL); +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t1 where a=t2.a) from t2; +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2; +select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t1 where a=t2.a) from t2; +drop table t1,t2; + +drop table if exists t; +create table t (a int, b real, c varchar(10)); +insert into t values (1, 1, 'a'), (2,2,'b'), (NULL, 2, 'b'); +select ROW(1, 1, 'a') IN (select a,b,c from t); +select ROW(1, 2, 'a') IN (select a,b,c from t); +select ROW(1, 1, 'a') IN (select b,a,c from t); +select ROW(1, 1, 'a') IN (select a,b,c from t where a is not null); +select ROW(1, 2, 'a') IN (select a,b,c from t where a is not null); +select ROW(1, 1, 'a') IN (select b,a,c from t where a is not null); +select ROW(1, 1, 'a') IN (select a,b,c from t where c='b' or c='a'); +select ROW(1, 2, 'a') IN (select a,b,c from t where c='b' or c='a'); +select ROW(1, 1, 'a') IN (select b,a,c from t where c='b' or c='a'); +-- error 1235 +select ROW(1, 1, 'a') IN (select b,a,c from t limit 2); +drop table t; + +create table t (a int); +insert into t values (1); +do @a:=(SELECT a from t); +select @a; +drop table t; +-- error 1146 +do (SELECT a from t); diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 5cbbd2a350e..24620982cda 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -85,5 +85,8 @@ create table t1 (a int not null, b int not null); insert into t1 values (1,1),(1,2),(1,3); update t1 set b=4 where a=1 order by b asc limit 1; update t1 set b=4 where a=1 order by b desc limit 1; +create table t2 (a int not null, b int not null); +insert into t2 values (1,1),(1,2),(1,3); select * from t1; -drop table t1; +update t1 set b=(select distinct 1 from (select * from t2) a); +drop table t1,t2; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index b6f00daa5cc..c8b7987a506 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -50,7 +50,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ my_getopt.c my_mkdir.c \ default.c my_compress.c checksum.c raid.cc \ my_net.c my_semaphore.c my_port.c \ - my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.c \ + my_vsnprintf.c charset.c xml.c my_bitmap.c my_bit.c md5.c \ my_gethostbyname.c rijndael.c my_aes.c sha1.c \ my_handler.c EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ @@ -103,6 +103,9 @@ test_dir: test_dir.c $(LIBRARIES) test_charset$(EXEEXT): test_charset.c $(LIBRARIES) $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_charset.c $(LDADD) $(LIBS) +test_xml$(EXEEXT): test_xml.c $(LIBRARIES) + $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_xml.c $(LDADD) $(LIBS) + charset2html$(EXEEXT): charset2html.c $(LIBRARIES) $(LINK) $(FLAGS) -DMAIN $(srcdir)/charset2html.c $(LDADD) $(LIBS) diff --git a/mysys/charset.c b/mysys/charset.c index cf0628495fc..f590ee2a49e 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -19,7 +19,9 @@ #include <m_ctype.h> #include <m_string.h> #include <my_dir.h> +#include <my_xml.h> +#define MY_CHARSET_INDEX "Index.xml" const char *charsets_dir = NULL; static int charset_initialized=0; @@ -85,53 +87,185 @@ char *get_charsets_dir(char *buf) } -static my_bool read_charset_index(myf myflags) +#define MAX_BUF 1024*16 + + +static void mstr(char *str,const char *src,uint l1,uint l2) { - struct simpleconfig_buf_st fb; - char buf[MAX_LINE], num_buf[MAX_LINE]; - - strmov(get_charsets_dir(buf), "Index"); + l1 = l1<l2 ? l1 : l2; + memcpy(str,src,l1); + str[l1]='\0'; +} - if ((fb.f = my_fopen(buf, O_RDONLY, myflags)) == NULL) - return TRUE; - fb.buf[0] = '\0'; - fb.p = fb.buf; +struct my_cs_file_section_st +{ + int state; + const char *str; +}; + +#define _CS_MISC 1 +#define _CS_ID 2 +#define _CS_NAME 3 +#define _CS_FAMILY 4 +#define _CS_ORDER 5 +#define _CS_COLNAME 6 +#define _CS_FLAG 7 +#define _CS_CHARSET 8 +#define _CS_COLLATION 9 + +static struct my_cs_file_section_st sec[] = +{ + {_CS_MISC, "xml"}, + {_CS_MISC, "xml.version"}, + {_CS_MISC, "xml.encoding"}, + {_CS_MISC, "charsets"}, + {_CS_MISC, "charsets.max-id"}, + {_CS_MISC, "charsets.description"}, + {_CS_CHARSET, "charsets.charset"}, + {_CS_NAME, "charsets.charset.name"}, + {_CS_FAMILY, "charsets.charset.family"}, + {_CS_MISC, "charsets.charset.alias"}, + {_CS_COLLATION, "charsets.charset.collation"}, + {_CS_COLNAME, "charsets.charset.collation.name"}, + {_CS_ID, "charsets.charset.collation.id"}, + {_CS_ORDER, "charsets.charset.collation.order"}, + {_CS_FLAG, "charsets.charset.collation.flag"}, + {0, NULL} +}; + +static struct my_cs_file_section_st * cs_file_sec(const char *attr, uint len) +{ + struct my_cs_file_section_st *s; + for (s=sec; s->str; s++) + if (!strncmp(attr,s->str,len)) + return s; + return NULL; +} + +struct my_cs_file_info +{ + CHARSET_INFO cs; + myf myflags; +}; + +static int cs_enter(MY_XML_PARSER *st,const char *attr, uint len) +{ + struct my_cs_file_info *i = (struct my_cs_file_info *)st->user_data; + struct my_cs_file_section_st *s = cs_file_sec(attr,len); - while (!get_word(&fb, buf) && !get_word(&fb, num_buf)) + if ( s && (s->state == _CS_CHARSET)) { - uint csnum; - uint length; - CHARSET_INFO *cs; + bzero(&i->cs,sizeof(i->cs)); + } + return MY_XML_OK; +} - if (!(csnum = atoi(num_buf))) - { - /* corrupt Index file */ - my_fclose(fb.f,myflags); - return TRUE; - } - - if (all_charsets[csnum]) - continue; - - if (!(cs=(CHARSET_INFO*) my_once_alloc(sizeof(cs[0]),myflags))) +static int cs_leave(MY_XML_PARSER *st,const char *attr, uint len) +{ + struct my_cs_file_info *i = (struct my_cs_file_info *)st->user_data; + struct my_cs_file_section_st *s = cs_file_sec(attr,len); + int state = s ? s->state : 0; + + if (state == _CS_COLLATION) + { + if (!all_charsets[i->cs.number]) { - my_fclose(fb.f,myflags); - return TRUE; + if (!(all_charsets[i->cs.number]= + (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),i->myflags))) + { + return MY_XML_ERROR; + } + all_charsets[i->cs.number][0]=i->cs; } - bzero(cs,sizeof(cs[0])); - - if (!(cs->name= (char*)my_once_alloc(length=(uint)strlen(buf)+1,myflags))) + else { - my_fclose(fb.f,myflags); - return TRUE; + all_charsets[i->cs.number]->state |= i->cs.state; } - memcpy((char*)cs->name,buf,length); - cs->number=csnum; - all_charsets[csnum]=cs; + i->cs.state=0; } - my_fclose(fb.f,myflags); + return MY_XML_OK; +} + +static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) +{ + struct my_cs_file_info *i = (struct my_cs_file_info *)st->user_data; + struct my_cs_file_section_st *s; + int state = (s=cs_file_sec(st->attr,strlen(st->attr))) ? s->state : 0; + + if(0) + { + char str[256]; + mstr(str,attr,len,sizeof(str)-1); + printf("VALUE %d %s='%s'\n",state,st->attr,str); + } + + switch (state) + { + case _CS_ID: + i->cs.number = my_strntoul(my_charset_latin1,attr,len,(char**)NULL,0); + break; + case _CS_COLNAME: + if ((i->cs.name = (char*) my_once_alloc(len+1,i->myflags))) + { + memcpy((char*)i->cs.name,attr,len); + ((char*)(i->cs.name))[len]='\0'; + } + break; + case _CS_NAME: + if ((i->cs.csname = (char*) my_once_alloc(len+1,i->myflags))) + { + memcpy((char*)i->cs.csname,attr,len); + ((char*)(i->cs.csname))[len]='\0'; + } + break; + case _CS_FLAG: + if (!strncmp("primary",attr,len)) + i->cs.state |= MY_CS_PRIMARY; + } + return MY_XML_OK; +} +static my_bool read_charset_index(const char *filename, myf myflags) +{ + char *buf; + int fd; + uint len; + MY_XML_PARSER p; + struct my_cs_file_info i; + + if (! (buf = (char *)my_malloc(MAX_BUF,myflags))) + return FALSE; + + strmov(get_charsets_dir(buf),filename); + + if ((fd=my_open(buf,O_RDONLY,myflags)) < 0) + { + my_free(buf,myflags); + return TRUE; + } + + len=read(fd,buf,MAX_BUF); + my_xml_parser_create(&p); + my_close(fd,myflags); + + my_xml_set_enter_handler(&p,cs_enter); + my_xml_set_value_handler(&p,cs_value); + my_xml_set_leave_handler(&p,cs_leave); + my_xml_set_user_data(&p,(void*)&i); + + if (MY_XML_OK!=my_xml_parse(&p,buf,len)) + { + /* + printf("ERROR at line %d pos %d '%s'\n", + my_xml_error_lineno(&p)+1, + my_xml_error_pos(&p), + my_xml_error_string(&p)); + */ + } + + my_xml_parser_free(&p); + return FALSE; } @@ -179,7 +313,7 @@ static my_bool init_available_charsets(myf myflags) if (*cs) set_max_sort_char(*cs); } - error = read_charset_index(myflags); + error = read_charset_index(MY_CHARSET_INDEX,myflags); charset_initialized=1; pthread_mutex_unlock(&THR_LOCK_charset); } @@ -472,7 +606,7 @@ CHARSET_INFO *get_charset(uint cs_number, myf flags) if (!cs && (flags & MY_WME)) { char index_file[FN_REFLEN], cs_string[23]; - strmov(get_charsets_dir(index_file), "Index"); + strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX); cs_string[0]='#'; int10_to_str(cs_number, cs_string+1, 10); my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file); @@ -505,7 +639,7 @@ CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags) if (!cs && (flags & MY_WME)) { char index_file[FN_REFLEN]; - strmov(get_charsets_dir(index_file), "Index"); + strmov(get_charsets_dir(index_file),MY_CHARSET_INDEX); my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file); } diff --git a/mysys/test_xml.c b/mysys/test_xml.c new file mode 100644 index 00000000000..2a679906cbf --- /dev/null +++ b/mysys/test_xml.c @@ -0,0 +1,105 @@ +/* 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 */ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include "my_xml.h" + +static void mstr(char *str,const char *src,uint l1,uint l2) +{ + l1 = l1<l2 ? l1 : l2; + memcpy(str,src,l1); + str[l1]='\0'; +} + +static int dstr(MY_XML_PARSER *st,const char *attr, uint len) +{ + char str[1024]; + + mstr(str,attr,len,sizeof(str)-1); + printf("VALUE '%s'\n",str); + return MY_XML_OK; +} + +static int bstr(MY_XML_PARSER *st,const char *attr, uint len) +{ + char str[1024]; + + mstr(str,attr,len,sizeof(str)-1); + printf("ENTER %s\n",str); + return MY_XML_OK; +} + + +static int estr(MY_XML_PARSER *st,const char *attr, uint len) +{ + char str[1024]; + + mstr(str,attr,len,sizeof(str)-1); + printf("LEAVE %s\n",str); + return MY_XML_OK; +} + +static void usage(const char *prog) +{ + printf("Usage:\n"); + printf("%s xmlfile\n",prog); +} + +int main(int ac, char **av) +{ + char str[1024*64]=""; + const char *fn; + int f; + uint len; + MY_XML_PARSER p; + + if (ac<2) + { + usage(av[0]); + return 0; + } + + fn=av[1]?av[1]:"test.xml"; + if ((f=open(fn,O_RDONLY))<0) + { + fprintf(stderr,"Err '%s'\n",fn); + return 1; + } + + len=read(f,str,sizeof(str)-1); + str[len]='\0'; + + my_xml_parser_create(&p); + + my_xml_set_enter_handler(&p,bstr); + my_xml_set_value_handler(&p,dstr); + my_xml_set_leave_handler(&p,estr); + + if (MY_XML_OK!=(f=my_xml_parse(&p,str,len))) + { + printf("ERROR at line %d pos %d '%s'\n", + my_xml_error_lineno(&p)+1, + my_xml_error_pos(&p), + my_xml_error_string(&p)); + } + + my_xml_parser_free(&p); + + return 0; +} diff --git a/mysys/xml.c b/mysys/xml.c new file mode 100644 index 00000000000..4f6301249ae --- /dev/null +++ b/mysys/xml.c @@ -0,0 +1,374 @@ +/* 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 */ + +#include "my_global.h" +#include "m_string.h" +#include "my_xml.h" + + +#define MY_XML_EOF 'E' +#define MY_XML_STRING 'S' +#define MY_XML_IDENT 'I' +#define MY_XML_EQ '=' +#define MY_XML_LT '<' +#define MY_XML_GT '>' +#define MY_XML_SLASH '/' +#define MY_XML_COMMENT 'C' +#define MY_XML_TEXT 'T' +#define MY_XML_QUESTION '?' +#define MY_XML_EXCLAM '!' + +typedef struct xml_attr_st +{ + const char *beg; + const char *end; +} MY_XML_ATTR; + +static const char *lex2str(int lex) +{ + switch(lex) + { + case MY_XML_EOF: return "EOF"; + case MY_XML_STRING: return "STRING"; + case MY_XML_IDENT: return "IDENT"; + case MY_XML_EQ: return "'='"; + case MY_XML_LT: return "'<'"; + case MY_XML_GT: return "'>'"; + case MY_XML_SLASH: return "'/'"; + case MY_XML_COMMENT: return "COMMENT"; + case MY_XML_TEXT: return "TEXT"; + case MY_XML_QUESTION: return "'?'"; + case MY_XML_EXCLAM: return "'!'"; + } + return "UNKNOWN"; +} + +static void my_xml_norm_text(MY_XML_ATTR *a) +{ + for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->beg[0]) ; a->beg++ ); + for ( ; (a->beg < a->end) && strchr(" \t\r\n",a->end[-1]) ; a->end-- ); +} + + +static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a) +{ + int lex; + + for( ; ( p->cur < p->end) && strchr(" \t\r\n",p->cur[0]) ; p->cur++); + + if (p->cur >= p->end) + { + a->beg=p->end; + a->end=p->end; + lex=MY_XML_EOF; + goto ret; + } + + a->beg=p->cur; + a->end=p->cur; + + if (!memcmp(p->cur,"<!--",4)) + { + for( ; (p->cur < p->end) && memcmp(p->cur, "-->", 3); p->cur++); + if(!memcmp(p->cur, "-->", 3)) + p->cur+=3; + a->end=p->cur; + lex=MY_XML_COMMENT; + } + else if (strchr("?=/<>!",p->cur[0])) + { + p->cur++; + a->end=p->cur; + lex=a->beg[0]; + } + else if ( (p->cur[0]=='"') || (p->cur[0]=='\'') ) + { + p->cur++; + for( ; ( p->cur < p->end ) && (p->cur[0]!=a->beg[0]); p->cur++); + a->end=p->cur; + if (a->beg[0]==p->cur[0])p->cur++; + a->beg++; + my_xml_norm_text(a); + lex=MY_XML_STRING; + } + else + { + for( ; (p->cur < p->end) && !strchr("?'\"=/<> \t\r\n", p->cur[0]); p->cur++); + a->end=p->cur; + my_xml_norm_text(a); + lex=MY_XML_IDENT; + } + +#if 0 + printf("LEX=%s[%d]\n",lex2str(lex),a->end-a->beg); +#endif + +ret: + return lex; +} + + +static int my_xml_value(MY_XML_PARSER *st, const char *str, uint len) +{ + return (st->value) ? (st->value)(st,str,len) : MY_XML_OK; +} + + +static int my_xml_enter(MY_XML_PARSER *st, const char *str, uint len) +{ + if ( (st->attrend-st->attr+len+1)>sizeof(st->attr)) + { + sprintf(st->errstr,"To deep XML"); + return MY_XML_ERROR; + } + if (st->attrend > st->attr) + { + st->attrend[0]='.'; + st->attrend++; + } + memcpy(st->attrend,str,len); + st->attrend+=len; + st->attrend[0]='\0'; + return st->enter ? st->enter(st,st->attr,st->attrend-st->attr) : MY_XML_OK; +} + +static void mstr(char *s,const char *src,uint l1, uint l2) +{ + l1 = l1<l2 ? l1 : l2; + memcpy(s,src,l1); + s[l1]='\0'; +} + +static int my_xml_leave(MY_XML_PARSER *p, const char *str, uint slen) +{ + char *e; + uint glen; + char s[32]; + char g[32]; + int rc; + + /* Find previous '.' or beginning */ + for( e=p->attrend; (e>p->attr) && (e[0]!='.') ; e--); + glen = (e[0]=='.') ? (p->attrend-e-1) : p->attrend-e; + + if (str && (slen != glen)) + { + mstr(s,str,sizeof(s)-1,slen); + mstr(g,e+1,sizeof(g)-1,glen), + sprintf(p->errstr,"'</%s>' unexpected ('</%s>' wanted)",s,g); + return MY_XML_ERROR; + } + + rc = p->leave ? p->leave(p,p->attr,p->attrend-p->attr) : MY_XML_OK; + + *e='\0'; + p->attrend=e; + + return rc; +} + + +int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) +{ + p->attrend=p->attr; + p->beg=str; + p->cur=str; + p->end=str+len; + + while ( p->cur < p->end ) + { + MY_XML_ATTR a; + if(p->cur[0]=='<') + { + int lex; + int question=0; + int exclam=0; + + lex=my_xml_scan(p,&a); + + if (MY_XML_COMMENT==lex) + { + continue; + } + + lex=my_xml_scan(p,&a); + + if (MY_XML_SLASH==lex) + { + if(MY_XML_IDENT!=(lex=my_xml_scan(p,&a))) + { + sprintf(p->errstr,"1: %s unexpected (ident wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + if(MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg)) + return MY_XML_ERROR; + lex=my_xml_scan(p,&a); + goto gt; + } + + if (MY_XML_EXCLAM==lex) + { + lex=my_xml_scan(p,&a); + exclam=1; + } + else if (MY_XML_QUESTION==lex) + { + lex=my_xml_scan(p,&a); + question=1; + } + + if (MY_XML_IDENT==lex) + { + if(MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) + return MY_XML_ERROR; + } + else + { + sprintf(p->errstr,"3: %s unexpected (ident or '/' wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + + while ((MY_XML_IDENT==(lex=my_xml_scan(p,&a))) || (MY_XML_STRING==lex)) + { + MY_XML_ATTR b; + if(MY_XML_EQ==(lex=my_xml_scan(p,&b))) + { + lex=my_xml_scan(p,&b); + if ( (lex==MY_XML_IDENT) || (lex=MY_XML_STRING) ) + { + if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || + (MY_XML_OK!=my_xml_value(p,b.beg,b.end-b.beg)) || + (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) + return MY_XML_ERROR; + } + else + { + sprintf(p->errstr,"4: %s unexpected (ident or string wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + } + else if ( (MY_XML_STRING==lex) || (MY_XML_IDENT==lex) ) + { + if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) || + (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg))) + return MY_XML_ERROR; + } + else + break; + } + + if (lex==MY_XML_SLASH) + { + if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + return MY_XML_ERROR; + lex=my_xml_scan(p,&a); + } + +gt: + if (question) + { + if (lex!=MY_XML_QUESTION) + { + sprintf(p->errstr,"6: %s unexpected ('?' wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + return MY_XML_ERROR; + lex=my_xml_scan(p,&a); + } + + if (exclam) + { + if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + return MY_XML_ERROR; + } + + if (lex!=MY_XML_GT) + { + sprintf(p->errstr,"5: %s unexpected ('>' wanted)",lex2str(lex)); + return MY_XML_ERROR; + } + } + else + { + a.beg=p->cur; + for ( ; (p->cur < p->end) && (p->cur[0]!='<') ; p->cur++); + a.end=p->cur; + + my_xml_norm_text(&a); + if (a.beg!=a.end) + { + my_xml_value(p,a.beg,a.end-a.beg); + } + } + } + return MY_XML_OK; +} + +void my_xml_parser_create(MY_XML_PARSER *p) +{ + bzero((void*)p,sizeof(p[0])); +} + +void my_xml_parser_free(MY_XML_PARSER *p __attribute__((unused))) +{ +} + +void my_xml_set_value_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) +{ + p->value=action; +} + +void my_xml_set_enter_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) +{ + p->enter=action; +} + +void my_xml_set_leave_handler(MY_XML_PARSER *p, int (*action)(MY_XML_PARSER *p, const char *s, uint l)) +{ + p->leave=action; +} + +void my_xml_set_user_data(MY_XML_PARSER *p, void *user_data) +{ + p->user_data=user_data; +} + +const char *my_xml_error_string(MY_XML_PARSER *p) +{ + return p->errstr; +} + + +uint my_xml_error_pos(MY_XML_PARSER *p) +{ + const char *beg=p->beg; + const char *s; + for ( s=p->beg ; s<p->cur; s++) + if (s[0]=='\n') + beg=s; + return p->cur-beg; +} + +uint my_xml_error_lineno(MY_XML_PARSER *p) +{ + uint res=0; + const char *s; + for ( s=p->beg ; s<p->cur; s++) + if (s[0]=='\n') + res++; + return res; +} diff --git a/sql/field.cc b/sql/field.cc index f206774b456..5f99171b04a 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2599,7 +2599,7 @@ String *Field_double::val_str(String *val_buffer, bool Field_double::send_binary(Protocol *protocol) { - return protocol->store((float) Field_double::val_real(), dec, (String*) 0); + return protocol->store((double) Field_double::val_real(), dec, (String*) 0); } @@ -2797,7 +2797,6 @@ double Field_timestamp::val_real(void) longlong Field_timestamp::val_int(void) { - uint len,pos; int part_time; uint32 temp; time_t time_arg; @@ -3169,7 +3168,7 @@ bool Field_time::send_binary(Protocol *protocol) Field_time::get_time(&tm); tm.day= tm.hour/3600; // Move hours to days tm.hour-= tm.day*3600; - return protocol->store(&tm); + return protocol->store_time(&tm); } @@ -3254,6 +3253,11 @@ int Field_year::store(longlong nr) return 0; } +bool Field_year::send_binary(Protocol *protocol) +{ + ulonglong tmp= Field_year::val_int(); + return protocol->store_short(tmp); +} double Field_year::val_real(void) { @@ -3371,6 +3375,16 @@ int Field_date::store(longlong nr) return error; } +bool Field_date::send_binary(Protocol *protocol) +{ + longlong tmp= Field_date::val_int(); + TIME tm; + tm.year= (uint32) tmp/10000L % 10000; + tm.month= (uint32) tmp/100 % 100; + tm.day= (uint32) tmp % 100; + return protocol->store_date(&tm); +} + double Field_date::val_real(void) { @@ -3544,7 +3558,12 @@ void Field_newdate::store_time(TIME *ltime,timestamp_type type) int3store(ptr,tmp); } - +bool Field_newdate::send_binary(Protocol *protocol) +{ + TIME tm; + Field_newdate::get_date(&tm,0); + return protocol->store_date(&tm); +} double Field_newdate::val_real(void) { @@ -3705,6 +3724,13 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type) longlongstore(ptr,tmp); } +bool Field_datetime::send_binary(Protocol *protocol) +{ + TIME tm; + Field_datetime::get_date(&tm, 1); + return protocol->store(&tm); +} + double Field_datetime::val_real(void) { @@ -3926,7 +3952,6 @@ double Field_string::val_real(void) longlong Field_string::val_int(void) { - longlong value; CHARSET_INFO *cs=charset(); return my_strntoll(cs,ptr,field_length,NULL,10); } diff --git a/sql/field.h b/sql/field.h index 40578d19c82..67bae7302f9 100644 --- a/sql/field.h +++ b/sql/field.h @@ -166,7 +166,7 @@ public: ptr-=row_offset; return tmp; } - bool send_binary(Protocol *protocol); + virtual bool send_binary(Protocol *protocol); virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0) { uint32 length=pack_length(); @@ -792,7 +792,6 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); - bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); void sql_type(String &str) const; @@ -833,7 +832,6 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); - bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type); @@ -876,7 +874,6 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); - bool send_binary(Protocol *protocol); int cmp(const char *,const char*); int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length); int cmp_offset(uint offset); @@ -982,7 +979,6 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); - bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return (uint32) packlength; } diff --git a/sql/filesort.cc b/sql/filesort.cc index 8b55a2f4aa1..00ef12839cf 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -496,7 +496,7 @@ static void make_sortkey(register SORTPARAM *param, length=sort_field->length; } #ifdef USE_STRCOLL - if(use_strnxfrm(cs)) + if (use_strnxfrm(cs)) { if (item->binary()) { diff --git a/sql/gstream.cc b/sql/gstream.cc index 5a58fef6744..a97ed9cae03 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -3,36 +3,38 @@ int GTextReadStream::get_next_toc_type() const { const char *cur = m_cur; - while((*cur)&&(strchr(" \t\r\n",*cur))) + while ((*cur)&&(strchr(" \t\r\n",*cur))) { cur++; } - if(!(*cur)) + if (!(*cur)) { return eostream; } - if(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_')) + if (((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || + (*cur=='_')) { return word; } - if(((*cur>='0') && (*cur<='9')) || (*cur=='-') || (*cur=='+') || (*cur=='.')) + if (((*cur>='0') && (*cur<='9')) || (*cur=='-') || (*cur=='+') || + (*cur=='.')) { return numeric; } - if(*cur == '(') + if (*cur == '(') { return l_bra; } - if(*cur == ')') + if (*cur == ')') { return r_bra; } - if(*cur == ',') + if (*cur == ',') { return comma; } @@ -43,28 +45,28 @@ int GTextReadStream::get_next_toc_type() const const char *GTextReadStream::get_next_word(int *word_len) { const char *cur = m_cur; - while((*cur)&&(strchr(" \t\r\n",*cur))) + while ((*cur)&&(strchr(" \t\r\n",*cur))) { cur++; } m_last_text_position = cur; - if(!(*cur)) + if (!(*cur)) { return 0; } const char *wd_start = cur; - if(((*cur<'a') || (*cur>'z')) && ((*cur<'A') || (*cur>'Z')) && (*cur!='_')) + if (((*cur<'a') || (*cur>'z')) && ((*cur<'A') || (*cur>'Z')) && (*cur!='_')) { return NULL; } ++cur; - while(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_') || - ((*cur>='0') && (*cur<='9'))) + while (((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || + (*cur=='_') || ((*cur>='0') && (*cur<='9'))) { ++cur; } @@ -79,19 +81,19 @@ const char *GTextReadStream::get_next_word(int *word_len) int GTextReadStream::get_next_number(double *d) { const char *cur = m_cur; - while((*cur)&&(strchr(" \t\r\n",*cur))) + while ((*cur)&&(strchr(" \t\r\n",*cur))) { cur++; } m_last_text_position = cur; - if(!(*cur)) + if (!(*cur)) { set_error_msg("Numeric constant expected"); return 1; } - if(((*cur<'0') || (*cur>'9')) && (*cur!='-') && (*cur!='+') && (*cur!='.')) + if (((*cur<'0') || (*cur>'9')) && (*cur!='-') && (*cur!='+') && (*cur!='.')) { set_error_msg("Numeric constant expected"); return 1; @@ -101,7 +103,7 @@ int GTextReadStream::get_next_number(double *d) *d = strtod(cur, &endptr); - if(endptr) + if (endptr) { m_cur = endptr; } @@ -112,11 +114,11 @@ int GTextReadStream::get_next_number(double *d) char GTextReadStream::get_next_symbol() { const char *cur = m_cur; - while((*cur)&&(strchr(" \t\r\n",*cur))) + while ((*cur)&&(strchr(" \t\r\n",*cur))) { cur++; } - if(!(*cur)) + if (!(*cur)) { return 0; } diff --git a/sql/item.cc b/sql/item.cc index feb318f829d..b0b56bf9101 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -47,11 +47,6 @@ Item::Item(): loop_id= 0; } -Item_ref_in_optimizer::Item_ref_in_optimizer(Item_in_optimizer *master, - char *table_name_par, - char *field_name_par): - Item_ref(master->args, table_name_par, field_name_par), owner(master) {} - bool Item::check_loop(uint id) { @@ -178,7 +173,7 @@ const char *Item_ident::full_name() const char *tmp; if (!table_name) return field_name ? field_name : name ? name : "tmp_field"; - if (db_name) + if (db_name && db_name[0]) { tmp=(char*) sql_alloc((uint) strlen(db_name)+(uint) strlen(table_name)+ (uint) strlen(field_name)+3); @@ -198,6 +193,7 @@ String *Item_field::val_str(String *str) { if ((null_value=field->is_null())) return 0; + str->set_charset(str_value.charset()); return field->val_str(str,&str_value); } @@ -220,6 +216,7 @@ String *Item_field::str_result(String *str) { if ((null_value=result_field->is_null())) return 0; + str->set_charset(str_value.charset()); return result_field->val_str(str,&str_value); } @@ -437,20 +434,6 @@ String *Item_copy_string::val_str(String *str) return &str_value; } -double Item_ref_in_optimizer::val() -{ - return owner->get_cache(); -} -longlong Item_ref_in_optimizer::val_int() -{ - return owner->get_cache_int(); -} -String* Item_ref_in_optimizer::val_str(String* s) -{ - return owner->get_cache_str(s); -} - - /* Functions to convert item to field (for send_fields) */ @@ -464,18 +447,6 @@ bool Item::fix_fields(THD *thd, return 0; } -bool Item_outer_select_context_saver::fix_fields(THD *thd, - struct st_table_list *list, - Item ** ref) -{ - DBUG_ENTER("Item_outer_select_context_saver::fix_fields"); - bool res= item->fix_fields(thd, - 0, // do not show current subselect fields - &item); - *ref= item; - DBUG_RETURN(res); -} - bool Item_asterisk_remover::fix_fields(THD *thd, struct st_table_list *list, Item ** ref) @@ -529,6 +500,26 @@ bool Item_asterisk_remover::fix_fields(THD *thd, DBUG_RETURN(res); } +bool Item_ref_on_list_position::fix_fields(THD *thd, + struct st_table_list *tables, + Item ** reference) +{ + List_iterator<Item> li(list); + Item *item; + for (uint i= 0; (item= li++) && i < pos; i++); + if (item) + { + ref= li.ref(); + return Item_ref_null_helper::fix_fields(thd, tables, reference); + } + else + { + ref= 0; + my_error(ER_CARDINALITY_COL, MYF(0), pos); + return 1; + } +} + double Item_ref_null_helper::val() { double tmp= (*ref)->val_result(); @@ -556,8 +547,11 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (!field) // If field is not checked { - Field *tmp; - if ((tmp= find_field_in_tables(thd, this, tables, 0)) == not_found_field) + TABLE_LIST *where= 0; + Field *tmp= (Field *)not_found_field; + if (outer_resolving || + (tmp= find_field_in_tables(thd, this, tables, &where, 0)) == + not_found_field) { /* We can't find table field in table list of current select, @@ -573,14 +567,13 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item **refer= (Item **)not_found_item; // Prevent using outer fields in subselects, that is not supported now SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select; - if (cursel->master_unit()->first_select()->linkage != - DERIVED_TABLE_TYPE) - for (SELECT_LEX *sl=cursel->outer_select(); + if (cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE) + for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select()); sl; sl= sl->outer_select()) { if ((tmp= find_field_in_tables(thd, this, - (last= sl)->get_table_list(), + (last= sl)->get_table_list(), &where, 0)) != not_found_field) break; if ((refer= find_item_in_list(this, sl->item_list, @@ -598,7 +591,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) else if (tmp == not_found_field && refer == (Item **)not_found_item) { // call to return error code - find_field_in_tables(thd, this, tables, 1); + find_field_in_tables(thd, this, tables, &where, 1); return -1; } else if (refer != (Item **)not_found_item) @@ -608,7 +601,6 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) (char *)field_name); if (!r) return 1; - int res; if (r->check_cols(1) || r->fix_fields(thd, tables, ref)) return 1; r->depended_from= last; @@ -624,6 +616,17 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) found table as depended (of select where was found table) */ thd->lex.current_select->mark_as_dependent(last); + if (depended_from->having_fix_field) + { + Item_ref *rf; + *ref= rf= new Item_ref((where->db[0]?where->db:0), + (char *)where->alias, + (char *)field_name); + if (!rf) + return 1; + (rf)->outer_resolving= outer_resolving; + return rf->check_cols(1) || rf->fix_fields(thd, tables, ref); + } } } else if (!tmp) @@ -639,14 +642,6 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) table->used_fields++; table->used_keys&=field->part_of_key; } - if (depended_from != 0 && depended_from->having_fix_field) - { - *ref= new Item_ref((char *)db_name, (char *)table_name, - (char *)field_name); - if (!*ref) - return 1; - return (*ref)->check_cols(1) || (*ref)->fix_fields(thd, tables, ref); - } fixed= 1; return 0; } @@ -1017,13 +1012,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) { if (!ref) { - SELECT_LEX *sl= thd->lex.current_select->outer_select(); + TABLE_LIST *where= 0; + SELECT_LEX *sl= (outer_resolving? + thd->lex.current_select->select_lex(): + thd->lex.current_select->outer_select()); /* Finding only in current select will be performed for selects that have not outer one and for derived tables (which not support using outer fields for now) */ - if ((ref= find_item_in_list(this, + if (outer_resolving || + (ref= find_item_in_list(this, *(thd->lex.current_select->get_item_list()), ((sl && thd->lex.current_select->master_unit()-> @@ -1051,7 +1050,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) (Item **)not_found_item) break; if ((tmp= find_field_in_tables(thd, this, - sl->get_table_list(), + sl->get_table_list(), &where, 0)) != not_found_field); if (sl->master_unit()->first_select()->linkage == DERIVED_TABLE_TYPE) @@ -1221,6 +1220,141 @@ bool field_is_equal_to_item(Field *field,Item *item) return result == field->val_real(); } +Item_cache* Item_cache::get_cache(Item_result type) +{ + switch (type) + { + case INT_RESULT: + return new Item_cache_int(); + case REAL_RESULT: + return new Item_cache_real(); + case STRING_RESULT: + return new Item_cache_str(); + case ROW_RESULT: + return new Item_cache_row(); + default: + // should never be in real life + DBUG_ASSERT(0); + return 0; + } +} + +void Item_cache_str::store(Item *item) +{ + str_value.set(buffer, sizeof(buffer), item->charset()); + value= item->str_result(&str_value); + if ((null_value= item->null_value)) + value= 0; + else if (value != &str_value) + { + /* + We copy string value to avoid changing value if 'item' is table field + in queries like following (where t1.c is varchar): + select a, + (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'), + (select c from t1 where a=t2.a) + from t2; + */ + str_value.copy(*value); + value= &str_value; + } + +} +double Item_cache_str::val() +{ + if (value) + return my_strntod(value->charset(), value->ptr(), + value->length(), (char**)0); + else + return (double)0; +} +longlong Item_cache_str::val_int() +{ + if (value) + return my_strntoll(value->charset(), value->ptr(), + value->length(), (char**) 0, 10); + else + return (longlong)0; +} + +bool Item_cache_row::allocate(uint num) +{ + item_count= num; + THD *thd= current_thd; + return (!(values= + (Item_cache **) thd->calloc(sizeof(Item_cache *)*item_count))); +} + +bool Item_cache_row::setup(Item * item) +{ + if (!values && allocate(item->cols())) + return 1; + for (uint i= 0; i < item_count; i++) + { + Item *el= item->el(i); + Item_cache *tmp; + if (!(tmp= values[i]= Item_cache::get_cache(el->result_type()))) + return 1; + tmp->setup(el); + } + return 0; +} + +void Item_cache_row::store(Item * item) +{ + null_value= 0; + item->bring_value(); + for (uint i= 0; i < item_count; i++) + { + values[i]->store(item->el(i)); + null_value|= values[i]->null_value; + } +} + +void Item_cache_row::illegal_method_call(const char *method) +{ + DBUG_ENTER("Item_cache_row::illegal_method_call"); + DBUG_PRINT("error", ("!!! %s method was called for row item", method)); + DBUG_ASSERT(0); + my_error(ER_CARDINALITY_COL, MYF(0), 1); + DBUG_VOID_RETURN; +} + +bool Item_cache_row::check_cols(uint c) +{ + if (c != item_count) + { + my_error(ER_CARDINALITY_COL, MYF(0), c); + return 1; + } + return 0; +} + +bool Item_cache_row::null_inside() +{ + for (uint i= 0; i < item_count; i++) + { + if (values[i]->cols() > 1) + { + if (values[i]->null_inside()) + return 1; + } + else + { + values[i]->val_int(); + if (values[i]->null_value) + return 1; + } + } + return 0; +} + +void Item_cache_row::bring_value() +{ + for (uint i= 0; i < item_count; i++) + values[i]->bring_value(); + return; +} /***************************************************************************** ** Instantiate templates diff --git a/sql/item.h b/sql/item.h index 89867a8cdbd..3decdc388eb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -31,12 +31,12 @@ public: static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } static void operator delete(void *ptr,size_t size) {} /*lint -e715 */ - enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM, - INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM, - COPY_STR_ITEM,FIELD_AVG_ITEM, DEFAULT_ITEM, - PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, - FIELD_VARIANCE_ITEM,CONST_ITEM, - SUBSELECT_ITEM, ROW_ITEM}; + enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, + INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM, + COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_ITEM, + PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, + FIELD_VARIANCE_ITEM, CONST_ITEM, + SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; String str_value; /* used to store value */ @@ -96,6 +96,7 @@ public: CHARSET_INFO *thd_charset() const; CHARSET_INFO *charset() const { return str_value.charset(); }; void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); } + virtual void set_outer_resolving() {} // Row emulation virtual uint cols() { return 1; } @@ -103,64 +104,12 @@ public: virtual Item** addr(uint i) { return 0; } virtual bool check_cols(uint c); // It is not row => null inside is impossible - virtual bool null_inside() { return 0; }; + virtual bool null_inside() { return 0; } + // used in row subselects to get value of elements + virtual void bring_value() {} }; -/* - Wrapper base class -*/ - -class Item_wrapper :public Item -{ -protected: - Item *item; -public: - /* - Following methods should not be used, because fix_fields exclude this - item (it assign '*ref' with field 'item' in derived classes) - */ - enum Type type() const { return item->type(); } - enum_field_types field_type() const { return item->field_type(); } - double val() { return item->val(); } - longlong val_int() { return item->val_int(); } - String* val_str(String* s) { return item->val_str(s); } - bool check_cols(uint col) { return item->check_cols(col); } - bool eq(const Item *item, bool binary_cmp) const - { return item->eq(item, binary_cmp); } - bool is_null() - { - item->val_int(); - return item->null_value; - } - bool get_date(TIME *ltime, bool fuzzydate) - { - return (null_value=item->get_date(ltime, fuzzydate)); - } - bool send(Protocol *prot, String *tmp) { return item->send(prot, tmp); } - int save_in_field(Field *field, bool no_conversions) - { - return item->save_in_field(field, no_conversions); - } - void save_org_in_field(Field *field) { item->save_org_in_field(field); } - enum Item_result result_type () const { return item->result_type(); } - table_map used_tables() const { return item->used_tables(); } -}; - - -/* - Save context of name resolution for Item, used in subselect transformer. -*/ -class Item_outer_select_context_saver :public Item_wrapper -{ -public: - Item_outer_select_context_saver(Item *it) - { - item= it; - } - bool fix_fields(THD *, struct st_table_list *, Item ** ref); -}; - class st_select_lex; class Item_ident :public Item { @@ -169,12 +118,14 @@ public: const char *table_name; const char *field_name; st_select_lex *depended_from; + bool outer_resolving; /* used for items from reduced subselect */ Item_ident(const char *db_name_par,const char *table_name_par, const char *field_name_par) - :db_name(db_name_par),table_name(table_name_par), - field_name(field_name_par), depended_from(0) + :db_name(db_name_par), table_name(table_name_par), + field_name(field_name_par), depended_from(0), outer_resolving(0) { name = (char*) field_name_par; } const char *full_name() const; + void set_outer_resolving() { outer_resolving= 1; } }; @@ -381,7 +332,7 @@ public: name=(char*) str_value.ptr(); decimals=NOT_FIXED_DEC; } - Item_string(const char *name_par,const char *str,uint length, + Item_string(const char *name_par, const char *str, uint length, CHARSET_INFO *cs) { str_value.set(str,length,cs); @@ -393,11 +344,13 @@ public: enum Type type() const { return STRING_ITEM; } double val() { - return my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),(char**)NULL); + return my_strntod(str_value.charset(), str_value.ptr(), + str_value.length(), (char**) 0); } longlong val_int() { - return my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10); + return my_strntoll(str_value.charset(), str_value.ptr(), + str_value.length(), (char**) 0, 10); } String *val_str(String*) { return (String*) &str_value; } int save_in_field(Field *field, bool no_conversions); @@ -551,7 +504,7 @@ protected: Item_in_subselect* owner; public: Item_ref_null_helper(Item_in_subselect* master, Item **item, - char *table_name_par,char *field_name_par): + char *table_name_par, char *field_name_par): Item_ref(item, table_name_par, field_name_par), owner(master) {} double val(); longlong val_int(); @@ -559,6 +512,28 @@ public: bool get_date(TIME *ltime, bool fuzzydate); }; + +/* + Used to find item in list of select items after '*' items processing. + + Because item '*' can be used in item list. when we create + Item_ref_on_list_position we do not know how item list will be changed, but + we know number of item position (I mean queries like "select * from t"). +*/ +class Item_ref_on_list_position: public Item_ref_null_helper +{ +protected: + List<Item> &list; + uint pos; +public: + Item_ref_on_list_position(Item_in_subselect* master, + List<Item> &li, uint num, + char *table_name, char *field_name): + Item_ref_null_helper(master, 0, table_name, field_name), + list(li), pos(num) {} + bool fix_fields(THD *, struct st_table_list *, Item ** ref); +}; + /* To resolve '*' field moved to condition and register NULL values @@ -575,24 +550,6 @@ public: bool fix_fields(THD *, struct st_table_list *, Item ** ref); }; -class Item_in_optimizer; -class Item_ref_in_optimizer: public Item_ref -{ -protected: - Item_in_optimizer* owner; -public: - Item_ref_in_optimizer(Item_in_optimizer* master, - char *table_name_par,char *field_name_par); - double val(); - longlong val_int(); - String* val_str(String* s); - bool fix_fields(THD *, struct st_table_list *, Item ** ref) - { - fixed= 1; - return 0; - } -}; - /* The following class is used to optimize comparing of date columns We need to save the original item, to be able to set the field to the @@ -707,6 +664,122 @@ public: bool cmp(void); }; +class Item_cache: public Item +{ +public: + virtual bool allocate(uint i) { return 0; }; + virtual bool setup(Item *) { return 0; }; + virtual void store(Item *)= 0; + void set_len_n_dec(uint32 max_len, uint8 dec) + { + max_length= max_len; + decimals= dec; + } + enum Type type() const { return CACHE_ITEM; } + static Item_cache* get_cache(Item_result type); +}; + +class Item_cache_int: public Item_cache +{ + longlong value; +public: + Item_cache_int() { fixed= 1; null_value= 1; } + + void store(Item *item) + { + value= item->val_int_result(); + null_value= item->null_value; + } + double val() { return (double) value; } + longlong val_int() { return value; } + String* val_str(String *str) { str->set(value, thd_charset()); return str; } + enum Item_result result_type() const { return INT_RESULT; } +}; + +class Item_cache_real: public Item_cache +{ + double value; +public: + Item_cache_real() { fixed= 1; null_value= 1; } + + void store(Item *item) + { + value= item->val_result(); + null_value= item->null_value; + } + double val() { return value; } + longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } + String* val_str(String *str) + { + str->set(value, decimals, thd_charset()); + return str; + } + enum Item_result result_type() const { return REAL_RESULT; } +}; + +class Item_cache_str: public Item_cache +{ + char buffer[80]; + String *value; +public: + Item_cache_str() { fixed= 1; null_value= 1; } + + void store(Item *item); + double val(); + longlong val_int(); + String* val_str(String *) { return value; } + enum Item_result result_type() const { return STRING_RESULT; } + CHARSET_INFO *charset() const { return value->charset(); }; +}; + +class Item_cache_row: public Item_cache +{ + Item_cache **values; + uint item_count; +public: + Item_cache_row(): values(0), item_count(2) { fixed= 1; null_value= 1; } + + /* + 'allocate' used only in row transformer, to preallocate space for row + cache. + */ + bool allocate(uint num); + /* + 'setup' is needed only by row => it not called by simple row subselect + (only by IN subselect (in subselect optimizer)) + */ + bool setup(Item *item); + void store(Item *item); + void illegal_method_call(const char *); + void make_field(Send_field *) + { + illegal_method_call((const char*)"make_field"); + }; + double val() + { + illegal_method_call((const char*)"val"); + return 0; + }; + longlong val_int() + { + illegal_method_call((const char*)"val_int"); + return 0; + }; + String *val_str(String *) + { + illegal_method_call((const char*)"val_str"); + return 0; + }; + enum Item_result result_type() const { return ROW_RESULT; } + + uint cols() { return item_count; } + Item* el(uint i) { return values[i]; } + Item** addr(uint i) { return (Item **) (values + i); } + bool check_cols(uint c); + bool null_inside(); + void bring_value(); +}; + extern Item_buff *new_Item_buff(Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item *resolve_const_item(Item *item,Item *cmp_item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index eb3df461603..3d65c05b9cf 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -153,11 +153,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); } else - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - current_thd->fatal_error= 1; return 1; - } } return 0; } @@ -247,6 +243,8 @@ int Arg_comparator::compare_e_int() int Arg_comparator::compare_row() { int res= 0; + (*a)->bring_value(); + (*b)->bring_value(); uint n= (*a)->cols(); for (uint i= 0; i<n; i++) { @@ -261,6 +259,8 @@ int Arg_comparator::compare_row() int Arg_comparator::compare_e_row() { int res= 0; + (*a)->bring_value(); + (*b)->bring_value(); uint n= (*a)->cols(); for (uint i= 0; i<n; i++) { @@ -270,60 +270,59 @@ int Arg_comparator::compare_e_row() return 1; } -longlong Item_in_optimizer::val_int() +bool Item_in_optimizer::preallocate_row() { - int_cache_ok= 1; - flt_cache_ok= 0; - str_cache_ok= 0; - int_cache= args[0]->val_int_result(); - if (args[0]->null_value) - { - null_value= 1; - return 0; - } - longlong tmp= args[1]->val_int_result(); - null_value= args[1]->null_value; - return tmp; + return (!(cache= Item_cache::get_cache(ROW_RESULT))); } -longlong Item_in_optimizer::get_cache_int() +bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, + Item ** ref) { - if (!int_cache_ok) + if (args[0]->fix_fields(thd, tables, args)) + return 1; + if (args[0]->maybe_null) + maybe_null=1; + if (args[0]->binary()) + set_charset(my_charset_bin); + with_sum_func= args[0]->with_sum_func; + used_tables_cache= args[0]->used_tables(); + const_item_cache= args[0]->const_item(); + if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) + return 1; + cache->setup(args[0]); + if (args[1]->fix_fields(thd, tables, args)) + return 1; + Item_in_subselect * sub= (Item_in_subselect *)args[1]; + if (args[0]->cols() != sub->engine->cols()) { - int_cache_ok= 1; - flt_cache_ok= 0; - str_cache_ok= 0; - int_cache= args[0]->val_int_result(); - null_value= args[0]->null_value; + my_error(ER_CARDINALITY_COL, MYF(0), args[0]->cols()); + return 1; } - return int_cache; + if (args[1]->maybe_null) + maybe_null=1; + with_sum_func= with_sum_func || args[1]->with_sum_func; + used_tables_cache|= args[1]->used_tables(); + const_item_cache&= args[1]->const_item(); + return 0; } -double Item_in_optimizer::get_cache() +longlong Item_in_optimizer::val_int() { - if (!flt_cache_ok) + cache->store(args[0]); + if (cache->null_value) { - flt_cache_ok= 1; - int_cache_ok= 0; - str_cache_ok= 0; - flt_cache= args[0]->val_result(); - null_value= args[0]->null_value; + null_value= 1; + return 0; } - return flt_cache; + longlong tmp= args[1]->val_int_result(); + null_value= args[1]->null_value; + return tmp; } -String *Item_in_optimizer::get_cache_str(String *s) +bool Item_in_optimizer::is_null() { - if (!str_cache_ok) - { - str_cache_ok= 1; - int_cache_ok= 0; - flt_cache_ok= 0; - str_value.set(buffer, sizeof(buffer), s->charset()); - str_cache= args[0]->str_result(&str_value); - null_value= args[0]->null_value; - } - return str_cache; + cache->store(args[0]); + return (null_value= (cache->null_value || args[1]->is_null())); } longlong Item_func_eq::val_int() @@ -936,6 +935,13 @@ Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 0; } +void Item_func_case::set_outer_resolving() +{ + first_expr->set_outer_resolving(); + else_expr->set_outer_resolving(); + Item_func::set_outer_resolving(); +} + bool Item_func_case::check_loop(uint id) { DBUG_ENTER("Item_func_case::check_loop"); @@ -1218,8 +1224,9 @@ void cmp_item_row::store_value(Item *item) { THD *thd= current_thd; n= item->cols(); - if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n))) + if ((comparators= (cmp_item **) thd->calloc(sizeof(cmp_item *)*n))) { + item->bring_value(); item->null_value= 0; for (uint i=0; i < n; i++) if ((comparators[i]= cmp_item::get_comparator(item->el(i)))) @@ -1228,18 +1235,10 @@ void cmp_item_row::store_value(Item *item) item->null_value|= item->el(i)->null_value; } else - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - thd->fatal_error= 1; return; - } } else - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - thd->fatal_error= 1; return; - } } void cmp_item_row::store_value_by_template(cmp_item *t, Item *item) @@ -1253,6 +1252,7 @@ void cmp_item_row::store_value_by_template(cmp_item *t, Item *item) n= tmpl->n; if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n))) { + item->bring_value(); item->null_value= 0; for (uint i=0; i < n; i++) if ((comparators[i]= tmpl->comparators[i]->make_same())) @@ -1262,18 +1262,10 @@ void cmp_item_row::store_value_by_template(cmp_item *t, Item *item) item->null_value|= item->el(i)->null_value; } else - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - current_thd->fatal_error= 1; return; - } } else - { - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - current_thd->fatal_error= 1; return; - } } int cmp_item_row::cmp(Item *arg) @@ -1285,6 +1277,7 @@ int cmp_item_row::cmp(Item *arg) return 1; } bool was_null= 0; + arg->bring_value(); for (uint i=0; i < n; i++) if (comparators[i]->cmp(arg->el(i))) { @@ -1510,6 +1503,15 @@ bool Item_cond::check_loop(uint id) DBUG_RETURN(0); } +void Item_cond::set_outer_resolving() +{ + Item_func::set_outer_resolving(); + List_iterator<Item> li(list); + Item *item; + while ((item= li++)) + item->set_outer_resolving(); +} + void Item_cond::split_sum_func(List<Item> &fields) { List_iterator<Item> li(list); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 994e51ef89f..bd7d1bfaf7a 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -85,25 +85,28 @@ public: void fix_length_and_dec() { decimals=0; max_length=1; } }; +class Item_cache; class Item_in_optimizer: public Item_bool_func { protected: - char buffer[80]; - longlong int_cache; - double flt_cache; - String *str_cache; - bool int_cache_ok, flt_cache_ok, str_cache_ok; -public: - Item_in_optimizer(Item *a,Item *b): - Item_bool_func(a,b), int_cache_ok(0), flt_cache_ok(0), str_cache_ok(0) {} - bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } + Item_cache *cache; +public: + Item_in_optimizer(Item *a, Item_in_subselect *b): + Item_bool_func(a, (Item *)b), cache(0) {} + // used by row in transformer + bool preallocate_row(); + bool fix_fields(THD *, struct st_table_list *, Item **); + bool is_null(); + /* + Item_in_optimizer item is special boolean function. On value request + (one of val, val_int or val_str methods) it evaluate left expression + of IN by storing it value in cache item (one of Item_cache* items), + then it test cache is it NULL. If left expression (cache) is NULL then + Item_in_optimizer return NULL, else it evaluate Item_in_subselect. + */ longlong val_int(); - - double get_cache(); - longlong get_cache_int(); - String *get_cache_str(String *s); - - friend class Item_ref_in_optimizer; + + Item_cache **get_cache() { return &cache; } }; class Item_bool_func2 :public Item_int_func @@ -281,6 +284,11 @@ public: const char *func_name() const { return "interval"; } void update_used_tables(); bool check_loop(uint id); + void set_outer_resolving() + { + item->set_outer_resolving(); + Item_func::set_outer_resolving(); + } }; @@ -363,6 +371,7 @@ public: bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); Item *find_item(String *str); bool check_loop(uint id); + void set_outer_resolving(); }; @@ -542,10 +551,14 @@ public: cmp_item_row(): comparators(0), n(0) {} ~cmp_item_row() { - if(comparators) - for(uint i= 0; i < n; i++) + if (comparators) + { + for (uint i= 0; i < n; i++) + { if (comparators[i]) delete comparators[i]; + } + } } void store_value(Item *item); int cmp(Item *arg); @@ -647,6 +660,11 @@ class Item_func_in :public Item_int_func DBUG_RETURN(item->check_loop(id)); } bool nulls_in_row(); + void set_outer_resolving() + { + item->set_outer_resolving(); + Item_int_func::set_outer_resolving(); + } }; /* Functions used by where clause */ @@ -788,6 +806,7 @@ public: friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); bool check_loop(uint id); void top_level_item() { abort_on_null=1; } + void set_outer_resolving(); }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 40579646ae8..dcf4638c48a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -146,6 +146,16 @@ bool Item_func::check_loop(uint id) DBUG_RETURN(0); } +void Item_func::set_outer_resolving() +{ + if (arg_count) + { + Item **arg,**arg_end; + for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) + (*arg)->set_outer_resolving(); + } +} + void Item_func::split_sum_func(List<Item> &fields) { Item **arg,**arg_end; @@ -2359,6 +2369,15 @@ bool Item_func_match::check_loop(uint id) DBUG_RETURN(0); } +void Item_func_match::set_outer_resolving() +{ + Item_real_func::set_outer_resolving(); + List_iterator<Item> li(fields); + Item *item; + while ((item= li++)) + item->set_outer_resolving(); +} + bool Item_func_match::fix_index() { List_iterator_fast<Item> li(fields); diff --git a/sql/item_func.h b/sql/item_func.h index a5420f9056c..bf64412cab3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -133,6 +133,7 @@ public: friend class udf_handler; Field *tmp_table_field(TABLE *t_arg); bool check_loop(uint id); + void set_outer_resolving(); }; @@ -632,6 +633,11 @@ public: DBUG_RETURN(1); DBUG_RETURN(item->check_loop(id)); } + void set_outer_resolving() + { + item->set_outer_resolving(); + Item_int_func::set_outer_resolving(); + } }; @@ -988,7 +994,7 @@ public: { ft_handler->please->close_search(ft_handler); ft_handler=0; - if(join_key) + if (join_key) table->file->ft_handler=0; table->fulltext_searched=0; } @@ -1005,6 +1011,7 @@ public: bool fix_index(); void init_search(bool no_order); bool check_loop(uint id); + void set_outer_resolving(); }; diff --git a/sql/item_row.cc b/sql/item_row.cc index 85a81a50256..c62ab60c0cd 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -41,7 +41,7 @@ void Item_row::illegal_method_call(const char *method) DBUG_ENTER("Item_row::illegal_method_call"); DBUG_PRINT("error", ("!!! %s method was called for row item", method)); DBUG_ASSERT(0); - my_error(ER_CARDINALITY_COL, MYF(0), arg_count); + my_error(ER_CARDINALITY_COL, MYF(0), 1); DBUG_VOID_RETURN; } @@ -54,7 +54,16 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) if (items[i]->fix_fields(thd, tabl, items+i)) return 1; used_tables_cache |= items[i]->used_tables(); - const_item_cache&= items[i]->const_item(); + if (const_item_cache&= items[i]->const_item() && !with_null) + { + if (items[i]->cols() > 1) + with_null|= items[i]->null_inside(); + else + { + items[i]->val_int(); + with_null|= items[i]->null_value; + } + } maybe_null|= items[i]->maybe_null; } return 0; @@ -82,21 +91,24 @@ bool Item_row::check_cols(uint c) return 0; } -bool Item_row::null_inside() +void Item_row::bring_value() { for (uint i= 0; i < arg_count; i++) - { - if (items[i]->cols() > 1) - { - if (items[i]->null_inside()) - return 1; - } - else - { - items[i]->val_int(); - if (items[i]->null_value) - return 1; - } - } + items[i]->bring_value(); +} + +void Item_row::set_outer_resolving() +{ + for (uint i= 0; i < arg_count; i++) + items[i]->set_outer_resolving(); +} + +bool Item_row::check_loop(uint id) +{ + if (Item::check_loop(id)) + return 1; + for (uint i= 0; i < arg_count; i++) + if (items[i]->check_loop(id)) + return 1; return 0; } diff --git a/sql/item_row.h b/sql/item_row.h index 4767d19d08f..ccaf68bed64 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -16,24 +16,27 @@ class Item_row: public Item { - bool array_holder; + Item **items; table_map used_tables_cache; - bool const_item_cache; uint arg_count; - Item **items; + bool array_holder; + bool const_item_cache; + bool with_null; public: Item_row(List<Item> &); Item_row(Item_row *item): - Item(), array_holder(0), + Item(), + items(item->items), used_tables_cache(item->used_tables_cache), - const_item_cache(item->const_item_cache), arg_count(item->arg_count), - items(item->items) + array_holder(0), + const_item_cache(item->const_item_cache), + with_null(0) {} ~Item_row() { - if(array_holder && items) + if (array_holder && items) sql_element_free(items); } @@ -64,10 +67,13 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } void update_used_tables(); + bool check_loop(uint id); + void set_outer_resolving(); uint cols() { return arg_count; } Item* el(uint i) { return items[i]; } Item** addr(uint i) { return items + i; } bool check_cols(uint c); - bool null_inside(); + bool null_inside() { return with_null; }; + void bring_value(); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 78689bb3044..d2b0e89254e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1271,18 +1271,60 @@ String *Item_func_trim::val_str(String *str) return &tmp_value; } +/* + Password() function can have 2 args now. Second argument can be used + to make results repeatable +*/ String *Item_func_password::val_str(String *str) { - String *res =args[0]->val_str(str); + struct rand_struct rand_st; // local structure for 2 param version + ulong seed=0; // seed to initialise random generator to + + String *res =args[0]->val_str(str); if ((null_value=args[0]->null_value)) return 0; - if (res->length() == 0) - return &empty_string; - make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords, - ¤t_thd->rand); - str->set(tmp_value,get_password_length(opt_old_passwords),res->charset()); - return str; + + if (arg_count == 1) + { + if (res->length() == 0) + return &empty_string; + make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords, + ¤t_thd->rand); + str->set(tmp_value,get_password_length(opt_old_passwords),res->charset()); + return str; + } + else + { + /* We'll need the buffer to get second parameter */ + char key_buff[80]; + String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); + String *key =args[1]->val_str(&tmp_key_value); + + /* Check second argument for NULL value. First one is already checked */ + if ((null_value=args[1]->null_value)) + return 0; + + /* This shall be done after checking for null for proper results */ + if (res->length() == 0) + return &empty_string; + + /* Generate the seed first this allows to avoid double allocation */ + char* seed_ptr=key->c_ptr(); + while (*seed_ptr) + { + seed=seed*211+*seed_ptr; /* Use simple hashing */ + seed_ptr++; + } + + /* Use constants which allow nice random values even with small seed */ + randominit(&rand_st,seed*111111+33333333L,seed*1111+55555555L); + + make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords, + &rand_st); + str->set(tmp_value,get_password_length(opt_old_passwords),res->charset()); + return str; + } } String *Item_func_old_password::val_str(String *str) @@ -1961,7 +2003,8 @@ String *Item_func_conv_charset::val_str(String *str) d0=d=(unsigned char*)str->ptr(); de=d+dmaxlen; - while( s < se && d < de){ + while (s < se && d < de) + { cnvres=from->mb_wc(from,&wc,s,se); if (cnvres>0) @@ -2035,7 +2078,7 @@ String *Item_func_conv_charset3::val_str(String *str) d0=d=(unsigned char*)str->ptr(); de=d+dmaxlen; - while( s < se && d < de){ + while (s < se && d < de){ cnvres=from_charset->mb_wc(from_charset,&wc,s,se); if (cnvres>0) @@ -2397,7 +2440,7 @@ String *Item_func_quote::val_str(String *str) */ to= (char*) str->ptr() + new_length - 1; *to--= '\''; - for (start= (char*) arg->ptr() ; end-- != start; to--) + for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--) { /* We can't use the bitmask here as we want to replace \O and ^Z with 0 @@ -2655,7 +2698,7 @@ String *Item_func_spatial_collection::val_str(String *str) null_value=1; str->length(0); - if(str->reserve(9,512)) + if (str->reserve(9,512)) return 0; str->q_append((char)Geometry::wkbNDR); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index c8706c2c933..c90ff6e2295 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -108,14 +108,19 @@ public: separator->fix_fields(thd, tlist, &separator) || Item_func::fix_fields(thd, tlist, ref)); } - const char *func_name() const { return "concat_ws"; } - bool check_loop(uint id) - { - DBUG_ENTER("Item_func_concat_ws::check_loop"); - if (Item_str_func::check_loop(id)) - DBUG_RETURN(1); - DBUG_RETURN(separator->check_loop(id)); - } + const char *func_name() const { return "concat_ws"; } + bool check_loop(uint id) + { + DBUG_ENTER("Item_func_concat_ws::check_loop"); + if (Item_str_func::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(separator->check_loop(id)); + } + void set_outer_resolving() + { + separator->set_outer_resolving(); + Item_func::set_outer_resolving(); + } }; class Item_func_reverse :public Item_str_func @@ -257,6 +262,7 @@ class Item_func_password :public Item_str_func char tmp_value[64]; /* This should be enough for new password format */ public: Item_func_password(Item *a) :Item_str_func(a) {} + Item_func_password(Item *a, Item *b) :Item_str_func(a,b) {} String *val_str(String *); void fix_length_and_dec() { max_length = get_password_length(opt_old_passwords); } const char *func_name() const { return "password"; } @@ -393,6 +399,11 @@ public: DBUG_RETURN(1); DBUG_RETURN(item->check_loop(id)); } + void set_outer_resolving() + { + item->set_outer_resolving(); + Item_str_func::set_outer_resolving(); + } }; @@ -421,6 +432,11 @@ public: DBUG_RETURN(1); DBUG_RETURN(item->check_loop(id)); } + void set_outer_resolving() + { + item->set_outer_resolving(); + Item_str_func::set_outer_resolving(); + } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 4b9e9c256d1..c5ecdc87d40 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -32,6 +32,11 @@ SUBSELECT TODO: #include "mysql_priv.h" #include "sql_select.h" +inline Item * and_items(Item* cond, Item *item) +{ + return (cond? (new Item_cond_and(cond, item)) : item); +} + Item_subselect::Item_subselect(): Item_result_field(), engine_owner(1), value_assigned(0), substitution(0), have_to_be_excluded(0) @@ -51,7 +56,7 @@ void Item_subselect::init(THD *thd, st_select_lex *select_lex, DBUG_ENTER("Item_subselect::init"); DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex)); - select_transformer(select_lex); + select_transformer(thd, select_lex->master_unit()); if (select_lex->next_select()) engine= new subselect_union_engine(thd, select_lex->master_unit(), result, this); @@ -67,7 +72,7 @@ Item_subselect::~Item_subselect() delete engine; } -void Item_subselect::select_transformer(st_select_lex *select_lex) +void Item_subselect::select_transformer(THD *thd, st_select_lex_unit *unit) { DBUG_ENTER("Item_subselect::select_transformer"); DBUG_VOID_RETURN; @@ -112,9 +117,14 @@ bool Item_subselect::check_loop(uint id) DBUG_RETURN(engine->check_loop(id)); } +Item::Type Item_subselect::type() const +{ + return SUBSELECT_ITEM; +} + void Item_subselect::fix_length_and_dec() { - engine->fix_length_and_dec(); + engine->fix_length_and_dec(0); } inline table_map Item_subselect::used_tables() const @@ -122,56 +132,165 @@ inline table_map Item_subselect::used_tables() const return (table_map) engine->depended() ? 1L : 0L; } -Item_singleval_subselect::Item_singleval_subselect(THD *thd, +Item_singlerow_subselect::Item_singlerow_subselect(THD *thd, st_select_lex *select_lex): - Item_subselect() + Item_subselect(), value(0) { - DBUG_ENTER("Item_singleval_subselect::Item_singleval_subselect"); - init(thd, select_lex, new select_singleval_subselect(this)); + DBUG_ENTER("Item_singlerow_subselect::Item_singlerow_subselect"); + init(thd, select_lex, new select_singlerow_subselect(this)); max_columns= 1; maybe_null= 1; + max_columns= UINT_MAX; DBUG_VOID_RETURN; } -void Item_singleval_subselect::fix_length_and_dec() +void Item_singlerow_subselect::reset() { - engine->fix_length_and_dec(); - res_type= engine->type(); + null_value= 1; + if (value) + value->null_value= 1; } -Item::Type Item_subselect::type() const +void Item_singlerow_subselect::select_transformer(THD *thd, + st_select_lex_unit *unit) { - return SUBSELECT_ITEM; + SELECT_LEX *select_lex= unit->first_select(); + + if (!select_lex->next_select() && !select_lex->table_list.elements && + select_lex->item_list.elements == 1 && + // TODO: mark subselect items from item list separately + !(select_lex->item_list.head()->type() == FIELD_ITEM || + select_lex->item_list.head()->type() == REF_ITEM) + ) + { + + have_to_be_excluded= 1; + if (thd->lex.describe) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_SELECT_REDUCED, warn_buff); + } + substitution= select_lex->item_list.head(); + substitution->set_outer_resolving(); + + if (select_lex->where || select_lex->having) + { + Item *cond; + if (!select_lex->having) + cond= select_lex->where; + else if (!select_lex->where) + cond= select_lex->having; + else + if (!(cond= new Item_cond_and(select_lex->having, select_lex->where))) + return; + if (!(substitution= new Item_func_if(cond, substitution, + new Item_null()))) + return; + } + } } -double Item_singleval_subselect::val () +void Item_singlerow_subselect::store(uint i, Item *item) { - if (engine->exec()) + row[i]->store(item); +} + +enum Item_result Item_singlerow_subselect::result_type() const +{ + return engine->type(); +} + +void Item_singlerow_subselect::fix_length_and_dec() +{ + if ((max_columns= engine->cols()) == 1) + { + engine->fix_length_and_dec(row= &value); + if (!(value= Item_cache::get_cache(engine->type()))) + return; + } + else + { + THD *thd= current_thd; + if (!(row= (Item_cache**)thd->alloc(sizeof(Item_cache*)*max_columns))) + return; + engine->fix_length_and_dec(row); + value= *row; + } + maybe_null= engine->may_be_null(); +} + +uint Item_singlerow_subselect::cols() +{ + return engine->cols(); +} + +bool Item_singlerow_subselect::check_cols(uint c) +{ + if (c != engine->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), c); + return 1; + } + return 0; +} + +bool Item_singlerow_subselect::null_inside() +{ + for (uint i= 0; i < max_columns ; i++) + { + if (row[i]->null_value) + return 1; + } + return 0; +} + +void Item_singlerow_subselect::bring_value() +{ + engine->exec(); +} + +double Item_singlerow_subselect::val () +{ + if (!engine->exec() && !value->null_value) + { + null_value= 0; + return value->val(); + } + else { reset(); return 0; } - return real_value; } -longlong Item_singleval_subselect::val_int () +longlong Item_singlerow_subselect::val_int () { - if (engine->exec()) + if (!engine->exec() && !value->null_value) + { + null_value= 0; + return value->val_int(); + } + else { reset(); return 0; } - return int_value; } -String *Item_singleval_subselect::val_str (String *str) +String *Item_singlerow_subselect::val_str (String *str) { - if (engine->exec() || null_value) + if (!engine->exec() && !value->null_value) + { + null_value= 0; + return value->val_str(str); + } + else { reset(); return 0; } - return &string_value; } Item_exists_subselect::Item_exists_subselect(THD *thd, @@ -213,7 +332,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, left_expr= left_exp; func= f; init(thd, select_lex, new select_exists_subselect(this)); - max_columns= UINT_MAX; + max_columns= 1; reset(); // We need only 1 row to determinate existence select_lex->master_unit()->global_parameters->select_limit= 1; @@ -223,8 +342,9 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, void Item_exists_subselect::fix_length_and_dec() { - decimals=0; + decimals= 0; max_length= 1; + max_columns= engine->cols(); } double Item_exists_subselect::val () @@ -313,42 +433,44 @@ Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item): func= item->func; } -void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, +void Item_in_subselect::single_value_transformer(THD *thd, + st_select_lex_unit *unit, Item *left_expr, compare_func_creator func) { DBUG_ENTER("Item_in_subselect::single_value_transformer"); - if (select_lex->master_unit()->global_parameters->select_limit != - HA_POS_ERROR) + if (unit->global_parameters->select_limit != HA_POS_ERROR) { my_error(ER_NOT_SUPPORTED_YET, MYF(0), "LIMIT & IN/ALL/ANY/SOME subquery"); DBUG_VOID_RETURN; } + // no sense in ORDER BY without LIMIT + unit->global_parameters->order_list.empty(); + Item_in_optimizer *optimizer; substitution= optimizer= new Item_in_optimizer(left_expr, this); if (!optimizer) - { - current_thd->fatal_error= 1; DBUG_VOID_RETURN; - } + /* As far as Item_ref_in_optimizer do not substitude itself on fix_fields we can use same item for all selects. */ - Item *expr= new Item_ref_in_optimizer(optimizer, (char *)"<no matter>", - (char*)"<left expr>"); - select_lex->master_unit()->dependent= 1; - for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select()) + Item *expr= new Item_ref((Item**)optimizer->get_cache(), + (char *)"<no matter>", + (char*)"<left expr>"); + unit->dependent= 1; + for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select()) { - if (select_lex->select_limit != HA_POS_ERROR) + if (sl->select_limit != HA_POS_ERROR) { my_error(ER_NOT_SUPPORTED_YET, MYF(0), "LIMIT & IN/ALL/ANY/SOME subquery"); DBUG_VOID_RETURN; } - select_lex->dependent= 1; + sl->dependent= 1; Item *item; if (sl->item_list.elements > 1) { @@ -358,24 +480,16 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, else item= (Item*) sl->item_list.pop(); - if (sl->having || sl->with_sum_func || sl->group_list.first || - sl->order_list.first) + sl->order_list.empty(); // no sense in ORDER BY without LIMIT + + if (sl->having || sl->with_sum_func || sl->group_list.first) { sl->item_list.push_back(item); item= (*func)(expr, new Item_ref_null_helper(this, sl->item_list.head_ref(), (char *)"<no matter>", (char*)"<result>")); - if (sl->having || sl->with_sum_func || sl->group_list.first) - if (sl->having) - sl->having= new Item_cond_and(sl->having, item); - else - sl->having= item; - else - if (sl->where) - sl->where= new Item_cond_and(sl->having, item); - else - sl->where= item; + sl->having= and_items(sl->having, item); } else { @@ -386,10 +500,7 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, item= (*func)(expr, new Item_asterisk_remover(this, item, (char *)"<no matter>", (char*)"<result>")); - if (sl->where) - sl->where= new Item_cond_and(sl->where, item); - else - sl->where= item; + sl->where= and_items(sl->where, item); } else { @@ -399,7 +510,7 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, my_error(ER_NO_TABLES_USED, MYF(0)); DBUG_VOID_RETURN; } - if (select_lex->next_select()) + if (unit->first_select()->next_select()) { /* It is in union => we should perform it. @@ -416,7 +527,6 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, item= (*func)(left_expr, item); substitution= item; have_to_be_excluded= 1; - THD *thd= current_thd; if (thd->lex.describe) { char warn_buff[MYSQL_ERRMSG_SIZE]; @@ -431,15 +541,91 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, DBUG_VOID_RETURN; } -void Item_in_subselect::select_transformer(st_select_lex *select_lex) +void Item_in_subselect::row_value_transformer(THD *thd, + st_select_lex_unit *unit, + Item *left_expr) { - single_value_transformer(select_lex, left_expr, - &Item_bool_func2::eq_creator); + DBUG_ENTER("Item_in_subselect::row_value_transformer"); + if (unit->global_parameters->select_limit != + HA_POS_ERROR) + { + /* + Because we do the following (not exactly, following is just explenation) + transformation + SELECT * from t1 WHERE t1.a IN (SELECT t2.a FROM t2) + -> + SELECT * from t1 WHERE EXISTS(SELECT 1 FROM t2 t1.a = t2.a LIMIT 1) + + it's impossible to support limit in the sub select. + */ + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "LIMIT & IN/ALL/ANY/SOME subquery"); + DBUG_VOID_RETURN; + } + // no sense in ORDER BY without LIMIT + unit->global_parameters->order_list.empty(); + + Item_in_optimizer *optimizer; + substitution= optimizer= new Item_in_optimizer(left_expr, this); + if (!optimizer) + DBUG_VOID_RETURN; + + unit->dependent= 1; + uint n= left_expr->cols(); + if (optimizer->preallocate_row() || (*optimizer->get_cache())->allocate(n)) + DBUG_VOID_RETURN; + for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select()) + { + if (sl->select_limit != HA_POS_ERROR) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "LIMIT & IN/ALL/ANY/SOME subquery"); + DBUG_VOID_RETURN; + } + sl->order_list.empty(); // no sense in ORDER BY without LIMIT + + sl->dependent= 1; + + Item *item= 0; + List_iterator_fast<Item> li(sl->item_list); + for (uint i= 0; i < n; i++) + { + Item *func= + new Item_ref_on_list_position(this, sl->item_list, i, + (char *) "<no matter>", + (char *) "<list ref>"); + func= + Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())-> + addr(i), + (char *)"<no matter>", + (char *)"<left expr>"), + func); + item= and_items(item, func); + } + + if (sl->having || sl->with_sum_func || sl->group_list.first || + !sl->table_list.elements) + sl->having= and_items(sl->having, item); + else + sl->where= and_items(sl->where, item); + } + DBUG_VOID_RETURN; } -void Item_allany_subselect::select_transformer(st_select_lex *select_lex) + +void Item_in_subselect::select_transformer(THD *thd, st_select_lex_unit *unit) { - single_value_transformer(select_lex, left_expr, func); + if (left_expr->cols() == 1) + single_value_transformer(thd, unit, left_expr, + &Item_bool_func2::eq_creator); + else + row_value_transformer(thd, unit, left_expr); +} + +void Item_allany_subselect::select_transformer(THD *thd, + st_select_lex_unit *unit) +{ + single_value_transformer(thd, unit, left_expr, func); } subselect_single_select_engine::subselect_single_select_engine(THD *thd, @@ -476,7 +662,7 @@ subselect_union_engine::subselect_union_engine(THD *thd, subselect_engine(thd, item, result) { unit= u; - if( !result) + if (!result) { //out of memory thd->fatal_error= 1; @@ -492,13 +678,13 @@ int subselect_single_select_engine::prepare() prepared= 1; SELECT_LEX_NODE *save_select= thd->lex.current_select; thd->lex.current_select= select_lex; - if(join->prepare((TABLE_LIST*) select_lex->table_list.first, - select_lex->where, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, - select_lex->having, - (ORDER*) 0, select_lex, - select_lex->master_unit(), 0)) + if (join->prepare((TABLE_LIST*) select_lex->table_list.first, + select_lex->where, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) 0, select_lex, + select_lex->master_unit(), 0)) return 1; thd->lex.current_select= save_select; return 0; @@ -509,31 +695,82 @@ int subselect_union_engine::prepare() return unit->prepare(thd, result); } -void subselect_single_select_engine::fix_length_and_dec() +static Item_result set_row(SELECT_LEX *select_lex, Item * item, + Item_cache **row, bool *maybe_null) { + Item_result res_type= STRING_RESULT; + Item *sel_item; List_iterator_fast<Item> li(select_lex->item_list); - Item *sel_item= li++; - item->max_length= sel_item->max_length; - res_type= sel_item->result_type(); - item->decimals= sel_item->decimals; + for (uint i= 0; (sel_item= li++); i++) + { + item->max_length= sel_item->max_length; + res_type= sel_item->result_type(); + item->decimals= sel_item->decimals; + *maybe_null= sel_item->maybe_null; + if (row) + { + if (!(row[i]= Item_cache::get_cache(res_type))) + return STRING_RESULT; // we should return something + row[i]->set_len_n_dec(sel_item->max_length, sel_item->decimals); + } + } + if (select_lex->item_list.elements > 1) + res_type= ROW_RESULT; + return res_type; } -void subselect_union_engine::fix_length_and_dec() +void subselect_single_select_engine::fix_length_and_dec(Item_cache **row) { - uint32 mlen= 0, len; - Item *sel_item= 0; - for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + DBUG_ASSERT(row || select_lex->item_list.elements==1); + res_type= set_row(select_lex, item, row, &maybe_null); + if (cols() != 1) + maybe_null= 0; +} + +void subselect_union_engine::fix_length_and_dec(Item_cache **row) +{ + DBUG_ASSERT(row || unit->first_select()->item_list.elements==1); + + if (unit->first_select()->item_list.elements == 1) { - List_iterator_fast<Item> li(sl->item_list); - Item *s_item= li++; - if ((len= s_item->max_length)) - mlen= len; - if (!sel_item) - sel_item= s_item; + uint32 mlen= 0, len; + Item *sel_item= 0; + for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + { + List_iterator_fast<Item> li(sl->item_list); + Item *s_item= li++; + if ((len= s_item->max_length) > mlen) + mlen= len; + if (!sel_item) + sel_item= s_item; + maybe_null= s_item->maybe_null; + } + item->max_length= mlen; + res_type= sel_item->result_type(); + item->decimals= sel_item->decimals; + if (row) + { + if (!(row[0]= Item_cache::get_cache(res_type))) + return; + row[0]->set_len_n_dec(mlen, sel_item->decimals); + } + } + else + { + SELECT_LEX *sl= unit->first_select(); + bool fake= 0; + res_type= set_row(sl, item, row, &fake); + for (sl= sl->next_select(); sl; sl->next_select()) + { + List_iterator_fast<Item> li(sl->item_list); + Item *sel_item; + for (uint i= 0; (sel_item= li++); i++) + { + if (sel_item->max_length > row[i]->max_length) + row[i]->max_length= sel_item->max_length; + } + } } - item->max_length= mlen; - res_type= sel_item->result_type(); - item->decimals= sel_item->decimals; } int subselect_single_select_engine::exec() diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0e6f939803d..cf7f612224a 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -71,7 +71,7 @@ public: { null_value= 1; } - virtual void select_transformer(st_select_lex *select_lex); + virtual void select_transformer(THD *thd, st_select_lex_unit *unit); bool assigned() { return value_assigned; } void assigned(bool a) { value_assigned= a; } enum Type type() const; @@ -86,51 +86,43 @@ public: bool check_loop(uint id); friend class select_subselect; + friend class Item_in_optimizer; }; /* single value subselect */ -class Item_singleval_subselect :public Item_subselect +class Item_cache; +class Item_singlerow_subselect :public Item_subselect { protected: - longlong int_value; /* Here stored integer value of this item */ - double real_value; /* Here stored real value of this item */ - /* - Here stored string value of this item. - (str_value used only as temporary buffer, because it can be changed - by Item::save_field) - */ - String string_value; - enum Item_result res_type; /* type of results */ - + Item_cache *value, **row; public: - Item_singleval_subselect(THD *thd, st_select_lex *select_lex); - Item_singleval_subselect(Item_singleval_subselect *item): + Item_singlerow_subselect(THD *thd, st_select_lex *select_lex); + Item_singlerow_subselect(Item_singlerow_subselect *item): Item_subselect(item) { - int_value= item->int_value; - real_value= item->real_value; - string_value.set(item->string_value, 0, item->string_value.length()); + value= item->value; max_length= item->max_length; decimals= item->decimals; - res_type= item->res_type; - } - virtual void reset() - { - null_value= 1; - int_value= 0; - real_value= 0; - max_length= 4; - res_type= STRING_RESULT; } - double val (); + void reset(); + void select_transformer(THD *thd, st_select_lex_unit *unit); + void store(uint i, Item* item); + double val(); longlong val_int (); String *val_str (String *); - Item *new_item() { return new Item_singleval_subselect(this); } - enum Item_result result_type() const { return res_type; } + Item *new_item() { return new Item_singlerow_subselect(this); } + enum Item_result result_type() const; void fix_length_and_dec(); - friend class select_singleval_subselect; + uint cols(); + Item* el(uint i) { return (Item*)row[i]; } + Item** addr(uint i) { return (Item**)row + i; } + bool check_cols(uint c); + bool null_inside(); + void bring_value(); + + friend class select_singlerow_subselect; }; /* exists subselect */ @@ -149,7 +141,7 @@ public: } Item_exists_subselect(): Item_subselect() {} - virtual void reset() + void reset() { value= 0; } @@ -181,9 +173,11 @@ public: null_value= 0; was_null= 0; } - virtual void select_transformer(st_select_lex *select_lex); - void single_value_transformer(st_select_lex *select_lex, + virtual void select_transformer(THD *thd, st_select_lex_unit *unit); + void single_value_transformer(THD *thd, st_select_lex_unit *unit, Item *left_expr, compare_func_creator func); + void row_value_transformer(THD *thd, st_select_lex_unit *unit, + Item *left_expr); longlong val_int(); double val(); String *val_str(String*); @@ -202,22 +196,18 @@ public: Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f, st_select_lex *select_lex); Item_allany_subselect(Item_allany_subselect *item); - virtual void select_transformer(st_select_lex *select_lex); + virtual void select_transformer(THD *thd, st_select_lex_unit *unit); }; -class subselect_engine +class subselect_engine: public Sql_alloc { protected: select_subselect *result; /* results storage class */ THD *thd; /* pointer to current THD */ Item_subselect *item; /* item, that use this engine */ enum Item_result res_type; /* type of results */ + bool maybe_null; /* may be null (first item in select) */ public: - static void *operator new(size_t size) - { - return (void*) sql_alloc((uint) size); - } - static void operator delete(void *ptr, size_t size) {} subselect_engine(THD *thd, Item_subselect *si, select_subselect *res) { @@ -225,16 +215,19 @@ public: item= si; this->thd= thd; res_type= STRING_RESULT; + maybe_null= 0; } + virtual ~subselect_engine() {}; // to satisfy compiler virtual int prepare()= 0; - virtual void fix_length_and_dec()= 0; + virtual void fix_length_and_dec(Item_cache** row)= 0; virtual int exec()= 0; virtual uint cols()= 0; /* return number of columnss in select */ virtual bool depended()= 0; /* depended from outer select */ enum Item_result type() { return res_type; } virtual bool check_loop(uint id)= 0; virtual void exclude()= 0; + bool may_be_null() { return maybe_null; }; }; class subselect_single_select_engine: public subselect_engine @@ -249,7 +242,7 @@ public: select_subselect *result, Item_subselect *item); int prepare(); - void fix_length_and_dec(); + void fix_length_and_dec(Item_cache** row); int exec(); uint cols(); bool depended(); @@ -266,7 +259,7 @@ public: select_subselect *result, Item_subselect *item); int prepare(); - void fix_length_and_dec(); + void fix_length_and_dec(Item_cache** row); int exec(); uint cols(); bool depended(); diff --git a/sql/log_event.cc b/sql/log_event.cc index 89918dafc9e..8f98fa511a0 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -736,7 +736,9 @@ int Query_log_event::write_data(IO_CACHE* file) #ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans) - :Log_event(thd_arg, 0, using_trans), data_buf(0), query(query_arg), + :Log_event(thd_arg, !thd_arg->lex.tmp_table_used ? + 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans), + data_buf(0), query(query_arg), db(thd_arg->db), q_len((uint32) query_length), error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), thread_id(thd_arg->thread_id) @@ -818,6 +820,8 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) *end++=';'; *end++='\n'; my_fwrite(file, (byte*) buff, (uint) (end-buff),MYF(MY_NABP | MY_WME)); + if (flags & LOG_EVENT_THREAD_SPECIFIC_F) + fprintf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id); my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fprintf(file, ";\n"); } @@ -853,7 +857,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) thd->query_error= 0; // clear error thd->clear_error(); - thd->slave_proxy_id = thread_id; // for temp tables + thd->variables.pseudo_thread_id= thread_id; // for temp tables /* Sanity check to make sure the master did not get a really bad @@ -1485,7 +1489,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) ex.skip_lines = skip_lines; List<Item> field_list; set_fields(field_list); - thd->slave_proxy_id = thd->thread_id; + thd->variables.pseudo_thread_id= thd->thread_id; if (net) { // mysql_load will use thd->net to read the file diff --git a/sql/log_event.h b/sql/log_event.h index c4f93c7a9b6..ec3b4819e74 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -212,8 +212,10 @@ struct sql_ex_info #define BINLOG_MAGIC "\xfe\x62\x69\x6e" -#define LOG_EVENT_TIME_F 0x1 -#define LOG_EVENT_FORCED_ROTATE_F 0x2 +#define LOG_EVENT_TIME_F 0x1 +#define LOG_EVENT_FORCED_ROTATE_F 0x2 +#define LOG_EVENT_THREAD_SPECIFIC_F 0x4 /* query depends on thread + (for example: TEMPORARY TABLE) */ enum Log_event_type { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3d5adf24e03..fa9514c63b7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -423,6 +423,9 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name, enum enum_duplicates handle_duplicates, enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS, bool simple_alter=0); +int mysql_create_like_table(THD *thd, TABLE_LIST *table, + HA_CREATE_INFO *create_info, + Table_ident *src_table); bool mysql_rename_table(enum db_type base, const char *old_db, const char * old_name, @@ -464,7 +467,7 @@ bool drop_locked_tables(THD *thd,const char *db, const char *table_name); void abort_locked_tables(THD *thd,const char *db, const char *table_name); extern const Field *not_found_field; Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, - bool report_error); + TABLE_LIST **where, bool report_error); Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, bool check_grant,bool allow_rowid); #ifdef HAVE_OPENSSL diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 13b5d52a343..c2dfc9d1935 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -182,7 +182,6 @@ static char szPipeName [ 257 ]; static SECURITY_ATTRIBUTES saPipeSecurity; static SECURITY_DESCRIPTOR sdPipeDescriptor; static HANDLE hPipe = INVALID_HANDLE_VALUE; -static uint handler_count; static bool opt_enable_named_pipe = 0; #endif #ifdef __WIN__ @@ -1902,6 +1901,7 @@ int main(int argc, char **argv) set_options(); get_options(argc,argv); + max_system_variables.pseudo_thread_id= (ulong)~0; if (opt_log || opt_update_log || opt_slow_log || opt_bin_log) strcat(server_version,"-log"); DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc index b917c91ce15..93bae6f444d 100644 --- a/sql/nt_servc.cc +++ b/sql/nt_servc.cc @@ -431,7 +431,7 @@ BOOL NTService::SeekStatus(LPCSTR szInternName, int OperationType) if (ret_error == ERROR_ACCESS_DENIED) { printf("Install/Remove of the Service Denied!\n"); - if(!is_super_user()) + if (!is_super_user()) printf("That operation should be made by an user with Administrator privileges!\n"); } else @@ -530,13 +530,13 @@ BOOL NTService::is_super_user() UINT x; BOOL ret_value=FALSE; - if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,&hAccessToken )) + if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,&hAccessToken )) { - if(GetLastError() != ERROR_NO_TOKEN) - return FALSE; + if (GetLastError() != ERROR_NO_TOKEN) + return FALSE; - if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken)) - return FALSE; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken)) + return FALSE; } ret_value= GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer, @@ -544,21 +544,21 @@ BOOL NTService::is_super_user() CloseHandle(hAccessToken); - if(!ret_value ) - return FALSE; + if (!ret_value ) + return FALSE; - if(!AllocateAndInitializeSid(&siaNtAuthority, 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &psidAdministrators)) - return FALSE; + if (!AllocateAndInitializeSid(&siaNtAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &psidAdministrators)) + return FALSE; ret_value = FALSE; - for(x=0;x<ptgGroups->GroupCount;x++) + for (x=0;x<ptgGroups->GroupCount;x++) { - if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) ) + if ( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) ) { ret_value = TRUE; break; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index b117b6a5ea1..887ce6c561a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2162,12 +2162,13 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, tmp=1; // Max one record else { - if(tmp_min_flag & GEOM_FLAG) + if (tmp_min_flag & GEOM_FLAG) { - tmp=param->table->file-> - records_in_range((int) keynr,(byte*)(param->min_key + 1), - min_key_length, (ha_rkey_function)(tmp_min_flag ^ GEOM_FLAG), - (byte *)NullS,0,HA_READ_KEY_EXACT); + tmp= param->table->file-> + records_in_range((int) keynr, (byte*)(param->min_key + 1), + min_key_length, + (ha_rkey_function)(tmp_min_flag ^ GEOM_FLAG), + (byte *)NullS, 0, HA_READ_KEY_EXACT); } else { diff --git a/sql/password.c b/sql/password.c index 9fd3757106d..da7a499ba09 100644 --- a/sql/password.c +++ b/sql/password.c @@ -573,7 +573,7 @@ void get_hash_and_password(ulong* salt, uint8 pversion, char* hash, unsigned cha while (salt<salt_end) /* Iterate over these elements*/ { val=*salt; - for(t=3;t>=0;t--) + for (t=3;t>=0;t--) { bp[t]=val%256; diff --git a/sql/protocol.cc b/sql/protocol.cc index 9d7dc66b452..d7cf9d39b5c 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -616,7 +616,7 @@ bool Protocol_simple::store_null() field_pos++; #endif char buff[1]; - buff[0]= 251; + buff[0]= (char)251; return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC); } @@ -774,13 +774,27 @@ bool Protocol_simple::store_time(TIME *tm) /**************************************************************************** Functions to handle the binary protocol used with prepared statements + + Data format: + + [ok:1] <-- reserved ok packet + [null_field:(field_count+7+2)/8] <-- reserved to send null data. The size is + calculated using: + bit_fields= (field_count+7+2)/8; + 2 bits are reserved + [[length]data] <-- data field (the length applies only for + string/binary/time/timestamp fields and + rest of them are not sent as they have + the default length that client understands + based on the field type + [..]..[[length]data] <-- data ****************************************************************************/ bool Protocol_prep::prepare_for_send(List<Item> *item_list) { - field_count=item_list->elements; - bit_fields= (field_count+3)/8; - if (packet->alloc(bit_fields)) + field_count= item_list->elements; + bit_fields= (field_count+9)/8; + if (packet->alloc(bit_fields+1)) return 1; /* prepare_for_resend will be called after this one */ return 0; @@ -789,9 +803,8 @@ bool Protocol_prep::prepare_for_send(List<Item> *item_list) void Protocol_prep::prepare_for_resend() { - packet->length(bit_fields); - bzero((char*) packet->ptr()+1, bit_fields-1); - packet[0]=1; // Marker for ok packet + packet->length(bit_fields+1); + bzero((char*) packet->ptr(), 1+bit_fields); field_pos=0; } @@ -813,7 +826,7 @@ bool Protocol_prep::store(const char *from,uint length) bool Protocol_prep::store_null() { - uint offset=(field_pos+2)/8, bit= (1 << ((field_pos+2) & 7)); + uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7)); /* Room for this as it's allocated in prepare_for_send */ char *to= (char*) packet->ptr()+offset; *to= (char) ((uchar) *to | (uchar) bit); @@ -839,7 +852,8 @@ bool Protocol_prep::store_short(longlong from) { #ifndef DEBUG_OFF DBUG_ASSERT(field_types == 0 || - field_types[field_pos] == MYSQL_TYPE_SHORT); + field_types[field_pos] == MYSQL_TYPE_SHORT || + field_types[field_pos] == MYSQL_TYPE_YEAR); #endif field_pos++; char *to= packet->prep_append(2, PACKET_BUFFET_EXTRA_ALLOC); @@ -936,11 +950,11 @@ bool Protocol_prep::store(TIME *tm) pos= buff+1; int2store(pos, tm->year); - int2store(pos+2, tm->month); - int2store(pos+3, tm->day); - int2store(pos+4, tm->hour); - int2store(pos+5, tm->minute); - int2store(pos+6, tm->second); + pos[2]= (uchar) tm->month; + pos[3]= (uchar) tm->day; + pos[4]= (uchar) tm->hour; + pos[5]= (uchar) tm->minute; + pos[6]= (uchar) tm->second; int4store(pos+7, tm->second_part); if (tm->second_part) length=11; @@ -973,17 +987,24 @@ bool Protocol_prep::store_time(TIME *tm) field_pos++; pos= buff+1; pos[0]= tm->neg ? 1 : 0; - int4store(pos+1, tm->day); - int2store(pos+5, tm->hour); - int2store(pos+7, tm->minute); - int2store(pos+9, tm->second); - int4store(pos+11, tm->second_part); + int4store(pos+1, tm->day); + pos[5]= (uchar) tm->hour; + pos[6]= (uchar) tm->minute; + pos[7]= (uchar) tm->second; + int4store(pos+8, tm->second_part); if (tm->second_part) - length=14; + length=11; else if (tm->hour || tm->minute || tm->second || tm->day) - length=10; + length=8; else length=0; buff[0]=(char) length; // Length is stored first return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC); } + +#if 0 +bool Protocol_prep::send_fields(List<Item> *list, uint flag) +{ + return prepare_for_send(list); +}; +#endif diff --git a/sql/set_var.cc b/sql/set_var.cc index 63c77f8de2a..a067bab01d7 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -21,6 +21,8 @@ - If the variable is thread specific, add it to 'system_variables' struct. If not, add it to mysqld.cc and an declaration in 'mysql_priv.h' + - Don't forget to initialize new fields in global_system_variables and + max_system_variables! - Use one of the 'sys_var... classes from set_var.h or write a specific one for the variable type. - Define it in the 'variable definition list' in this file. @@ -154,6 +156,8 @@ sys_var_thd_ulong sys_max_error_count("max_error_count", &SV::max_error_count); sys_var_thd_ulong sys_max_heap_table_size("max_heap_table_size", &SV::max_heap_table_size); +sys_var_thd_ulong sys_pseudo_thread_id("pseudo_thread_id", + &SV::pseudo_thread_id); sys_var_thd_ha_rows sys_max_join_size("max_join_size", &SV::max_join_size, fix_max_join_size); @@ -364,6 +368,7 @@ sys_var *sys_variables[]= &sys_net_retry_count, &sys_net_wait_timeout, &sys_net_write_timeout, + &sys_pseudo_thread_id, &sys_query_cache_size, #ifdef HAVE_QUERY_CACHE &sys_query_cache_limit, @@ -512,6 +517,7 @@ struct show_var_st init_vars[]= { {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"port", (char*) &mysql_port, SHOW_INT}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, + {sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS}, {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index c70ac9ccf57..a1b506f1ff5 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -7,7 +7,7 @@ dist-hook: done; \ sleep 1 ; touch $(srcdir)/*/errmsg.sys $(INSTALL_DATA) $(srcdir)/charsets/README $(distdir)/charsets - $(INSTALL_DATA) $(srcdir)/charsets/Index $(distdir)/charsets + $(INSTALL_DATA) $(srcdir)/charsets/Index.xml $(distdir)/charsets all: @AVAILABLE_LANGUAGES_ERRORS@ @@ -25,7 +25,7 @@ install-data-local: done $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/charsets $(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README - $(INSTALL_DATA) $(srcdir)/charsets/Index $(DESTDIR)$(pkgdatadir)/charsets/Index + $(INSTALL_DATA) $(srcdir)/charsets/Index.xml $(DESTDIR)$(pkgdatadir)/charsets/Index.xml $(INSTALL_DATA) $(srcdir)/charsets/*.conf $(DESTDIR)$(pkgdatadir)/charsets fix_errors: diff --git a/sql/share/charsets/Index b/sql/share/charsets/Index deleted file mode 100644 index b2d9fe3e2a1..00000000000 --- a/sql/share/charsets/Index +++ /dev/null @@ -1,70 +0,0 @@ -# sql/share/charsets/Index -# -# This file lists all of the available character sets. Please keep this -# file sorted by character set number. - - -big5 1 -czech 2 -dec8 3 -dos 4 -german1 5 -hp8 6 -koi8_ru 7 -latin1 8 -latin2 9 -swe7 10 -usa7 11 -ujis 12 -sjis 13 -cp1251 14 -danish 15 -hebrew 16 -tis620 18 -euc_kr 19 -estonia 20 -hungarian 21 -koi8_ukr 22 -# win1251ukr is depreciated. Use cp1251cias, cp1251csas or cp1251bin instead. -win1251ukr 23 -gb2312 24 -greek 25 -win1250 26 -croat 27 -gbk 28 -# cp1257 is depreciated. -# Use cp1257ltlvciai, cp1257ltlvcsas, cp1257bin, cp1257ltlvcias instead -cp1257 29 -latin5 30 -latin1_de 31 -armscii8 32 -utf8 33 -win1250ch 34 - -ucs2 35 -cp866 36 -keybcs2 37 - -macce 38 -macroman 39 - -pclatin2 40 -latvian 41 -latvian1 42 -maccebin 43 -macceciai 44 -maccecias 45 -maccecsas 46 -latin1bin 47 -latin1cias 48 -latin1csas 49 -cp1251bin 50 -cp1251cias 51 -cp1251csas 52 -macromanbin 53 -macromancias 54 -macromanciai 55 -macromancsas 56 -cp1256 57 - -binary 63 diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml new file mode 100644 index 00000000000..9dd8b43f0b4 --- /dev/null +++ b/sql/share/charsets/Index.xml @@ -0,0 +1,455 @@ +<?xml version='1.0' encoding="utf-8"?> + +<charsets max-id=63> + +<description> +This file lists all of the available character sets. +To make maintaining easier please: + - keep records sorted by collation number. + - change charset-list.max-id when adding a new collation. +</description> + +<charset name="big5"> + <family>Traditional Chinese</family> + <alias>big-5</alias> + <alias>bigfive</alias> + <alias>big-five</alias> + <alias>cn-big5</alias> + <alias>csbig5</alias> + <collation name="big5" id="1" order="Chinese" flag="primary" flag="compiled"/> +</charset> + +<charset name="latin2"> + <family>Central European</family> + <alias>csisolatin2</alias> + <alias>iso-8859-2</alias> + <alias>iso-ir-101</alias> + <alias>iso_8859-2</alias> + <alias>iso_8859-2:1987</alias> + <alias>l2</alias> + <collation name="czech" id="2" order="Czech" flag="compiled"/> + <collation name="latin2" id="9" flag="primary"> + <order>Hungarian</order> + <order>Polish</order> + <order>Romanian</order> + <order>Croatian</order> + <order>Slovak</order> + <order>Slovenian</order> + <order>Sorbian</order> + </collation> + <collation name="hungarian" id="21" order="Hungarian"/> + <collation name="croat" id="27" order="Croatian"/> +</charset> + +<charset name="dec8"> + <family>Western</family> + <collation name="dec8" id="3" flag="primary"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> +</charset> + +<charset name="pclatin1"> + <family>Western</family> + <alias>850</alias> + <alias>cp850</alias> + <alias>cspc850multilingual</alias> + <alias>ibm850</alias> + <collation name="dos" id="4" flag="primary"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> +</charset> + +<charset name="latin1"> + <family>Western</family> + <alias>csisolatin1</alias> + <alias>csisolatin1</alias> + <alias>iso-8859-1</alias> + <alias>iso-ir-100</alias> + <alias>iso_8859-1</alias> + <alias>iso_8859-1:1987</alias> + <alias>l1</alias> + <alias>latin1</alias> + <collation name="german1" id="5" order="German Duden"/> + <collation name="latin1" id="8" order="Finnish, Swedish" flag="primary"/> + <collation name="danish" id="15" order="Danish"/> + <collation name="latin1_de" id="31" order="German DIN" flag="compiled"/> + <collation name="latin1_bin" id="47" order="Binary"/> + <collation name="latin1_ci_as" id="48"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> + <collation name="latin1_cs_as" id="49"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> +</charset> + +<charset name="hp8"> + <family>Western</family> + <alias>hproman8</alias> + <collation name="hp8" id="6" flag="primary"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> +</charset> + +<charset name="koi8_ru"> + <family>Cyrillic</family> + <alias>koi8-ru</alias> + <alias>cskoi8r</alias> + <collation name="koi8_ru" id="7" order="Russian" flag="primary"/> +</charset> + +<charset name="swe7"> + <family>Western</family> + <alias>iso-646-se</alias> + <collation name="swe7" id="10" order="Swedish" flag="primary"/> +</charset> + +<charset name="ascii"> + <family>Western</family> + <alias>us</alias> + <alias>us-ascii</alias> + <alias>csascii</alias> + <alias>iso-ir-6</alias> + <alias>iso646-us</alias> + <collation name="usa7" id="11" order="Egnlish" flag="primary"/> +</charset> + +<charset name="ujis"> + <family>Japanese</family> + <alias>euc-jp</alias> + <collation name="ujis" id="12" order="Japanese" flag="primary"/> +</charset> + +<charset name="sjis"> + <family>Japanese</family> + <alias>s-jis</alias> + <alias>shift-jis</alias> + <alias>x-sjis</alias> + <collation name="sjis" id="13" order="Japanese" flag="primary"/> +</charset> + +<charset name="cp1251"> + <family>Cyrillic</family> + <alias>windows-1251</alias> + <alias>ms-cyr</alias> + <alias>ms-cyrillic</alias> + <collation name="cp1251" id="14" flag="primary"> + <order>Belarusian</order> + <order>Bulgarian</order> + <order>Macedonian</order> + <order>Russian</order> + <order>Serbian</order> + <order>Mongolian</order> + <order>Ukrainian</order> + </collation> + <collation name="win1251ukr" id="23" order="<Depreciated>"/> + <collation name="cp1251_bin" id="50" order="Binary"/> + <collation name="cp1251_ci_as" id="51"> + <order>Belarusian</order> + <order>Bulgarian</order> + <order>Macedonian</order> + <order>Russian</order> + <order>Serbian</order> + <order>Mongolian</order> + <order>Ukrainian</order> + </collation> + <collation name="cp1251_cs_as" id="52"> + <order>Belarusian</order> + <order>Bulgarian</order> + <order>Macedonian</order> + <order>Russian</order> + <order>Serbian</order> + <order>Mongolian</order> + <order>Ukrainian</order> + </collation> +</charset> + +<charset name="hebrew"> + <family>Hebrew</family> + <alias>csisolatinhebrew</alias> + <alias>iso-8859-8</alias> + <alias>iso-ir-138</alias> + <collation name="hebrew" id="16" order="Hebrew" flag="primary"/> +</charset> + +<charset name="tis620"> + <family>Thai</family> + <alias>tis-620</alias> + <collation name="tis620" id="18" order="Thai" flag="primary" flag="compiled"/> +</charset> + +<charset name="euc_kr"> + <family>Korean</family> + <alias>euckr</alias> + <alias>euc-kr</alias> + <collation name="euc_kr" id="19" order="Korean" flag="primary" flag="compiled"/> +</charset> + +<charset name="latin7"> + <family>Baltic</family> + <alias>BalticRim</alias> + <alias>iso-8859-13</alias> + <alias>l7</alias> + <collation name="estonia" id="20" order="Estonian" flag="primary"/> + <collation name="latvian" id="41" order="Latvian"/> + <collation name="latvian1" id="42" order="Latvian"/> +</charset> + +<charset name="koi8_ukr"> + <family>Cyrillic</family> + <alias>koi8-u</alias> + <collation name="koi8_ukr" id="22" order="Ukranian" flag="primary"/> +</charset> + +<charset name="gb2312"> + <family>Simplified Chinese</family> + <alias>chinese</alias> + <alias>iso-ir-58</alias> + <collation name="gb2312" id="24" order="Chinese" flag="primary" flag="compiled"/> +</charset> + +<charset name="greek"> + <family>Greek</family> + <alias>csisolatingreek</alias> + <alias>ecma-118</alias> + <alias>greek8</alias> + <alias>iso-8859-7</alias> + <alias>iso-ir-126</alias> + <collation name="greek" id="25" order="Greek" flag="primary"/> +</charset> + +<charset name="cp1250"> + <family>Central European</family> + <alias>ms-ce</alias> + <alias>windows-1250</alias> + <collation name="win1250" id="26" flag="primary"> + <order>Hungarian</order> + <order>Polish</order> + <order>Romanian</order> + <order>Croatian</order> + <order>Slovak</order> + <order>Slovenian</order> + <order>Sorbian</order> + </collation> + <collation name="win1250ch" id="34" order="Czech"/> +</charset> + +<charset name="gbk"> + <family>East Asian</family> + <alias>cp936</alias> + <collation name="gbk" id="28" order="Chinese" flag="primary" flag="compiled"/> +</charset> + +<charset name="cp1257"> + <family>Baltic</family> + <alias>WinBaltRim</alias> + <alias>windows-1257</alias> + <collation name="cp1257" id="29" order="<Depreciated>"/> + <collation name="cp1257_bin" id="58" order="Binary"/> + <collation name="cp1257_ci_ai" id="59" flag="primary"> + <order>Latvian</order> + <order>Lithuanian</order> + </collation> + <collation name="cp1257_ci_as" id="60"> + <order>Latvian</order> + <order>Lithuanian</order> + </collation> + <collation name="cp1257_cs_as" id="61"> + <order>Latvian</order> + <order>Lithuanian</order> + </collation> +</charset> + +<charset name="latin5"> + <family>South Asian</family> + <alias>csisolatin5</alias> + <alias>iso-8859-9</alias> + <alias>iso-ir-148</alias> + <alias>l5</alias> + <alias>latin5</alias> + <alias>turkish</alias> + <collation name="latin5" id="30" order="Turkish" flag="primary"/> +</charset> + +<charset name="armscii8"> + <family>South Asian</family> + <alias>armscii-8</alias> + <collation name="armscii8" id="32" order="Armenian" flag="primary"/> +</charset> + +<charset name="utf8"> + <family>Unicode</family> + <alias>utf-8</alias> + <collation name="utf8" id="33" flag="primary"/> +</charset> + +<charset name="ucs2"> + <family>Unicode</family> + <collation name="ucs2" id="35" flag="primary"/> +</charset> + +<charset name="cp866"> + <family>Cyrillic</family> + <alias>866</alias> + <alias>csibm866</alias> + <alias>ibm866</alias> + <collation name="cp866" id="36" order="Russian" flag="primary"/> +</charset> + +<charset name="keybcs2"> + <family>Central European</family> + <collation name="keybcs2" id="37" order="Czech" flag="primary"/> +</charset> + +<charset name="MacCE"> + <family>Central European</family> + <alias>MacCentralEurope</alias> + <collation name="macce" id="38" flag="primary"> + <order>Hungarian</order> + <order>Polish</order> + <order>Romanian</order> + <order>Croatian</order> + <order>Slovak</order> + <order>Slovenian</order> + <order>Sorbian</order> + </collation> + <collation name="macce_bin" id="43" order="Binary"/> + <collation name="macce_ci_ai" id="44"> + <order>Hungarian</order> + <order>Polish</order> + <order>Romanian</order> + <order>Croatian</order> + <order>Slovak</order> + <order>Slovenian</order> + <order>Sorbian</order> + </collation> + <collation name="macce_ci_as" id="45"> + <order>Hungarian</order> + <order>Polish</order> + <order>Romanian</order> + <order>Croatian</order> + <order>Slovak</order> + <order>Slovenian</order> + <order>Sorbian</order> + </collation> + <collation name="macce_cs_as" id="46"> + <order>Hungarian</order> + <order>Polish</order> + <order>Romanian</order> + <order>Croatian</order> + <order>Slovak</order> + <order>Slovenian</order> + <order>Sorbian</order> + </collation> +</charset> + +<charset name="MacRoman"> + <family>Western</family> + <alias>Mac</alias> + <alias>Macintosh</alias> + <alias>csmacintosh</alias> + <collation name="macroman" id="39" flag="primary"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> + <collation name="macroman_bin" id="53" order="Binary"/> + <collation name="macroman_ci_as" id="54"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> + <collation name="macroman_ci_ai" id="55"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> + <collation name="macroman_cs_as" id="56"> + <order>Dutch</order> + <order>English</order> + <order>French</order> + <order>German Duden</order> + <order>Italian</order> + <order>Latin</order> + <order>Pogtuguese</order> + <order>Spanish</order> + </collation> +</charset> + +<charset name="pclatin2"> + <family>Central European</family> + <alias>852</alias> + <alias>cp852</alias> + <alias>ibm852</alias> + <collation name="pclatin2" id="40" flag="primary"> + <order>Hungarian</order> + <order>Polish</order> + <order>Romanian</order> + <order>Croatian</order> + <order>Slovak</order> + <order>Slovenian</order> + <order>Sorbian</order> + </collation> +</charset> + +<charset name="cp1256"> + <family>Arabic</family> + <alias>ms-arab</alias> + <alias>windows-1256</alias> + <collation name="cp1256" id="57" order="Arabic" flag="primary"/> +</charset> + +<charset name="binary"> + <collation name="binary" id="63" order="Binary" flag="primary" flag="compiled"/> +</charset> + +</charsets> diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index c1ee8b12e7f..6c3196bfeba 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -259,3 +259,4 @@ v/* "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 17c1dd76474..dcc016511dd 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -253,3 +253,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index a2ef2b0923d..6091616fc4a 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -261,3 +261,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 66d0996f2d6..465992e63b2 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -250,3 +250,4 @@ "Every derived table must have it's own alias", "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 367bda922f3..43eb5de89a5 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -255,3 +255,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 93009f564e6..d7bb19c2876 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -250,3 +250,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 24ee7a99409..765fbd875e2 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -260,3 +260,4 @@ "Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden.", "Select %u wurde während der Optimierung reduziert.", "Tabelle '%-.64s', die in einem der SELECT-Befehle verwendet wurde kann nicht in %-.32s verwendet werden." +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index ffed9111859..8831d4e47b9 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -250,3 +250,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index a597e3870b5..8d6c321d316 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -252,3 +252,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 5fd271f8941..451ad3e058b 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -250,3 +250,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index f339faf5fc4..70ab2d6d42d 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -252,3 +252,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 855f157d3b5..c18c3ed3873 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -250,3 +250,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index d930ec5ab74..9cd99613f52 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -252,3 +252,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 15bc59c39dc..32fe6c30b34 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -252,3 +252,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 95315516cda..4b59a62f991 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -254,3 +254,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 47dc0ed569d..7236bd86652 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -250,3 +250,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 722efe4f83f..0b8bbe1c219 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -254,3 +254,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index ddbb5bdbe5d..2f1eedd207c 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -253,3 +253,4 @@ "Every derived table must have it's own alias" "Select %u ÂÙÌ ÕÐÒÁÚÄÎÅÎ × ÐÒÏÃÅÓÓÅ ÏÐÔÉÍÉÚÁÃÉÉ", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index c9ab4d8f656..75cfd73f3f0 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -246,3 +246,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 0d6a847a341..de354f234c7 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -258,3 +258,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index cc56e1f6aef..a528c3e6b36 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -251,3 +251,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index b792864b9f4..5473f4e8e42 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -250,3 +250,4 @@ "Every derived table must have it's own alias" "Select %u was reduced during optimisation", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 2b6825adb8a..0b91786d1f3 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -255,3 +255,4 @@ "Every derived table must have it's own alias" "Select %u was ÓËÁÓÏ×ÁÎÏ ÐÒÉ ÏÐÔÉÍiÚÁÃii", "Table '%-.64s' from one of SELECT's can not be used in %-.32s" +"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
\ No newline at end of file diff --git a/sql/spatial.cc b/sql/spatial.cc index 1e2b9f1c512..5c6be3c221c 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -506,7 +506,7 @@ int GPolygon::get_data_as_text(String *txt) const for (; n_linear_rings>0; --n_linear_rings) { - if(no_data(data, 4)) + if (no_data(data, 4)) return 1; uint32 n_points = uint4korr(data); data += 4; @@ -593,7 +593,7 @@ int GPolygon::area(double *ar) const data += (8+8); } lr_area=fabs(lr_area)/2; - if(result==-1) result=lr_area; + if (result==-1) result=lr_area; else result-=lr_area; } *ar=fabs(result); @@ -1344,7 +1344,7 @@ int GGeometryCollection::get_mbr(MBR *mbr) const data += 4; for (; n_objects>0; --n_objects) { - if(no_data(data, WKB_HEADER_SIZE)) + if (no_data(data, WKB_HEADER_SIZE)) return 1; uint32 wkb_type = uint4korr(data + sizeof(char)); data += WKB_HEADER_SIZE; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 87cc0d616a9..08016d2df8c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -554,7 +554,7 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) uint key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1; TABLE *table,**prev; - int4store(key+key_length,thd->slave_proxy_id); + int4store(key+key_length,thd->variables.pseudo_thread_id); key_length += 4; prev= &thd->temporary_tables; @@ -594,7 +594,7 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *db, (strmov((table->real_name=strmov(table->table_cache_key=key, db)+1), table_name) - table->table_cache_key)+1; - int4store(key+table->key_length,thd->slave_proxy_id); + int4store(key+table->key_length,thd->variables.pseudo_thread_id); table->key_length += 4; return 0; } @@ -748,7 +748,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, if (thd->killed) DBUG_RETURN(0); key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1; - int4store(key + key_length, thd->slave_proxy_id); + int4store(key + key_length, thd->variables.pseudo_thread_id); for (table=thd->temporary_tables; table ; table=table->next) { @@ -762,6 +762,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, DBUG_RETURN(0); } table->query_id=thd->query_id; + thd->lex.tmp_table_used= 1; goto reset; } } @@ -1562,7 +1563,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, +1), table_name) - tmp_table->table_cache_key)+1; int4store(tmp_table->table_cache_key + tmp_table->key_length, - thd->slave_proxy_id); + thd->variables.pseudo_thread_id); tmp_table->key_length += 4; if (link_in_list) @@ -1654,6 +1655,7 @@ const Field *not_found_field= (Field*) 0x1; thd - pointer to current thread structure item - field item that should be found tables - tables for scaning + where - table where field found will be returned via this parameter report_error - if FALSE then do not report error if item not found and return not_found_field; @@ -1667,7 +1669,7 @@ const Field *not_found_field= (Field*) 0x1; Field * find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, - bool report_error) + TABLE_LIST **where, bool report_error) { Field *found=0; const char *db=item->db_name; @@ -1688,6 +1690,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, grant_option && !thd->master_access,1); if (find) { + (*where)= tables; if (find == WRONG_GRANT) return (Field*) 0; if (db || !thd->where) @@ -1707,7 +1710,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, if (!found_table && report_error) { char buff[NAME_LEN*2+1]; - if (db) + if (db && db[0]) { strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); table_name=buff; @@ -1735,6 +1738,14 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, bool allow_rowid= tables && !tables->next; // Only one table for (; tables ; tables=tables->next) { + if (!tables->table) + { + if (report_error) + my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), + item->full_name(),thd->where); + return (Field*) not_found_field; + } + Field *field=find_field_in_table(thd,tables->table,name,length, grant_option && !thd->master_access, allow_rowid); @@ -1742,6 +1753,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, { if (field == WRONG_GRANT) return (Field*) 0; + (*where)= tables; if (found) { if (!thd->where) // Returns first found diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index aa0f5824b4e..1cfbbf74da6 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1062,6 +1062,8 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used, for (; tables_used; tables_used=tables_used->next) { DBUG_ASSERT(!using_transactions || tables_used->table!=0); + if (tables_used->derived) + continue; if (using_transactions && tables_used->table->file->has_transactions()) /* diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ef40ebeb273..3ca1f4827ff 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -100,7 +100,7 @@ THD::THD():user_time(0), fatal_error(0), start_time=(time_t) 0; current_linfo = 0; slave_thread = 0; - slave_proxy_id = 0; + variables.pseudo_thread_id= 0; file_id = 0; cond_count=0; warn_id= 0; @@ -917,10 +917,10 @@ select_subselect::select_subselect(Item_subselect *item) this->item=item; } -bool select_singleval_subselect::send_data(List<Item> &items) +bool select_singlerow_subselect::send_data(List<Item> &items) { - DBUG_ENTER("select_singleval_subselect::send_data"); - Item_singleval_subselect *it= (Item_singleval_subselect *)item; + DBUG_ENTER("select_singlerow_subselect::send_data"); + Item_singlerow_subselect *it= (Item_singlerow_subselect *)item; if (it->assigned()) { my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0)); @@ -932,32 +932,9 @@ bool select_singleval_subselect::send_data(List<Item> &items) DBUG_RETURN(0); } List_iterator_fast<Item> li(items); - Item *val_item= li++; // Only one (single value subselect) - /* - Following val() call have to be first, because function AVG() & STD() - calculate value on it & determinate "is it NULL?". - */ - it->real_value= val_item->val_result(); - if ((it->null_value= val_item->null_value)) - { - it->reset(); - } - else - { - it->max_length= val_item->max_length; - it->decimals= val_item->decimals; - it->set_charset(val_item->charset()); - it->int_value= val_item->val_int_result(); - String *s= val_item->str_result(&it->string_value); - if (s != &it->string_value) - { - it->string_value.set(*s, 0, s->length()); - } - // TODO: remove when correct charset handling appeared for Item - it->str_value.set(*s, 0, s->length()); // store charset - - it->res_type= val_item->result_type(); - } + Item *val_item; + for (uint i= 0; (val_item= li++); i++) + it->store(i, val_item); it->assigned(1); DBUG_RETURN(0); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 7cf822585c9..a053db72e64 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -370,6 +370,12 @@ struct system_variables ulong tmp_table_size; ulong tx_isolation; + /* + In slave thread we need to know in behalf of which + thread the query is being run to replicate temp tables properly + */ + ulong pseudo_thread_id; + my_bool log_warnings; my_bool low_priority_updates; @@ -525,11 +531,6 @@ public: each thread that is using LOG_INFO needs to adjust the pointer to it */ LOG_INFO* current_linfo; - /* - In slave thread we need to know in behalf of which - thread the query is being run to replicate temp tables properly - */ - ulong slave_proxy_id; NET* slave_net; // network connection from slave -> m. my_off_t log_pos; /* Used by the sys_var class to store temporary values */ @@ -824,10 +825,10 @@ public: }; /* Single value subselect interface class */ -class select_singleval_subselect :public select_subselect +class select_singlerow_subselect :public select_subselect { public: - select_singleval_subselect(Item_subselect *item):select_subselect(item){} + select_singlerow_subselect(Item_subselect *item):select_subselect(item){} bool send_data(List<Item> &items); }; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index f7d845e9e36..1ddaedeb480 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -63,6 +63,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) TMP_TABLE_PARAM tmp_table_param; bool is_union=sl->next_select() && sl->next_select()->linkage == UNION_TYPE; DBUG_ENTER("mysql_derived"); + SELECT_LEX_NODE *save_current_select= lex->current_select; /* @@ -111,6 +112,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) } } + lex->current_select= sl; if (setup_fields(thd,tables,item_list,0,0,1)) { res=-1; @@ -119,7 +121,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count=item_list.elements; if (!(table=create_tmp_table(thd, &tmp_table_param, item_list, - (ORDER*) 0, is_union && !unit->union_option, 1, + (ORDER*) 0, + is_union && !unit->union_option, 1, (sl->options | thd->options | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR))) @@ -138,8 +141,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) if (unit->select_limit_cnt == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; - SELECT_LEX_NODE *save_current_select= lex->current_select; - lex->current_select= sl; if (is_union) res=mysql_union(thd,lex,derived_result,unit); else @@ -149,7 +150,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) sl->having, (ORDER*) NULL, sl->options | thd->options | SELECT_NO_UNLOCK, derived_result, unit, sl, 0); - lex->current_select= save_current_select; if (!res) { @@ -168,14 +168,9 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) tables->table_list->table=tables->table; // to fix a problem in EXPLAIN } else - { - if (is_union) - unit->exclude(); - else - sl->exclude(); - } + unit->exclude(); t->db=(char *)""; - t->derived=(SELECT_LEX *)0; // just in case ... + t->derived=(SELECT_LEX *)1; // just in case ... table->file->info(HA_STATUS_VARIABLE); } } @@ -184,6 +179,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) if (res) free_tmp_table(thd,table); exit: + lex->current_select= save_current_select; close_thread_tables(thd); } DBUG_RETURN(res); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 5d12f023842..013101a0ecc 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -96,7 +96,7 @@ int search_functions(MI_INFO *file_leafs, const char *mask, DBUG_ENTER("search_functions"); int count= 0; - if(mi_scan_init(file_leafs)) + if (mi_scan_init(file_leafs)) DBUG_RETURN(-1); help_leaf leaf; @@ -191,7 +191,7 @@ int search_categories(THD *thd, if (!(file_categories= open_help_file(thd,"function_category_name"))) DBUG_RETURN(-1); - if(mi_scan_init(file_categories)) + if (mi_scan_init(file_categories)) { mi_close(file_categories); DBUG_RETURN(-1); @@ -393,11 +393,11 @@ int mysqld_help(THD *thd, const char *mask) description->ptr(), example->ptr()))) goto end; } - else if((res= send_header_2(protocol)) || - (res= send_variant_2_list(protocol,&function_list,false)) || - (search_categories(thd, mask, &categories_list, 0)<0 && - (res=1)) || - (res= send_variant_2_list(protocol,&categories_list,true))) + else if ((res= send_header_2(protocol)) || + (res= send_variant_2_list(protocol,&function_list,false)) || + (search_categories(thd, mask, &categories_list, 0)<0 && + (res=1)) || + (res= send_variant_2_list(protocol,&categories_list,true))) { goto end; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ddbb562bdca..c7595c7ec5c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -171,6 +171,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->slave_thd_opt=0; lex->sql_command=SQLCOM_END; lex->safe_to_cache_query= 1; + lex->tmp_table_used= 0; bzero(&lex->mi,sizeof(lex->mi)); return lex; } @@ -1036,7 +1037,7 @@ void st_select_lex_node::include_global(st_select_lex_node **plink) //excluding from global list (internal function) void st_select_lex_node::fast_exclude() { - if(link_prev) + if (link_prev) { if ((*link_prev= link_next)) link_next->link_prev= link_prev; @@ -1068,7 +1069,7 @@ void st_select_lex_node::exclude() void st_select_lex_unit::exclude_level() { SELECT_LEX_UNIT *units= 0, **units_last= &units; - for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { if (sl->link_prev && (*sl->link_prev= sl->link_next)) sl->link_next->link_prev= sl->link_prev; @@ -1142,7 +1143,7 @@ void st_select_lex_node::mark_as_dependent(SELECT_LEX *last) for (SELECT_LEX_NODE *s= this; s &&s != last; s= s->outer_select()) - if( !s->dependent ) + if ( !s->dependent ) { // Select is dependent of outer select s->dependent= 1; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6e5fd6765fb..9b8f4a47515 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -461,6 +461,7 @@ typedef struct st_lex uint slave_thd_opt; CHARSET_INFO *charset; char *help_arg; + bool tmp_table_used; } LEX; diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 6eb4fbcaaf6..1f22073f556 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -62,7 +62,7 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new List_iterator<Item> list_it(select_lex->item_list); List_iterator<Item> new_it(new_fields); - while((item=list_it++)) + while ((item=list_it++)) { bool not_found=true; if (item->type()==Item::FIELD_ITEM) @@ -109,15 +109,15 @@ static int olap_combos(List<Item> old_fields, List<Item> new_fields, Item *item int num_new_fields) { int sl_return = 0; - if(position == num_new_fields) + if (position == num_new_fields) { - if(item) + if (item) new_fields.push_front(item); sl_return = make_new_olap_select(lex, select_lex, new_fields); } else { - if(item) + if (item) new_fields.push_front(item); while ((num_fields - num_new_fields >= selection - position) && !sl_return) { @@ -170,12 +170,12 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) if (select_lex->olap == CUBE_TYPE) { - for( int i=count-1; i>=0 && !sl_return; i--) + for ( int i=count-1; i>=0 && !sl_return; i--) sl_return=olap_combos(item_list_copy, new_item_list, (Item *)0, lex, select_lex, 0, 0, count, i); } else if (select_lex->olap == ROLLUP_TYPE) { - for( int i=count-1; i>=0 && !sl_return; i--) + for ( int i=count-1; i>=0 && !sl_return; i--) { Item *item; item_list_copy.pop(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 85658a93791..b47ce194a57 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -189,9 +189,9 @@ end: static int check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count, - bool do_send_error, char* crypted_scramble, - bool had_password,uint *cur_priv_version, - ACL_USER** hint_user) + bool simple_connect, bool do_send_error, + char* crypted_scramble, bool had_password, + uint *cur_priv_version, ACL_USER** hint_user) { thd->db=0; thd->db_length=0; @@ -222,14 +222,23 @@ static int check_user(THD *thd,enum_server_command command, const char *user, { if (do_send_error) { - net_printf(thd, ER_ACCESS_DENIED_ERROR, - thd->user, - thd->host_or_ip, - had_password ? ER(ER_YES) : ER(ER_NO)); - mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), - thd->user, - thd->host_or_ip, - had_password ? ER(ER_YES) : ER(ER_NO)); + /* Old client should get nicer error message if password version is not supported*/ + if (simple_connect && *hint_user && (*hint_user)->pversion) + { + net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE); + mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE)); + } + else + { + net_printf(thd, ER_ACCESS_DENIED_ERROR, + thd->user, + thd->host_or_ip, + had_password ? ER(ER_YES) : ER(ER_NO)); + mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), + thd->user, + thd->host_or_ip, + had_password ? ER(ER_YES) : ER(ER_NO)); + } return(1); // Error already given } else @@ -640,8 +649,9 @@ check_connections(THD *thd) /* Store information if we used password. passwd will be dammaged */ bool using_password=test(passwd[0]); /* Check user permissions. If password failure we'll get scramble back */ - if (check_user(thd,COM_CONNECT, user, passwd, db, 1, simple_connect, - prepared_scramble,using_password,&cur_priv_version,&cached_user)<0) + if (check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect, + simple_connect, prepared_scramble, using_password, &cur_priv_version, + &cached_user)<0) { /* If The client is old we just have to return error */ if (simple_connect) @@ -681,7 +691,7 @@ check_connections(THD *thd) } /* Final attempt to check the user based on reply */ if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos, - tmp_db, 1, 1,prepared_scramble,using_password,&cur_priv_version, + tmp_db, 1, 0, 1, prepared_scramble, using_password, &cur_priv_version, &cached_user)) return -1; } @@ -1085,7 +1095,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Do not retry if we already have sent error (result>0) */ if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect, - prepared_scramble,using_password,&cur_priv_version,&cached_user)<0) + simple_connect, prepared_scramble, using_password, &cur_priv_version, + &cached_user)<0) { /* If The client is old we just have to have auth failure */ if (simple_connect) @@ -1120,7 +1131,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Final attempt to check the user based on reply */ if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*)net->read_pos, - tmp_db, 0, 1,prepared_scramble,using_password,&cur_priv_version, + tmp_db, 0, 0, 1, prepared_scramble, using_password, &cur_priv_version, &cached_user)) goto restore_user; } @@ -1469,7 +1480,6 @@ mysql_execute_command(THD *thd) int res= 0; LEX *lex= &thd->lex; TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first; - TABLE_LIST *cursor; SELECT_LEX *select_lex= &lex->select_lex; SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_execute_command"); @@ -1607,7 +1617,14 @@ mysql_execute_command(THD *thd) break; } case SQLCOM_DO: - res=mysql_do(thd, *lex->insert_list); + if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) || + (res= open_and_lock_tables(thd,tables)))) + break; + + fix_tables_pointers(lex->all_selects_list); + res= mysql_do(thd, *lex->insert_list); + if (thd->net.report_error) + res= -1; break; case SQLCOM_EMPTY_QUERY: @@ -1813,7 +1830,6 @@ mysql_execute_command(THD *thd) } if (tables->next) { - TABLE_LIST *table; if (check_table_access(thd, SELECT_ACL, tables->next)) goto error; // Error message is given } @@ -1840,10 +1856,14 @@ mysql_execute_command(THD *thd) } else // regular create { - res = mysql_create_table(thd,tables->db ? tables->db : thd->db, - tables->real_name, &lex->create_info, - lex->create_list, - lex->key_list,0,0,0); // do logging + if (lex->name) + res= mysql_create_like_table(thd, tables, &lex->create_info, + (Table_ident *)lex->name); + else + res= mysql_create_table(thd,tables->db ? tables->db : thd->db, + tables->real_name, &lex->create_info, + lex->create_list, + lex->key_list,0,0,0); // do logging if (!res) send_ok(thd); } @@ -3034,6 +3054,7 @@ mysql_init_query(THD *thd) lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list); lex->olap=lex->describe=0; lex->derived_tables= false; + lex->lock_option=TL_READ; thd->check_loops_counter= thd->select_number= lex->select_lex.select_number= 1; thd->free_list= 0; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 704acc9c1c2..93004ce2937 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -440,10 +440,9 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, COND *conds) { THD *thd= stmt->thd; - TABLE *table; DBUG_ENTER("mysql_test_upd_fields"); - if (!(table = open_ltable(thd,table_list,table_list->lock_type))) + if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(1); if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) || @@ -477,13 +476,12 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, COND *conds, ORDER *order, ORDER *group, Item *having) { - TABLE *table; bool hidden_group_fields; THD *thd= stmt->thd; List<Item> all_fields(fields); DBUG_ENTER("mysql_test_select_fields"); - if (!(table = open_ltable(thd,tables,TL_READ))) + if (open_and_lock_tables(thd, tables)) DBUG_RETURN(1); thd->used_tables=0; // Updated by setup_fields @@ -512,7 +510,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, sending any info on where clause. */ if (send_prep_stmt(stmt, fields.elements) || - thd->protocol_prep.send_fields(&fields,0) || + thd->protocol_simple.send_fields(&fields,0) || send_item_params(stmt)) DBUG_RETURN(1); DBUG_RETURN(0); @@ -626,14 +624,17 @@ static bool parse_prepare_query(PREP_STMT *stmt, /* Initialize parameter items in statement */ -static bool init_param_items(THD *thd, PREP_STMT *stmt) + +static bool init_param_items( PREP_STMT *stmt) { + List<Item> ¶ms= stmt->thd->lex.param_list; Item_param **to; + if (!(stmt->param= to= (Item_param **) my_malloc(sizeof(Item_param *)*(stmt->param_count+1), MYF(MY_WME)))) return 1; - List_iterator<Item> param_iterator(thd->lex.param_list); + List_iterator<Item> param_iterator(params); while ((*(to++) = (Item_param *)param_iterator++)); return 0; } @@ -659,29 +660,32 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) DBUG_ENTER("mysql_stmt_prepare"); bzero((char*) &stmt, sizeof(stmt)); - stmt.thd= thd; + stmt.stmt_id= ++thd->current_stmt_id; init_sql_alloc(&stmt.mem_root, 8192, 8192); + + stmt.thd= thd; + stmt.thd->mem_root= stmt.mem_root; - thd->mem_root= stmt.mem_root; - if (alloc_query(thd, packet, packet_length)) + if (alloc_query(stmt.thd, packet, packet_length)) goto err; + if (parse_prepare_query(&stmt, thd->query, thd->query_length)) goto err; if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); - if (init_param_items(thd, &stmt)) + if (init_param_items(&stmt)) goto err; - stmt.mem_root= thd->mem_root; + stmt.mem_root= stmt.thd->mem_root; tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0); thd->mem_root= thd_root; // restore main mem_root DBUG_RETURN(0); err: - stmt.mem_root= thd->mem_root; + stmt.mem_root= stmt.thd->mem_root; free_prep_stmt(&stmt, free_free, (void*) 0); thd->mem_root = thd_root; // restore main mem_root DBUG_RETURN(1); @@ -727,9 +731,9 @@ void mysql_stmt_execute(THD *thd, char *packet) mysql_delete(), mysql_update() and mysql_select() to not to have re-check on setup_* and other things .. */ - thd->protocol= &thd->protocol_prep; // Switch to binary protocol + stmt->thd->protocol= &thd->protocol_prep; // Switch to binary protocol mysql_execute_command(stmt->thd); - thd->protocol= &thd->protocol_simple; // Use normal protocol + stmt->thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b6cc68477aa..b57e45a1a52 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1160,7 +1160,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, if (thd->possible_loops) { Item *item; - while(thd->possible_loops->elements) + while (thd->possible_loops->elements) { item= thd->possible_loops->pop(); if (item->check_loop(thd->check_loops_counter++)) @@ -7540,7 +7540,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, JOIN_TAB *tab=join->join_tab+i; TABLE *table=tab->table; char buff[512],*buff_ptr=buff; - char buff1[512], buff2[512], buff3[512]; + char buff1[512], buff2[512]; String tmp1(buff1,sizeof(buff1),default_charset_info); String tmp2(buff2,sizeof(buff2),default_charset_info); tmp1.length(0); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 41f2ab975f5..c66764d673f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -841,7 +841,6 @@ int mysqld_show_keys(THD *thd, TABLE_LIST *table_list) { TABLE *table; - char buff[256]; Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_keys"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, @@ -1113,8 +1112,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append(" USING BTREE", 12); // +BAR: send USING only in non-default case: non-spatial rtree - if((key_info->algorithm == HA_KEY_ALG_RTREE) && - !(key_info->flags & HA_SPATIAL)) + if ((key_info->algorithm == HA_KEY_ALG_RTREE) && + !(key_info->flags & HA_SPATIAL)) packet->append(" USING RTREE",12); packet->append(" (", 2); @@ -1330,7 +1329,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) time_t now= time(0); while ((thd_info=thread_infos.get())) { - char buff[20],*end; protocol->prepare_for_resend(); protocol->store((ulonglong) thd_info->thread_id); protocol->store(thd_info->user); @@ -1365,10 +1363,14 @@ int mysqld_show_charsets(THD *thd, const char *wild) List<Item> field_list; CHARSET_INFO **cs; Protocol *protocol= thd->protocol; + char flags[64]; + DBUG_ENTER("mysqld_show_charsets"); - field_list.push_back(new Item_empty_string("Name",30)); + field_list.push_back(new Item_empty_string("CS_Name",30)); + field_list.push_back(new Item_empty_string("COL_Name",30)); field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT)); + field_list.push_back(new Item_empty_string("Flags",30)); field_list.push_back(new Item_return_int("strx_maxlen",3, FIELD_TYPE_TINY)); field_list.push_back(new Item_return_int("mb_maxlen",3, FIELD_TYPE_TINY)); @@ -1377,14 +1379,17 @@ int mysqld_show_charsets(THD *thd, const char *wild) for (cs=all_charsets ; cs < all_charsets+255 ; cs++ ) { - if (!cs[0]) - continue; - if (!(wild && wild[0] && + if (cs[0] && !(wild && wild[0] && wild_case_compare(system_charset_info,cs[0]->name,wild))) { protocol->prepare_for_resend(); + protocol->store(cs[0]->csname); protocol->store(cs[0]->name); protocol->store_short((longlong) cs[0]->number); + flags[0]='\0'; + if (cs[0]->state & MY_CS_PRIMARY) + strcat(flags,"pri"); + protocol->store(flags); protocol->store_tiny((longlong) cs[0]->strxfrm_multiply); protocol->store_tiny((longlong) cs[0]->mbmaxlen); if (protocol->write()) @@ -1473,7 +1478,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, end= int10_to_str((long) thd->query_id, buff, 10); break; case SHOW_RPL_STATUS: - end= int10_to_str((long) rpl_status_type[(int)rpl_status], buff, 10); + end= strmov(buff, rpl_status_type[(int)rpl_status]); break; case SHOW_SLAVE_RUNNING: { diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 51b2386ae62..5b84b86c277 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -254,7 +254,7 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *from, CHARSET break; outp: - if((cnvres=to->wc_mb(to,wc,d,de)) >0 ) + if ((cnvres=to->wc_mb(to,wc,d,de)) >0 ) { d+=cnvres; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4848c374932..1f4657fb55f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -210,6 +210,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, wrong_tables.append(String(table->real_name,default_charset_info)); } } + thd->lex.tmp_table_used= tmp_table_deleted; if (some_tables_deleted || tmp_table_deleted) { query_cache_invalidate3(thd, tables, 0); @@ -418,7 +419,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, it.rewind(); while ((sql_field=it++)) { - if(!sql_field->charset) + if (!sql_field->charset) sql_field->charset = create_info->table_charset ? create_info->table_charset : thd->db_charset? thd->db_charset : @@ -834,6 +835,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, (void) rm_temporary_table(create_info->db_type, path); goto end; } + thd->lex.tmp_table_used= 1; } if (!tmp_table && !no_log) { @@ -1396,6 +1398,127 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) } +/* + Create a table identical to the specified table + + SYNOPSIS + mysql_create_like_table() + thd Thread object + table Table list (one table only) + create_info Create info + table_ident Src table_ident + + RETURN VALUES + 0 ok + -1 error +*/ + +int mysql_create_like_table(THD* thd, TABLE_LIST* table, + HA_CREATE_INFO *create_info, + Table_ident *table_ident) +{ + TABLE **tmp_table; + char src_path[FN_REFLEN], dst_path[FN_REFLEN]; + char *db= table->db; + char *table_name= table->real_name; + char *src_db= thd->db; + char *src_table= table_ident->table.str; + int err; + + DBUG_ENTER("mysql_create_like_table"); + + /* + Validate the source table + */ + if (table_ident->table.length > NAME_LEN || + (table_ident->table.length && + check_table_name(src_table,table_ident->table.length)) || + table_ident->db.str && check_db_name((src_db= table_ident->db.str))) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); + DBUG_RETURN(-1); + } + + if ((tmp_table= find_temporary_table(thd, src_db, src_table))) + strxmov(src_path, (*tmp_table)->path, reg_ext, NullS); + else + { + strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table, + reg_ext, NullS); + if (access(src_path, F_OK)) + { + my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table); + DBUG_RETURN(-1); + } + } + + /* + Validate the destination table + + skip the destination table name checking as this is already + validated. + */ + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + if (find_temporary_table(thd, db, table_name)) + goto table_exists; + sprintf(dst_path,"%s%s%lx_%lx_%x%s",mysql_tmpdir,tmp_file_prefix, + current_pid, thd->thread_id, thd->tmp_table++,reg_ext); + create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE; + } + else + { + strxmov(dst_path, mysql_data_home, "/", db, "/", table_name, + reg_ext, NullS); + if (!access(dst_path, F_OK)) + goto table_exists; + } + + /* + Create a new table by copying from source table + */ + if (my_copy(src_path, dst_path, MYF(MY_WME))) + DBUG_RETURN(-1); + + /* + As mysql_truncate don't work on a new table at this stage of + creation, instead create the table directly (for both normal + and temporary tables). + */ + *fn_ext(dst_path)= 0; + err= ha_create_table(dst_path, create_info, 1); + + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + { + if (err || !open_temporary_table(thd, dst_path, db, table_name, 1)) + { + (void) rm_temporary_table(create_info->db_type, + dst_path); /* purecov: inspected */ + DBUG_RETURN(-1); /* purecov: inspected */ + } + } + else if (err) + { + (void) quick_rm_table(create_info->db_type, db, + table_name); /* purecov: inspected */ + DBUG_RETURN(-1); /* purecov: inspected */ + } + DBUG_RETURN(0); + +table_exists: + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff,ER(ER_TABLE_EXISTS_ERROR),table_name); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TABLE_EXISTS_ERROR,warn_buff); + DBUG_RETURN(0); + } + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + DBUG_RETURN(-1); +} + + int mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) { #ifdef OS2 diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 3fbeaa753db..758778ecfa8 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -276,6 +276,7 @@ static void display_table_locks (void) VOID(pthread_mutex_unlock(&lock->mutex)); } VOID(pthread_mutex_unlock(&THR_LOCK_lock)); + uint i; if (!saved_table_locks.elements) goto end; qsort((gptr) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare); @@ -283,7 +284,7 @@ static void display_table_locks (void) puts("\nThread database.table_name Locked/Waiting Lock_type\n"); - for (uint i=0 ; i < saved_table_locks.elements ; i++) + for (i=0 ; i < saved_table_locks.elements ; i++) { TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*); printf("%-8ld%-28.28s%-22s%s\n", diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 51d43b41833..324befcb59e 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -33,6 +33,7 @@ #endif #include "mysql_priv.h" +#include <my_pthread.h> #ifdef HAVE_DLOPEN extern "C" @@ -70,7 +71,7 @@ extern "C" static bool initialized = 0; static MEM_ROOT mem; static HASH udf_hash; -static pthread_mutex_t THR_LOCK_udf; +static rw_lock_t THR_LOCK_udf; static udf_func *add_udf(char *name, Item_result ret, char *dl, @@ -122,8 +123,8 @@ void udf_init() if (initialized) DBUG_VOID_RETURN; - pthread_mutex_init(&THR_LOCK_udf,MY_MUTEX_INIT_SLOW); - + my_rwlock_init(&THR_LOCK_udf,NULL); + init_sql_alloc(&mem, 1024,0); THD *new_thd = new THD; if (!new_thd || @@ -262,7 +263,7 @@ static void del_udf(udf_func *udf) void free_udf(udf_func *udf) { DBUG_ENTER("free_udf"); - pthread_mutex_lock(&THR_LOCK_udf); + rw_wrlock(&THR_LOCK_udf); if (!--udf->usage_count) { /* @@ -274,7 +275,7 @@ void free_udf(udf_func *udf) if (!find_udf_dl(udf->dl)) dlclose(udf->dlhandle); } - pthread_mutex_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); DBUG_VOID_RETURN; } @@ -287,7 +288,7 @@ udf_func *find_udf(const char *name,uint length,bool mark_used) DBUG_ENTER("find_udf"); /* TODO: This should be changed to reader locks someday! */ - pthread_mutex_lock(&THR_LOCK_udf); + rw_rdlock(&THR_LOCK_udf); if ((udf=(udf_func*) hash_search(&udf_hash,(byte*) name, length ? length : (uint) strlen(name)))) { @@ -296,7 +297,7 @@ udf_func *find_udf(const char *name,uint length,bool mark_used) else if (mark_used) udf->usage_count++; } - pthread_mutex_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); DBUG_RETURN(udf); } @@ -375,7 +376,7 @@ int mysql_create_function(THD *thd,udf_func *udf) DBUG_RETURN(1); } - pthread_mutex_lock(&THR_LOCK_udf); + rw_wrlock(&THR_LOCK_udf); if ((hash_search(&udf_hash,(byte*) udf->name, udf->name_length))) { net_printf(thd, ER_UDF_EXISTS, udf->name); @@ -438,13 +439,13 @@ int mysql_create_function(THD *thd,udf_func *udf) del_udf(u_d); goto err; } - pthread_mutex_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); DBUG_RETURN(0); err: if (new_dl) dlclose(dl); - pthread_mutex_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); DBUG_RETURN(1); } @@ -460,7 +461,7 @@ int mysql_drop_function(THD *thd,const char *udf_name) send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); DBUG_RETURN(1); } - pthread_mutex_lock(&THR_LOCK_udf); + rw_wrlock(&THR_LOCK_udf); if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name, (uint) strlen(udf_name)))) { @@ -490,10 +491,10 @@ int mysql_drop_function(THD *thd,const char *udf_name) } close_thread_tables(thd); - pthread_mutex_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); DBUG_RETURN(0); err: - pthread_mutex_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); DBUG_RETURN(1); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 10175bfe345..cdd34977e5a 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -279,9 +279,10 @@ int st_select_lex_unit::exec() } if (!thd->fatal_error) // Check if EOM { - offset_limit_cnt= global_parameters->offset_limit; - select_limit_cnt= global_parameters->select_limit+ - global_parameters->offset_limit; + SELECT_LEX *sl=thd->lex.current_select->master_unit()->first_select(); + offset_limit_cnt= (sl->braces) ? global_parameters->offset_limit : 0; + select_limit_cnt= (sl->braces) ? global_parameters->select_limit+ + global_parameters->offset_limit : HA_POS_ERROR; if (select_limit_cnt < global_parameters->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit if (select_limit_cnt == HA_POS_ERROR) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e99f2a3b17c..bcee15c13cf 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -587,7 +587,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr using_list expr_or_default set_expr_or_default - param_marker singleval_subselect singleval_subselect_init + param_marker singlerow_subselect singlerow_subselect_init exists_subselect exists_subselect_init %type <item_list> @@ -835,6 +835,7 @@ create: lex->create_info.options=$2 | $4; lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type; lex->create_info.table_charset=thd->db_charset?thd->db_charset:default_charset_info; + lex->name=0; } create2 {} @@ -883,7 +884,13 @@ create: create2: '(' field_list ')' opt_create_table_options create3 {} | opt_create_table_options create3 {} - ; + | LIKE table_ident + { + LEX *lex=Lex; + if (!(lex->name= (char *)$2)) + YYABORT; + } + ; create3: /* empty */ {} @@ -1669,12 +1676,17 @@ select_init: '(' SELECT_SYM select_part2 ')' { LEX *lex= Lex; - SELECT_LEX_NODE * sel= lex->current_select; + SELECT_LEX * sel= lex->current_select->select_lex(); if (sel->set_braces(1)) { send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } + if (sel->linkage == UNION_TYPE && !sel->master_unit()->first_select()->braces) + { + send_error(lex->thd, ER_SYNTAX_ERROR); + YYABORT; + } /* select in braces, can't contain global parameters */ sel->master_unit()->global_parameters= sel->master_unit(); @@ -1684,11 +1696,17 @@ select_init2: select_part2 { LEX *lex= Lex; + SELECT_LEX * sel= lex->current_select->select_lex(); if (lex->current_select->set_braces(0)) { send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } + if (sel->linkage == UNION_TYPE && sel->master_unit()->first_select()->braces) + { + send_error(lex->thd, ER_SYNTAX_ERROR); + YYABORT; + } } union_clause ; @@ -1696,6 +1714,7 @@ select_init2: select_part2: { LEX *lex=Lex; + SELECT_LEX * sel= lex->current_select->select_lex(); if (lex->current_select == &lex->select_lex) lex->lock_option= TL_READ; /* Only for global SELECT */ mysql_init_select(lex); @@ -2018,7 +2037,7 @@ simple_expr: $$= new Item_row(*$5); } | EXISTS exists_subselect { $$= $2; } - | singleval_subselect { $$= $1; } + | singlerow_subselect { $$= $1; } | '{' ident expr '}' { $$= $3; } | MATCH ident_list_arg AGAINST '(' expr ')' { Select->add_ftfunc_to_list((Item_func_match *) @@ -2202,9 +2221,9 @@ simple_expr: | NOW_SYM '(' expr ')' { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;} | PASSWORD '(' expr ')' - { - $$= new Item_func_password($3); - } + { $$= new Item_func_password($3); } + | PASSWORD '(' expr ',' expr ')' + { $$= new Item_func_password($3,$5); } | POINTFROMTEXT '(' expr ')' { $$= new Item_func_geometry_from_text($3); } | POINTFROMTEXT '(' expr ',' expr ')' @@ -2510,7 +2529,9 @@ join_table: lex->current_select= unit->outer_select(); if (!($$= lex->current_select-> add_table_to_list(lex->thd, new Table_ident(unit), $5, 0, - lex->lock_option))) + TL_READ,(List<String> *)0, + (List<String> *)0))) + YYABORT; }; @@ -3188,16 +3209,16 @@ table_wild_list: | table_wild_list ',' table_wild_one {}; table_wild_one: - ident opt_wild + ident opt_wild opt_table_alias { - if (!Select->add_table_to_list(YYTHD, new Table_ident($1), NULL, 1, + if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3, 1, Lex->lock_option)) YYABORT; } - | ident '.' ident opt_wild + | ident '.' ident opt_wild opt_table_alias { if (!Select->add_table_to_list(YYTHD, new Table_ident($1, $3, 0), - NULL, 1, Lex->lock_option)) + $5, 1, Lex->lock_option)) YYABORT; } ; @@ -4488,17 +4509,17 @@ union_option: /* empty */ {} | ALL {Select->master_unit()->union_option= 1;}; -singleval_subselect: - subselect_start singleval_subselect_init +singlerow_subselect: + subselect_start singlerow_subselect_init subselect_end { $$= $2; }; -singleval_subselect_init: +singlerow_subselect_init: select_init2 { - $$= new Item_singleval_subselect(YYTHD, + $$= new Item_singlerow_subselect(YYTHD, Lex->current_select->master_unit()-> first_select()); }; diff --git a/sql/stacktrace.c b/sql/stacktrace.c index f5c0a59b572..762c45e7184 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -38,7 +38,7 @@ void safe_print_str(const char* name, const char* val, int max_len) } fprintf(stderr, "= "); - for(; max_len && PTR_SANE(val) && *val; --max_len) + for (; max_len && PTR_SANE(val) && *val; --max_len) fputc(*val++, stderr); fputc('\n', stderr); } @@ -59,7 +59,7 @@ void safe_print_str(const char* name, const char* val, int max_len) inline uchar** find_prev_fp(uint32* pc, uchar** fp) { int i; - for(i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) + for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) { uchar* p = (uchar*)pc; if (p[2] == 222 && p[3] == 35) @@ -73,7 +73,7 @@ inline uchar** find_prev_fp(uint32* pc, uchar** fp) inline uint32* find_prev_pc(uint32* pc, uchar** fp) { int i; - for(i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) + for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) { char* p = (char*)pc; if (p[1] == 0 && p[2] == 94 && p[3] == -73) diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 573c3c67db0..74ff300c9e9 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -6219,6 +6219,7 @@ CHARSET_INFO my_charset_big5 = { 1, /* number */ MY_CS_COMPILED, /* state */ + "big5", /* cs name */ "big5", /* name */ "", /* comment */ ctype_big5, diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 7848862a0db..377e50f3dab 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -260,6 +260,7 @@ static CHARSET_INFO my_charset_bin_st = { 63, /* number */ MY_CS_COMPILED|MY_CS_BINSORT,/* state */ + "binary", /* cs name */ "binary", /* name */ "", /* comment */ ctype_bin, /* ctype */ diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c index d309ddc80c8..bb0afe98032 100644 --- a/strings/ctype-czech.c +++ b/strings/ctype-czech.c @@ -597,6 +597,7 @@ CHARSET_INFO my_charset_czech = { 2, /* number */ MY_CS_COMPILED, /* state */ + "latin2", /* cs name */ "czech", /* name */ "", /* comment */ ctype_czech, diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index 2fe8db85369..6388d4b062f 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8637,6 +8637,7 @@ CHARSET_INFO my_charset_euc_kr = { 19, /* number */ MY_CS_COMPILED, /* state */ + "euc_kr", /* cs name */ "euc_kr", /* name */ "", /* comment */ ctype_euc_kr, diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index c06b70011df..77a55f6dadc 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5687,6 +5687,7 @@ CHARSET_INFO my_charset_gb2312 = { 24, /* number */ MY_CS_COMPILED, /* state */ + "gb2312", /* cs name */ "gb2312", /* name */ "", /* comment */ ctype_gb2312, diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 82a75188c24..004c3c778e0 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -9874,6 +9874,7 @@ CHARSET_INFO my_charset_gbk = { 28, /* number */ MY_CS_COMPILED, /* state */ + "gbk", /* cs name */ "gbk", /* name */ "", /* comment */ ctype_gbk, diff --git a/strings/ctype-latin1_de.c b/strings/ctype-latin1_de.c index 49acd3fa8a8..166e059ef42 100644 --- a/strings/ctype-latin1_de.c +++ b/strings/ctype-latin1_de.c @@ -415,6 +415,7 @@ CHARSET_INFO my_charset_latin1_de = { 31, /* number */ MY_CS_COMPILED, /* state */ + "latin1", /* cs name */ "latin1_de", /* name */ "", /* comment */ ctype_latin1_de, diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 092b7aa4f0f..5b963e74db9 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -201,7 +201,7 @@ int my_wildcmp_mb(CHARSET_INFO *cs, { // Found w_many uchar cmp; const char* mb = wildstr; - int mblen; + int mblen=0; wildstr++; /* Remove any '%' and '_' from the wild search string */ diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 43db7ebc24a..1e9a5895683 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4461,6 +4461,7 @@ CHARSET_INFO my_charset_sjis = { 13, /* number */ MY_CS_COMPILED, /* state */ + "sjis", /* cs name */ "sjis", /* name */ "", /* comment */ ctype_sjis, diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 2dae3036426..b448ebdd926 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -689,6 +689,7 @@ CHARSET_INFO my_charset_tis620 = { 18, /* number */ MY_CS_COMPILED, /* state */ + "tis620", /* cs name */ "tis620", /* name */ "", /* comment */ ctype_tis620, diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index 9d970005c85..2c3c8dd11c3 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -8431,6 +8431,7 @@ CHARSET_INFO my_charset_ujis = { 12, /* number */ MY_CS_COMPILED, /* state */ + "ujis", /* cs name */ "ujis", /* name */ "", /* comment */ ctype_ujis, diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index c32592dafec..738bcde92b6 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1959,6 +1959,7 @@ CHARSET_INFO my_charset_utf8 = { 33, /* number */ MY_CS_COMPILED, /* state */ + "utf8", /* cs name */ "utf8", /* name */ "", /* comment */ ctype_utf8, /* ctype */ @@ -3025,6 +3026,7 @@ CHARSET_INFO my_charset_ucs2 = { 35, /* number */ MY_CS_COMPILED, /* state */ + "ucs2", /* cs name */ "ucs2", /* name */ "", /* comment */ ctype_ucs2, /* ctype */ diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index b7a6b21cf4a..0bc63ab07cc 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -623,6 +623,7 @@ CHARSET_INFO my_charset_win1250ch = { 34, /* number */ MY_CS_COMPILED, /* state */ + "cp1250", /* cs name */ "win1250ch", /* name */ "", /* comment */ ctype_win1250ch, diff --git a/strings/ctype.c b/strings/ctype.c index 8e7d8ad939c..5869ee804c6 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -2811,6 +2811,7 @@ static CHARSET_INFO compiled_charsets[] = { { 8, /* number */ MY_CS_COMPILED, /* state */ + "latin1", /* cs name */ "latin1", /* name */ "", /* comment */ ctype_latin1, @@ -2856,6 +2857,7 @@ static CHARSET_INFO compiled_charsets[] = { { 14, /* number */ MY_CS_COMPILED, /* state */ + "cp1251", /* cs name */ "cp1251", /* name */ "", /* comment */ ctype_cp1251, @@ -2900,6 +2902,7 @@ static CHARSET_INFO compiled_charsets[] = { { 29, /* number */ MY_CS_COMPILED, /* state */ + "cp1257", /* cs name */ "cp1257", /* name */ "", /* comment */ ctype_cp1257, @@ -2944,6 +2947,7 @@ static CHARSET_INFO compiled_charsets[] = { { 27, /* number */ MY_CS_COMPILED, /* state */ + "latin2", /* cs name */ "croat", /* name */ "", /* comment */ ctype_croat, @@ -2989,6 +2993,7 @@ static CHARSET_INFO compiled_charsets[] = { { 15, /* number */ MY_CS_COMPILED, /* state */ + "latin1", /* cs name */ "danish", /* name */ "", /* comment */ ctype_danish, @@ -3033,6 +3038,7 @@ static CHARSET_INFO compiled_charsets[] = { { 3, /* number */ MY_CS_COMPILED, /* state */ + "dec8", /* cs name */ "dec8", /* name */ "", /* comment */ ctype_dec8, @@ -3077,6 +3083,7 @@ static CHARSET_INFO compiled_charsets[] = { { 4, /* number */ MY_CS_COMPILED, /* state */ + "cp850", /* cs name */ "dos", /* name */ "", /* comment */ ctype_dos, @@ -3121,6 +3128,7 @@ static CHARSET_INFO compiled_charsets[] = { { 20, /* number */ MY_CS_COMPILED, /* state */ + "latin7", /* cs name */ "estonia", /* name */ "", /* comment */ ctype_estonia, @@ -3166,6 +3174,7 @@ static CHARSET_INFO compiled_charsets[] = { { 5, /* number */ MY_CS_COMPILED, /* state */ + "latin1", /* cs name */ "german1", /* name */ "", /* comment */ ctype_german1, @@ -3210,6 +3219,7 @@ static CHARSET_INFO compiled_charsets[] = { { 25, /* number */ MY_CS_COMPILED, /* state */ + "greek", /* cs name */ "greek", /* name */ "", /* comment */ ctype_greek, @@ -3254,6 +3264,7 @@ static CHARSET_INFO compiled_charsets[] = { { 16, /* number */ MY_CS_COMPILED, /* state */ + "hebrew", /* cs name */ "hebrew", /* name */ "", /* comment */ ctype_hebrew, @@ -3298,6 +3309,7 @@ static CHARSET_INFO compiled_charsets[] = { { 6, /* number */ MY_CS_COMPILED, /* state */ + "hp8", /* cs name */ "hp8", /* name */ "", /* comment */ ctype_hp8, @@ -3342,6 +3354,7 @@ static CHARSET_INFO compiled_charsets[] = { { 21, /* number */ MY_CS_COMPILED, /* state */ + "latin2", /* cs name */ "hungarian", /* name */ "", /* comment */ ctype_hungarian, @@ -3386,6 +3399,7 @@ static CHARSET_INFO compiled_charsets[] = { { 7, /* number */ MY_CS_COMPILED, /* state */ + "koi8_ru", /* cs name */ "koi8_ru", /* name */ "", /* comment */ ctype_koi8_ru, @@ -3430,6 +3444,7 @@ static CHARSET_INFO compiled_charsets[] = { { 22, /* number */ MY_CS_COMPILED, /* state */ + "koi8_ukr", /* cs name */ "koi8_ukr", /* name */ "", /* comment */ ctype_koi8_ukr, @@ -3475,6 +3490,7 @@ static CHARSET_INFO compiled_charsets[] = { { 9, /* number */ MY_CS_COMPILED, /* state */ + "latin2", /* cs name */ "latin2", /* name */ "", /* comment */ ctype_latin2, @@ -3519,6 +3535,7 @@ static CHARSET_INFO compiled_charsets[] = { { 30, /* number */ MY_CS_COMPILED, /* state */ + "latin5", /* cs name */ "latin5", /* name */ "", /* comment */ ctype_latin5, @@ -3564,6 +3581,7 @@ static CHARSET_INFO compiled_charsets[] = { { 10, /* number */ MY_CS_COMPILED, /* state */ + "swe7", /* cs name */ "swe7", /* name */ "", /* comment */ ctype_swe7, @@ -3609,6 +3627,7 @@ static CHARSET_INFO compiled_charsets[] = { { 11, /* number */ MY_CS_COMPILED, /* state */ + "ascii", /* cs name */ "usa7", /* name */ "", /* comment */ ctype_usa7, @@ -3653,6 +3672,7 @@ static CHARSET_INFO compiled_charsets[] = { { 26, /* number */ MY_CS_COMPILED, /* state */ + "cp1250", /* cs name */ "win1250", /* name */ "", /* comment */ ctype_win1250, @@ -3697,6 +3717,7 @@ static CHARSET_INFO compiled_charsets[] = { { 23, /* number */ MY_CS_COMPILED, /* state */ + "cp1251", /* cs name */ "win1251ukr", /* name */ "", /* comment */ ctype_win1251ukr, @@ -3741,6 +3762,7 @@ static CHARSET_INFO compiled_charsets[] = { { 32, /* number */ MY_CS_COMPILED, /* state */ + "armscii8", /* cs name */ "armscii8", /* name */ "", /* comment */ ctype_armscii8, @@ -3785,6 +3807,7 @@ static CHARSET_INFO compiled_charsets[] = { { 17, /* number */ MY_CS_COMPILED, /* state */ + "cp1251", /* cs name */ "win1251", /* name */ "", /* comment */ ctype_win1251, @@ -3828,6 +3851,7 @@ static CHARSET_INFO compiled_charsets[] = { { 0, /* end-of-list marker */ 0, /* state */ + NullS, /* cs name */ NullS, /* name */ NullS, /* comment */ NULL, diff --git a/tests/client_test.c b/tests/client_test.c index 280df2bf717..d5e13dd3b43 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -32,14 +32,13 @@ #include <stdio.h> #include <string.h> -#include <assert.h> - - /* mysql client headers */ #include <my_sys.h> #include <mysql.h> #include <my_getopt.h> +#include <assert.h> + #ifndef true #define true 1 #endif @@ -58,100 +57,119 @@ static char *opt_user=0; static char *opt_password=0; static char *opt_host=0; static char *opt_unix_socket=0; -static uint opt_port; +static unsigned int opt_port; static my_bool tty_password=0; static MYSQL *mysql=0; -static char query[255]; +static char query[255]; +static char current_db[]= "client_test_db"; -#define myheader(str) { printf("\n\n#######################\n"); \ - printf("%s",str); \ - printf("\n#######################\n"); \ +#define myheader(str) { fprintf(stdout,"\n\n#######################\n"); \ + fprintf(stdout,"%s",str); \ + fprintf(stdout,"\n#######################\n"); \ } #define init_bind(x) (bzero(x,sizeof(x))) -void print_error(const char *msg) +#ifndef mysql_param_result +#define mysql_param_result mysql_prepare_result +#endif + +static void print_error(const char *msg) { if (mysql) { - fprintf(stderr,"\n [MySQL]%s \n",mysql_error(mysql)); + if (mysql->server_version) + fprintf(stderr,"\n [MySQL-%s]",mysql->server_version); + else + fprintf(stderr,"\n [MySQL]"); + fprintf(stderr," %s\n",mysql_error(mysql)); } - else if(msg) fprintf(stderr, "%s\n", msg); + else if(msg) fprintf(stderr, " [MySQL] %s\n", msg); } -void print_st_error(MYSQL_STMT *stmt, const char *msg) +static void print_st_error(MYSQL_STMT *stmt, const char *msg) { if (stmt) { - fprintf(stderr,"\n [MySQL]%s \n",mysql_stmt_error(stmt)); + if (stmt->mysql && stmt->mysql->server_version) + fprintf(stderr,"\n [MySQL-%s]",stmt->mysql->server_version); + else + fprintf(stderr,"\n [MySQL]"); + + fprintf(stderr," %s\n",mysql_stmt_error(stmt)); } - else if(msg) fprintf(stderr, "%s\n", msg); + else if(msg) fprintf(stderr, " [MySQL] %s\n", msg); } +static void client_disconnect(); #define myerror(msg) print_error(msg) #define mysterror(stmt, msg) print_st_error(stmt, msg) -#define myassert(x) if(x) {\ - fprintf(stderr,"ASSERTION FAILED AT %d@%s\n",__LINE__, __FILE__);\ - exit(1);\ +#define myassert(exp) \ + if(!exp) {\ + client_disconnect(); \ + fprintf(stderr,"\n"); \ + assert(exp); \ } -#define myassert_r(x) if(!x) {\ - fprintf(stderr,"ASSERTION FAILED AT %d@%s\n",__LINE__, __FILE__);\ - exit(1);\ +#define myassert_r(exp) \ + if(exp) {\ + client_disconnect(); \ + fprintf(stderr,"\n"); \ + assert(!(exp)); \ } #define myquery(r) \ -if( r != 0) \ { \ +if( r || r == -1) \ myerror(NULL); \ - myassert(true);\ + myassert(r == 0); \ } #define myquery_r(r) \ -if( r != 0) \ { \ +if( r || r == -1) \ myerror(NULL); \ - myassert_r(true);\ +myassert_r(r == 0); \ } #define mystmt(stmt,r) \ -if( r != 0) \ { \ +if( r || r == -1) \ mysterror(stmt,NULL); \ - myassert(true);\ +myassert(r == 0);\ } -#define myxquery(stmt) \ -if( stmt == 0) \ +#define mystmt_r(stmt,r) \ { \ - myerror(NULL); \ - myassert(true);\ +if( r || r == -1) \ + mysterror(stmt,NULL); \ +myassert_r(r == 0);\ } -#define myxquery_r(stmt) \ -if( stmt == 0) \ +#define mystmt_init(stmt) \ { \ +if( stmt == 0) \ myerror(NULL); \ - myassert_r(true);\ -} \ -else myassert(true); +myassert(stmt != 0); \ +} -#define mystmt_r(stmt,r) \ -if( r != 0) \ +#define mystmt_init_r(stmt) \ { \ - mysterror(stmt,NULL); \ - myassert_r(true);\ -} +myassert(stmt == 0);\ +} #define mytest(x) if(!x) {myerror(NULL);myassert(true);} #define mytest_r(x) if(x) {myerror(NULL);myassert(true);} +#define PREPARE(A,B) mysql_prepare(A,B,strlen(B)) + /******************************************************** * connect to the server * *********************************************************/ static void client_connect() { + char buff[255]; myheader("client_connect"); if(!(mysql = mysql_init(NULL))) @@ -163,28 +181,37 @@ static void client_connect() opt_password, opt_db ? opt_db:"test", opt_port, opt_unix_socket, 0))) { - myerror("connection failed"); + myerror("connection failed"); + mysql_close(mysql); exit(0); } /* set AUTOCOMMIT to ON*/ mysql_autocommit(mysql, true); + sprintf(buff,"CREATE DATABASE IF NOT EXISTS %s", current_db); + mysql_query(mysql, buff); + sprintf(buff,"USE %s", current_db); + mysql_query(mysql, buff); } /******************************************************** * close the connection * *********************************************************/ -void client_disconnect() +static void client_disconnect() { - myheader("client_disconnect"); - - mysql_close(mysql); + if (mysql) + { + char buff[255]; + sprintf(buff,"DROP DATABASE IF EXISTS %s", current_db); + mysql_query(mysql, buff); + mysql_close(mysql); + } } /******************************************************** * query processing * *********************************************************/ -void client_query() +static void client_query() { int rc; @@ -222,7 +249,7 @@ void client_query() /******************************************************** * print dashes * *********************************************************/ -void my_print_dashes(MYSQL_RES *result) +static void my_print_dashes(MYSQL_RES *result) { MYSQL_FIELD *field; unsigned int i,j; @@ -244,7 +271,7 @@ void my_print_dashes(MYSQL_RES *result) /******************************************************** * print resultset metadata information * *********************************************************/ -void my_print_result_metadata(MYSQL_RES *result) +static void my_print_result_metadata(MYSQL_RES *result) { MYSQL_FIELD *field; unsigned int i,j; @@ -287,6 +314,9 @@ int my_process_result_set(MYSQL_RES *result) MYSQL_FIELD *field; unsigned int i; unsigned int row_count=0; + + if (!result) + return 0; my_print_result_metadata(result); @@ -313,50 +343,157 @@ int my_process_result_set(MYSQL_RES *result) my_print_dashes(result); if (mysql_errno(mysql) != 0) - fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); + fprintf(stderr, "\n mysql_fetch_row() failed\n"); else - fprintf(stdout,"\n\t%d rows returned\n", row_count); + fprintf(stdout,"\n %d rows returned", row_count); return(row_count); } -static void verify_col_data(const char *table, const char *col, const char *exp_data) +/******************************************************** +* process the stmt result set * +*********************************************************/ +uint my_process_stmt_result(MYSQL_STMT *stmt) { - MYSQL_STMT *stmt; - MYSQL_BIND bind[1]; - char data[255]; - int rc; - - init_bind(bind); + int field_count; + uint row_count= 0; + MYSQL_BIND buffer[50]; + MYSQL_FIELD *field; + MYSQL_RES *result; + char data[50][255]; + long length[50]; + int rc, i; + + if (!(result= mysql_prepare_result(stmt))) + { + while (!mysql_fetch(stmt)); + return 0; + } - bind[0].buffer_type=FIELD_TYPE_STRING; - bind[0].buffer= (char *)data; - bind[0].buffer_length= sizeof(data); + field_count= stmt->field_count; + for(i=0; i < field_count; i++) + { + buffer[i].buffer_type= MYSQL_TYPE_STRING; + buffer[i].buffer_length=50; + buffer[i].length=(long *)&length[i]; + buffer[i].buffer=(gptr)data[i]; + } - sprintf(query, "SELECT `%s` FROM `%s`", col, table); + my_print_result_metadata(result); - printf("\n %s", query); - stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + rc= mysql_bind_result(stmt,buffer); + mystmt(stmt,rc); - rc = mysql_bind_result(stmt,bind); - mystmt(stmt, rc); + mysql_field_seek(result, 0); + while (mysql_fetch(stmt) == 0) + { + fputc('\t',stdout); + fputc('|',stdout); - rc = mysql_execute(stmt); - mystmt(stmt, rc); + for (i=0; i < field_count; i++) + { + field = mysql_fetch_field(result); + if(length[i] == MYSQL_NULL_DATA) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); + } + fputc('\t',stdout); + fputc('\n',stdout); + row_count++; + } + my_print_dashes(result); + fprintf(stdout,"\n %d rows returned", row_count); + mysql_free_result(result); - rc = mysql_fetch(stmt); - mystmt(stmt,rc); + return row_count; +} - printf("\n data : %s (expected: %s)",data, exp_data); - assert(strcmp(data,exp_data)==0); +/* + Utility function to verify a particular column data +*/ +static void verify_col_data(const char *table, const char *col, + const char *exp_data) +{ + MYSQL_RES *result; + MYSQL_ROW row; + char query[255]; + int rc, field= 1; + + if (table && col) + { + sprintf(query, "SELECT %s FROM %s LIMIT 1", col, table); - mysql_stmt_close(stmt); + fprintf(stdout,"\n %s", query); + rc = mysql_query(mysql, query); + myquery(rc); + + field= 0; + } + + result = mysql_use_result(mysql); + mytest(result); + + if (!(row= mysql_fetch_row(result)) || !row[field]) + { + fprintf(stdout,"\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + fprintf(stdout,"\n obtained: `%s` (expected: `%s`)", + row[field], exp_data); + myassert(strcmp(row[field],exp_data) == 0); + mysql_free_result(result); +} + +/* + Utility function to verify the field members +*/ + +static void verify_prepare_field(MYSQL_RES *result, + unsigned int no,const char *name, const char *org_name, + enum enum_field_types type, const char *table, + const char *org_table, const char *db) +{ + MYSQL_FIELD *field; + + if (!(field= mysql_fetch_field_direct(result,no))) + { + fprintf(stdout,"\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + fprintf(stdout,"\n field[%d]:", no); + fprintf(stdout,"\n name :`%s`\t(expected: `%s`)", field->name, name); + fprintf(stdout,"\n org_name :`%s`\t(expected: `%s`)", field->org_name, org_name); + fprintf(stdout,"\n type :`%d`\t(expected: `%d`)", field->type, type); + fprintf(stdout,"\n table :`%s`\t(expected: `%s`)", field->table, table); + fprintf(stdout,"\n org_table:`%s`\t(expected: `%s`)", field->org_table, org_table); + fprintf(stdout,"\n database :`%s`\t(expected: `%s`)", field->db, db); + fprintf(stdout,"\n"); + myassert(strcmp(field->name,name) == 0); + myassert(strcmp(field->org_name,org_name) == 0); + myassert(field->type == type); + myassert(strcmp(field->table,table) == 0); + myassert(strcmp(field->org_table,org_table) == 0); + myassert(strcmp(field->db,db) == 0); +} + +/* + Utility function to verify the parameter count +*/ +static void verify_param_count(MYSQL_STMT *stmt, long exp_count) +{ + long param_count= mysql_param_count(stmt); + fprintf(stdout,"\n total parameters in stmt: %ld (expected: %ld)", + param_count, exp_count); + myassert(param_count == exp_count); } + /******************************************************** * store result processing * *********************************************************/ -void client_store_result() +static void client_store_result() { MYSQL_RES *result; int rc; @@ -375,9 +512,9 @@ void client_store_result() } /******************************************************** -* use result processing * +* fetch the results *********************************************************/ -void client_use_result() +static void client_use_result() { MYSQL_RES *result; int rc; @@ -398,7 +535,7 @@ void client_use_result() /******************************************************** * query processing * *********************************************************/ -void test_debug_example() +static void test_debug_example() { int rc; MYSQL_RES *result; @@ -418,7 +555,7 @@ void test_debug_example() rc = mysql_query(mysql,"UPDATE test_debug_example SET name='updated' WHERE name='deleted'"); myquery(rc); - rc = mysql_query(mysql,"SELECT * FROM test_debug_example"); + rc = mysql_query(mysql,"SELECT * FROM test_debug_example where name='mysql'"); myquery(rc); result = mysql_use_result(mysql); @@ -434,7 +571,7 @@ void test_debug_example() /******************************************************** * to test autocommit feature * *********************************************************/ -void test_tran_bdb() +static void test_tran_bdb() { MYSQL_RES *result; MYSQL_ROW row; @@ -512,7 +649,7 @@ void test_tran_bdb() /******************************************************** * to test autocommit feature * *********************************************************/ -void test_tran_innodb() +static void test_tran_innodb() { MYSQL_RES *result; MYSQL_ROW row; @@ -591,10 +728,10 @@ void test_tran_innodb() To test simple prepares of all DML statements *********************************************************/ -void test_prepare_simple() +static void test_prepare_simple() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; myheader("test_prepare_simple"); @@ -610,41 +747,33 @@ void test_prepare_simple() /* alter table */ strcpy(query,"ALTER TABLE test_prepare_simple ADD new char(20)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout,"\n total parameters in alter:%d\n", param_count); - assert(param_count == 0); + verify_param_count(stmt,0); mysql_stmt_close(stmt); /* insert */ strcpy(query,"INSERT INTO test_prepare_simple VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout,"\n total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); mysql_stmt_close(stmt); /* update */ strcpy(query,"UPDATE test_prepare_simple SET id=? WHERE id=? AND name= ?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout,"\n total parameters in update:%d\n", param_count); - assert(param_count == 3); + verify_param_count(stmt,3); mysql_stmt_close(stmt); /* delete */ strcpy(query,"DELETE FROM test_prepare_simple WHERE id=10"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout,"\n total parameters in delete:%d\n", param_count); - assert(param_count == 0); + verify_param_count(stmt,0); rc = mysql_execute(stmt); mystmt(stmt, rc); @@ -653,11 +782,9 @@ void test_prepare_simple() /* delete */ strcpy(query,"DELETE FROM test_prepare_simple WHERE id=?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout,"\n total parameters in delete:%d\n", param_count); - assert(param_count == 1); + verify_param_count(stmt,1); rc = mysql_execute(stmt); mystmt_r(stmt, rc); @@ -666,11 +793,9 @@ void test_prepare_simple() /* select */ strcpy(query,"SELECT * FROM test_prepare_simple WHERE id=? AND name= ?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout,"\n total parameters in select:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); mysql_stmt_close(stmt); @@ -683,9 +808,10 @@ void test_prepare_simple() /******************************************************** * to test simple prepare field results * *********************************************************/ -void test_prepare_field_result() +static void test_prepare_field_result() { MYSQL_STMT *stmt; + MYSQL_RES *result; int rc,param_count; myheader("test_prepare_field_result"); @@ -696,29 +822,47 @@ void test_prepare_field_result() rc = mysql_commit(mysql); myquery(rc); - rc = mysql_query(mysql,"CREATE TABLE test_prepare_field_result(id int, name varchar(50), extra int)"); + rc = mysql_query(mysql,"CREATE TABLE test_prepare_field_result(int_c int, \ + var_c varchar(50), ts_c timestamp(14),\ + char_c char(3), date_c date,extra tinyint)"); myquery(rc); /* insert */ - strcpy(query,"SELECT id,name FROM test_prepare_field_result WHERE id=?"); + strcpy(query,"SELECT int_c,var_c,date_c as date,ts_c,char_c FROM \ + test_prepare_field_result as t1 WHERE int_c=?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout,"\n total parameters in insert:%d\n", param_count); - assert(param_count == 1); - mysql_stmt_close(stmt); + verify_param_count(stmt,1); - /* now fetch the results ..*/ - rc = mysql_commit(mysql); - myquery(rc); + result = mysql_prepare_result(stmt); + mytest(result); + + my_print_result_metadata(result); + + fprintf(stdout,"\n\n field attributes:\n"); + verify_prepare_field(result,0,"int_c","int_c",MYSQL_TYPE_LONG, + "t1","test_prepare_field_result",current_db); + verify_prepare_field(result,1,"var_c","var_c",MYSQL_TYPE_VAR_STRING, + "t1","test_prepare_field_result",current_db); + verify_prepare_field(result,2,"date","date_c",MYSQL_TYPE_DATE, + "t1","test_prepare_field_result",current_db); + verify_prepare_field(result,3,"ts_c","ts_c",MYSQL_TYPE_TIMESTAMP, + "t1","test_prepare_field_result",current_db); + verify_prepare_field(result,4,"char_c","char_c",MYSQL_TYPE_STRING, + "t1","test_prepare_field_result",current_db); + + param_count= mysql_num_fields(result); + fprintf(stdout,"\n\n total fields: `%d` (expected: `5`)", param_count); + myassert(param_count == 5); + mysql_stmt_close(stmt); } /******************************************************** * to test simple prepare field results * *********************************************************/ -void test_prepare_syntax() +static void test_prepare_syntax() { MYSQL_STMT *stmt; int rc; @@ -736,11 +880,11 @@ void test_prepare_syntax() strcpy(query,"INSERT INTO test_prepare_syntax VALUES(?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery_r(stmt); + mystmt_init_r(stmt); strcpy(query,"SELECT id,name FROM test_prepare_syntax WHERE id=? AND WHERE"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery_r(stmt); + mystmt_init_r(stmt); /* now fetch the results ..*/ rc = mysql_commit(mysql); @@ -751,10 +895,10 @@ void test_prepare_syntax() /******************************************************** * to test simple prepare * *********************************************************/ -void test_prepare() +static void test_prepare() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char query[200]; int int_data; char str_data[50]; @@ -779,7 +923,7 @@ void test_prepare() myquery(rc); rc = mysql_query(mysql,"CREATE TABLE my_prepare(col1 tinyint,\ - col2 varchar(50), col3 int,\ + col2 varchar(15), col3 int,\ col4 smallint, col5 bigint, \ col6 float, col7 double )"); myquery(rc); @@ -787,11 +931,9 @@ void test_prepare() /* insert by prepare */ strcpy(query,"INSERT INTO my_prepare VALUES(?,?,?,?,?,?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 7); + verify_param_count(stmt,7); /* tinyint */ bind[0].buffer_type=FIELD_TYPE_TINY; @@ -852,7 +994,7 @@ void test_prepare() result = mysql_store_result(mysql); mytest(result); - assert((int)tiny_data == my_process_result_set(result)); + myassert((int)tiny_data == my_process_result_set(result)); mysql_free_result(result); } @@ -860,10 +1002,10 @@ void test_prepare() /******************************************************** * to test double comparision * *********************************************************/ -void test_double_compare() +static void test_double_compare() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char query[200],real_data[10], tiny_data; double double_data; MYSQL_RES *result; @@ -890,10 +1032,9 @@ void test_double_compare() strcpy(query, "UPDATE test_double_compare SET col1=100 WHERE col1 = ? AND col2 = ? AND COL3 = ?"); stmt = mysql_prepare(mysql,query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in update:%d\n", param_count); + verify_param_count(stmt,3); /* tinyint */ bind[0].buffer_type=FIELD_TYPE_TINY; @@ -916,7 +1057,7 @@ void test_double_compare() mystmt(stmt, rc); rc = (int)mysql_affected_rows(mysql); - printf("\n total affected rows:%d",rc); + fprintf(stdout,"\n total affected rows:%d",rc); mysql_stmt_close(stmt); @@ -932,21 +1073,17 @@ void test_double_compare() result = mysql_store_result(mysql); mytest(result); - assert((int)tiny_data == my_process_result_set(result)); + myassert((int)tiny_data == my_process_result_set(result)); mysql_free_result(result); - } - - - /******************************************************** * to test simple null * *********************************************************/ -void test_null() +static void test_null() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; int nData=1; MYSQL_RES *result; MYSQL_BIND bind[2]; @@ -966,15 +1103,13 @@ void test_null() /* insert by prepare, wrong column name */ strcpy(query,"INSERT INTO test_null(col3,col2) VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery_r(stmt); + mystmt_init_r(stmt); strcpy(query,"INSERT INTO test_null(col1,col2) VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); bind[0].is_null=1; bind[0].buffer_type=MYSQL_TYPE_NULL; @@ -1003,49 +1138,171 @@ void test_null() result = mysql_store_result(mysql); mytest(result); - assert(nData == my_process_result_set(result)); + myassert(nData == my_process_result_set(result)); mysql_free_result(result); } +/******************************************************** +* to test fetch null * +*********************************************************/ +static void test_fetch_null() +{ + MYSQL_STMT *stmt; + int rc; + const char query[100]; + int length[11], i, nData; + MYSQL_BIND bind[11]; + + myheader("test_fetch_null"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_fetch_null"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_fetch_null(col1 tinyint, col2 smallint, \ + col3 int, col4 bigint, \ + col5 float, col6 double, \ + col7 date, col8 time, \ + col9 varbinary(10), \ + col10 varchar(50),\ + col11 char(20))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"INSERT INTO test_fetch_null(col11) VALUES(1000)"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + /* fetch */ + for (i=0; i < 10; i++) + { + bind[i].buffer_type=FIELD_TYPE_LONG; + length[i]=99; + bind[i].length= (long *)&length[i]; + } + bind[i].buffer_type=FIELD_TYPE_LONG; + bind[i].buffer=(gptr)&nData; + + strcpy((char *)query , "SELECT * FROM test_fetch_null"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + rc = mysql_bind_result(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + for (i=0; i < 10; i++) + { + fprintf(stdout, "\n data[%d]: %s", i, length[i] == MYSQL_NULL_DATA ? "NULL" : "NOT NULL"); + myassert(length[i] == MYSQL_NULL_DATA); + } + fprintf(stdout, "\n data[%d]: %d", i, nData); + myassert(nData == 1000); + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} /******************************************************** * to test simple select * *********************************************************/ -void test_select_simple() +static void test_select_version() { MYSQL_STMT *stmt; - int rc,length; + int rc; + const char query[100]; + + myheader("test_select_version"); + + strcpy((char *)query , "SELECT @@version"); + stmt = PREPARE(mysql, query); + mystmt_init(stmt); + + verify_param_count(stmt,0); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test simple select * +*********************************************************/ +static void test_select_simple() +{ + MYSQL_STMT *stmt; + int rc; const char query[100]; - MYSQL_RES *result; myheader("test_select_simple"); /* insert by prepare */ strcpy((char *)query, "SHOW TABLES FROM mysql"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - length = mysql_param_count(stmt); - fprintf(stdout," total parameters in select:%d\n", length); - assert(length == 0); + verify_param_count(stmt,0); rc = mysql_execute(stmt); mystmt(stmt, rc); - /* get the result */ - result = mysql_store_result(mysql); - mytest(result); + my_process_stmt_result(stmt); + mysql_stmt_close(stmt); +} - my_process_result_set(result); - mysql_free_result(result); +/******************************************************** +* to test simple select to debug * +*********************************************************/ +static void test_select_direct() +{ + int rc; + MYSQL_RES *result; - mysql_stmt_close(stmt); + myheader("test_select_direct"); + + rc = mysql_autocommit(mysql,true); + myquery(rc); -#if 0 - strcpy((char *)query , "SELECT @@ VERSION"); - length = strlen(query); - rc = mysql_query(mysql,query); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_select(id int, id1 tinyint, \ + id2 float, \ + id3 double, \ + name varchar(50))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + /* insert a row and commit the transaction */ + rc = mysql_query(mysql,"INSERT INTO test_select VALUES(10,5,2.3,4.5,'venu')"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"SELECT * FROM test_select"); myquery(rc); /* get the result */ @@ -1054,22 +1311,88 @@ void test_select_simple() my_process_result_set(result); mysql_free_result(result); -#endif } +/******************************************************** +* to test simple select with prepare * +*********************************************************/ +static void test_select_prepare() +{ + int rc, count; + MYSQL_STMT *stmt; + + myheader("test_select_prepare"); + + rc = mysql_autocommit(mysql,true); + myquery(rc); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_select(id int, name varchar(50))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + /* insert a row and commit the transaction */ + rc = mysql_query(mysql,"INSERT INTO test_select VALUES(10,'venu')"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_select",50); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt,rc); + + count= my_process_stmt_result(stmt); + + rc = mysql_query(mysql,"DROP TABLE test_select"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_select(id tinyint, id1 int, \ + id2 float, id3 float, \ + name varchar(50))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + /* insert a row and commit the transaction */ + rc = mysql_query(mysql,"INSERT INTO test_select(id,id1,id2,name) VALUES(10,5,2.3,'venu')"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + stmt = mysql_prepare(mysql,"SELECT * FROM test_select",25); + mystmt_init(stmt); + + rc = mysql_execute(stmt); + mystmt(stmt,rc); + + my_process_stmt_result(stmt); +} /******************************************************** * to test simple select * *********************************************************/ -void test_select() +static void test_select() { MYSQL_STMT *stmt; - int rc,param_count=0; - char *szData=(char *)"updated-value"; + int rc; + char szData[25]; int nData=1; MYSQL_BIND bind[2]; - MYSQL_RES *result; - myheader("test_select"); @@ -1105,15 +1428,13 @@ void test_select() strcpy(query,"SELECT * FROM test_select WHERE id=? AND name=?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in select:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); /* string data */ nData=10; - szData=(char *)"venu"; + strcpy(szData,(char *)"venu"); bind[1].buffer_type=FIELD_TYPE_STRING; bind[1].buffer=szData; bind[1].buffer_length=4; @@ -1126,28 +1447,50 @@ void test_select() rc = mysql_execute(stmt); mystmt(stmt, rc); + myassert( 1 == my_process_stmt_result(stmt)); + + mysql_stmt_close(stmt); +} + +/******************************************************** +* to test simple select show * +*********************************************************/ +static void test_select_show() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + + myheader("test_select_show"); + + mysql_autocommit(mysql,true); + + strcpy(query,"SELECT * FROM mysql.host"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,0); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + /* get the result */ result = mysql_store_result(mysql); mytest(result); - assert( 1 == my_process_result_set(result)); + my_process_result_set(result); mysql_free_result(result); mysql_stmt_close(stmt); - - /* bit complicated SELECT */ } - - - /******************************************************** * to test simple update * *********************************************************/ -void test_simple_update() +static void test_simple_update() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char szData[25]; int nData=1; MYSQL_RES *result; @@ -1175,7 +1518,7 @@ void test_simple_update() rc = mysql_query(mysql,"INSERT INTO test_update VALUES(1,'MySQL',100)"); myquery(rc); - assert(1 == mysql_affected_rows(mysql)); + myassert(1 == mysql_affected_rows(mysql)); rc = mysql_commit(mysql); myquery(rc); @@ -1183,11 +1526,9 @@ void test_simple_update() /* insert by prepare */ strcpy(query,"UPDATE test_update SET col2=? WHERE col1=?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in update:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); nData=1; bind[0].buffer_type=FIELD_TYPE_STRING; @@ -1201,7 +1542,7 @@ void test_simple_update() rc = mysql_execute(stmt); mystmt(stmt, rc); - assert(1 == mysql_affected_rows(mysql)); + myassert(1 == mysql_affected_rows(mysql)); mysql_stmt_close(stmt); @@ -1217,7 +1558,7 @@ void test_simple_update() result = mysql_store_result(mysql); mytest(result); - assert(1 == my_process_result_set(result)); + myassert(1 == my_process_result_set(result)); mysql_free_result(result); } @@ -1225,10 +1566,10 @@ void test_simple_update() /******************************************************** * to test simple long data handling * *********************************************************/ -void test_long_data() +static void test_long_data() { MYSQL_STMT *stmt; - int rc,param_count, int_data=10; + int rc, int_data; char *data=NullS; MYSQL_RES *result; MYSQL_BIND bind[3]; @@ -1255,15 +1596,13 @@ void test_long_data() strcpy(query,"INSERT INTO test_long_data(col1,col2) VALUES(?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery_r(stmt); + mystmt_init_r(stmt); strcpy(query,"INSERT INTO test_long_data(col1,col2,col3) VALUES(?,?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 3); + verify_param_count(stmt,3); bind[0].buffer=(char *)&int_data; bind[0].buffer_type=FIELD_TYPE_LONG; @@ -1272,7 +1611,7 @@ void test_long_data() /* Non string or binary type, error */ bind[1].buffer_type=FIELD_TYPE_LONG; rc = mysql_bind_param(stmt,bind); - fprintf(stdout,"mysql_bind_param() returned %d\n",rc); + fprintf(stdout," mysql_bind_param() returned: %d\n",rc); mystmt_r(stmt, rc); bind[1].buffer_type=FIELD_TYPE_STRING; @@ -1280,36 +1619,37 @@ void test_long_data() rc = mysql_bind_param(stmt,bind); mystmt(stmt, rc); + int_data= 999; rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); data = (char *)"Micheal"; /* supply data in pieces */ - rc = mysql_send_long_data(stmt,1,data,7,1); + rc = mysql_send_long_data(stmt,1,data,7,0); mystmt(stmt, rc); /* try to execute mysql_execute() now, it should return MYSQL_NEED_DATA as the long data supply is not yet over */ rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); /* append data again ..*/ /* Indicate end of data */ - data = (char *)" 'monty' widenius"; + data = (char *)" 'monty' Widenius"; rc = mysql_send_long_data(stmt,1,data,17,1); mystmt(stmt, rc); - rc = mysql_send_long_data(stmt,2,"Venu (venu@mysql.com",4,1); + rc = mysql_send_long_data(stmt,2,"Venu (venu@mysql.com)",4,1); mystmt(stmt, rc); /* execute */ rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); + fprintf(stdout," mysql_execute() returned %d\n",rc); mystmt(stmt,rc); rc = mysql_commit(mysql); @@ -1323,17 +1663,21 @@ void test_long_data() result = mysql_store_result(mysql); mytest(result); - assert(1 == my_process_result_set(result)); + myassert(1 == my_process_result_set(result)); mysql_free_result(result); + + verify_col_data("test_long_data","col1","999"); + verify_col_data("test_long_data","col2","Micheal 'monty' Widenius"); + verify_col_data("test_long_data","col3","Venu"); } /******************************************************** * to test long data (string) handling * *********************************************************/ -void test_long_data_str() +static void test_long_data_str() { MYSQL_STMT *stmt; - int rc,param_count; + int rc, i; char data[255]; long length; MYSQL_RES *result; @@ -1360,11 +1704,9 @@ void test_long_data_str() strcpy(query,"INSERT INTO test_long_data_str VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); bind[0].buffer = (gptr)&length; bind[0].buffer_type = FIELD_TYPE_LONG; @@ -1377,28 +1719,24 @@ void test_long_data_str() length = 10; rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); length = 40; sprintf(data,"MySQL AB"); /* supply data in pieces */ + for(i=0; i < 4; i++) { - int i; - for(i=0; i < 4; i++) - { - rc = mysql_send_long_data(stmt,1,(char *)data,5,0); - mystmt(stmt, rc); - } - - /* try to execute mysql_execute() now, it should return - MYSQL_NEED_DATA as the long data supply is not yet over - */ - rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + rc = mysql_send_long_data(stmt,1,(char *)data,5,0); + mystmt(stmt, rc); } + /* try to execute mysql_execute() now, it should return + MYSQL_NEED_DATA as the long data supply is not yet over + */ + rc = mysql_execute(stmt); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); /* Indiate end of data supply */ rc = mysql_send_long_data(stmt,1,0,0,1); @@ -1406,7 +1744,7 @@ void test_long_data_str() /* execute */ rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); + fprintf(stdout," mysql_execute() returned %d\n",rc); mystmt(stmt,rc); mysql_stmt_close(stmt); @@ -1422,20 +1760,27 @@ void test_long_data_str() result = mysql_store_result(mysql); mytest(result); - assert(1 == my_process_result_set(result)); + myassert(1 == my_process_result_set(result)); mysql_free_result(result); + + sprintf(data,"%d", i*5); + verify_col_data("test_long_data_str","LENGTH(longstr)", data); + data[0]='\0'; + while (i--) + sprintf(data,"%s%s", data,"MySQL"); + verify_col_data("test_long_data_str","longstr", data); } /******************************************************** * to test long data (string) handling * *********************************************************/ -void test_long_data_str1() +static void test_long_data_str1() { MYSQL_STMT *stmt; - int rc,param_count; - char *data=(char *)"MySQL AB"; - int length; + int rc; + char data[255]; + int length, i; MYSQL_RES *result; MYSQL_BIND bind[2]; @@ -1460,11 +1805,9 @@ void test_long_data_str1() strcpy(query,"INSERT INTO test_long_data_str VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); bind[0].buffer=data; /* string data */ bind[0].is_long_data=1; /* specify long data suppy during run-time */ @@ -1478,44 +1821,41 @@ void test_long_data_str1() length = 10; rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); - length = strlen(data); + length = sprintf(data,"MySQL AB"); /* supply data in pieces */ + for(i=0; i < 3; i++) { - int i; - for(i=0; i < 2; i++) - { - rc = mysql_send_long_data(stmt,0,data,length,0); - mystmt(stmt, rc); + rc = mysql_send_long_data(stmt,0,data,length,0); + mystmt(stmt, rc); - rc = mysql_send_long_data(stmt,1,data,2,0); - mystmt(stmt, rc); - } - /* try to execute mysql_execute() now, it should return - MYSQL_NEED_DATA as the long data supply is not yet over - */ - rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + rc = mysql_send_long_data(stmt,1,data,2,0); + mystmt(stmt, rc); } - + /* try to execute mysql_execute() now, it should return + MYSQL_NEED_DATA as the long data supply is not yet over + */ + rc = mysql_execute(stmt); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); + /* Indiate end of data supply */ rc = mysql_send_long_data(stmt,1,0,0,1); mystmt(stmt, rc); rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); rc = mysql_send_long_data(stmt,0,0,0,1); mystmt(stmt, rc); /* execute */ rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); + fprintf(stdout," mysql_execute() returned %d\n",rc); mystmt(stmt,rc); mysql_stmt_close(stmt); @@ -1531,18 +1871,24 @@ void test_long_data_str1() result = mysql_store_result(mysql); mytest(result); - assert(1 == my_process_result_set(result)); + myassert(1 == my_process_result_set(result)); mysql_free_result(result); + + sprintf(data,"%d",i*length); + verify_col_data("test_long_data_str","length(longstr)",data); + + sprintf(data,"%d",i*2); + verify_col_data("test_long_data_str","length(blb)",data); } /******************************************************** * to test long data (binary) handling * *********************************************************/ -void test_long_data_bin() +static void test_long_data_bin() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char data[255]; int length; MYSQL_RES *result; @@ -1569,11 +1915,9 @@ void test_long_data_bin() strcpy(query,"INSERT INTO test_long_data_bin VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); bind[0].buffer = (gptr)&length; bind[0].buffer_type = FIELD_TYPE_LONG; @@ -1586,8 +1930,8 @@ void test_long_data_bin() length = 10; rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); sprintf(data,"MySQL AB"); @@ -1604,8 +1948,8 @@ void test_long_data_bin() MYSQL_NEED_DATA as the long data supply is not yet over */ rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); - assert(rc == MYSQL_NEED_DATA); + fprintf(stdout," mysql_execute() returned %d\n",rc); + myassert(rc == MYSQL_NEED_DATA); } /* Indiate end of data supply */ @@ -1614,7 +1958,7 @@ void test_long_data_bin() /* execute */ rc = mysql_execute(stmt); - fprintf(stdout,"mysql_execute() returned %d\n",rc); + fprintf(stdout," mysql_execute() returned %d\n",rc); mystmt(stmt,rc); mysql_stmt_close(stmt); @@ -1630,7 +1974,7 @@ void test_long_data_bin() result = mysql_store_result(mysql); mytest(result); - assert(1 == my_process_result_set(result)); + myassert(1 == my_process_result_set(result)); mysql_free_result(result); } @@ -1638,10 +1982,10 @@ void test_long_data_bin() /******************************************************** * to test simple delete * *********************************************************/ -void test_simple_delete() +static void test_simple_delete() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char szData[30]={0}; int nData=1; MYSQL_RES *result; @@ -1670,7 +2014,7 @@ void test_simple_delete() rc = mysql_query(mysql,"INSERT INTO test_simple_delete VALUES(1,'MySQL',100)"); myquery(rc); - assert(1 == mysql_affected_rows(mysql)); + myassert(1 == mysql_affected_rows(mysql)); rc = mysql_commit(mysql); myquery(rc); @@ -1678,11 +2022,9 @@ void test_simple_delete() /* insert by prepare */ strcpy(query,"DELETE FROM test_simple_delete WHERE col1=? AND col2=? AND col3=100"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in delete:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); nData=1; strcpy(szData,"MySQL"); @@ -1697,7 +2039,7 @@ void test_simple_delete() rc = mysql_execute(stmt); mystmt(stmt, rc); - assert(1 == mysql_affected_rows(mysql)); + myassert(1 == mysql_affected_rows(mysql)); mysql_stmt_close(stmt); @@ -1713,7 +2055,7 @@ void test_simple_delete() result = mysql_store_result(mysql); mytest(result); - assert(0 == my_process_result_set(result)); + myassert(0 == my_process_result_set(result)); mysql_free_result(result); } @@ -1722,10 +2064,10 @@ void test_simple_delete() /******************************************************** * to test simple update * *********************************************************/ -void test_update() +static void test_update() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char szData[25]; int nData=1; MYSQL_RES *result; @@ -1753,11 +2095,9 @@ void test_update() strcpy(query,"INSERT INTO test_update(col2,col3) VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); /* string data */ bind[0].buffer_type=FIELD_TYPE_STRING; @@ -1773,16 +2113,14 @@ void test_update() rc = mysql_execute(stmt); mystmt(stmt, rc); - assert(1 == mysql_affected_rows(mysql)); + myassert(1 == mysql_affected_rows(mysql)); mysql_stmt_close(stmt); strcpy(query,"UPDATE test_update SET col2=? WHERE col3=?"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in update:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); nData=100; @@ -1797,7 +2135,7 @@ void test_update() rc = mysql_execute(stmt); mystmt(stmt, rc); - assert(1 == mysql_affected_rows(mysql)); + myassert(1 == mysql_affected_rows(mysql)); mysql_stmt_close(stmt); @@ -1813,7 +2151,7 @@ void test_update() result = mysql_store_result(mysql); mytest(result); - assert(1 == my_process_result_set(result)); + myassert(1 == my_process_result_set(result)); mysql_free_result(result); } @@ -1821,13 +2159,13 @@ void test_update() /******************************************************** * to test simple prepare * *********************************************************/ -void test_init_prepare() +static void test_prepare_noparam() { MYSQL_STMT *stmt; - int param_count, rc; + int rc; MYSQL_RES *result; - myheader("test_init_prepare"); + myheader("test_prepare_noparam"); rc = mysql_query(mysql,"DROP TABLE IF EXISTS my_prepare"); myquery(rc); @@ -1842,11 +2180,9 @@ void test_init_prepare() /* insert by prepare */ strcpy(query,"INSERT INTO my_prepare VALUES(10,'venu')"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 0); + verify_param_count(stmt,0); rc = mysql_execute(stmt); mystmt(stmt, rc); @@ -1865,7 +2201,7 @@ void test_init_prepare() result = mysql_store_result(mysql); mytest(result); - assert(1 == my_process_result_set(result)); + myassert(1 == my_process_result_set(result)); mysql_free_result(result); } @@ -1873,12 +2209,12 @@ void test_init_prepare() /******************************************************** * to test simple bind result * *********************************************************/ -void test_bind_result() +static void test_bind_result() { MYSQL_STMT *stmt; int rc; const char query[100]; - int nData; + int nData, length, length1; char szData[100]; MYSQL_BIND bind[2]; @@ -1903,6 +2239,9 @@ void test_bind_result() rc = mysql_query(mysql,"INSERT INTO test_bind_result VALUES(20,'MySQL')"); myquery(rc); + rc = mysql_query(mysql,"INSERT INTO test_bind_result(col2) VALUES('monty')"); + myquery(rc); + rc = mysql_commit(mysql); myquery(rc); @@ -1910,13 +2249,131 @@ void test_bind_result() bind[0].buffer_type=FIELD_TYPE_LONG; bind[0].buffer= (gptr) &nData; /* integer data */ + bind[0].length= (long *)&length; bind[1].buffer_type=FIELD_TYPE_STRING; bind[1].buffer=szData; /* string data */ bind[1].buffer_length=sizeof(szData); + bind[1].length=(long *)&length1; + + strcpy((char *)query , "SELECT * FROM test_bind_result"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + rc = mysql_bind_result(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout,"\n row 1: %d,%s(%d)",nData, szData, length1); + myassert(nData == 10); + myassert(strcmp(szData,"venu")==0); + myassert(length1 == 4); + + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout,"\n row 2: %d,%s(%d)",nData, szData, length1); + myassert(nData == 20); + myassert(strcmp(szData,"MySQL")==0); + myassert(length1 == 5); + + length=99; + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + if (length == MYSQL_NULL_DATA) + fprintf(stdout,"\n row 3: NULL,%s(%d)", szData, length1); + else + fprintf(stdout,"\n row 3: %d,%s(%d)", nData, szData, length1); + myassert(length == MYSQL_NULL_DATA); + myassert(strcmp(szData,"monty")==0); + myassert(length1 == 5); + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/******************************************************** +* to test ext bind result * +*********************************************************/ +static void test_bind_result_ext() +{ + MYSQL_STMT *stmt; + int rc; + const char query[100]; + uchar t_data; + short s_data; + int i_data; + longlong b_data; + float f_data; + double d_data; + char szData[20], bData[20]; + int szLength, bLength; + MYSQL_BIND bind[8]; + + myheader("test_bind_result_ext"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_result"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_result(c1 tinyint, c2 smallint, \ + c3 int, c4 bigint, \ + c5 float, c6 double, \ + c7 varbinary(10), \ + c8 varchar(50))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"INSERT INTO test_bind_result VALUES(19,2999,3999,4999999,\ + 2345.6,5678.89563,\ + 'venu','mysql')"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + bind[0].buffer_type=MYSQL_TYPE_TINY; + bind[0].buffer=(gptr)&t_data; + + bind[1].buffer_type=MYSQL_TYPE_SHORT; + bind[2].buffer_type=MYSQL_TYPE_LONG; + + bind[3].buffer_type=MYSQL_TYPE_LONGLONG; + bind[1].buffer=(gptr)&s_data; + + bind[2].buffer=(gptr)&i_data; + bind[3].buffer=(gptr)&b_data; + + bind[4].buffer_type=MYSQL_TYPE_FLOAT; + bind[4].buffer=(gptr)&f_data; + + bind[5].buffer_type=MYSQL_TYPE_DOUBLE; + bind[5].buffer=(gptr)&d_data; + + bind[6].buffer_type=MYSQL_TYPE_STRING; + bind[6].buffer=(gptr)&szData; + bind[6].length=(long *)&szLength; + + bind[7].buffer_type=MYSQL_TYPE_TINY_BLOB; + bind[7].buffer=(gptr)&bData; + bind[7].length=(long *)&bLength; strcpy((char *)query , "SELECT * FROM test_bind_result"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); rc = mysql_bind_result(stmt,bind); mystmt(stmt, rc); @@ -1927,30 +2384,281 @@ void test_bind_result() rc = mysql_fetch(stmt); mystmt(stmt,rc); - printf("\n row 1:%d,%s",nData, szData); - assert(nData == 10); - assert(strcmp(szData,"venu")==0); + fprintf(stdout, "\n data (tiny) : %d", t_data); + fprintf(stdout, "\n data (short) : %d", s_data); + fprintf(stdout, "\n data (int) : %d", i_data); + fprintf(stdout, "\n data (big) : %lld", b_data); + + fprintf(stdout, "\n data (float) : %f", f_data); + fprintf(stdout, "\n data (double) : %f", d_data); + + fprintf(stdout, "\n data (str) : %s(%d)", szData, szLength); + fprintf(stdout, "\n data (bin) : %s(%d)", bData, bLength); + + + myassert(t_data == 19); + myassert(s_data == 2999); + myassert(i_data == 3999); + myassert(b_data == 4999999); + /*myassert(f_data == 2345.60);*/ + /*myassert(d_data == 5678.89563);*/ + myassert(strcmp(szData,"venu")==0); + myassert(strcmp(bData,"mysql")==0); + myassert(szLength == 4); + myassert(bLength == 5); + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/******************************************************** +* to test ext bind result * +*********************************************************/ +static void test_bind_result_ext1() +{ + MYSQL_STMT *stmt; + int rc; + const char query[100]; + char t_data[20]; + float s_data; + short i_data; + short b_data; + int f_data; + long bData; + long length[11]; + char d_data[20]; + double szData; + MYSQL_BIND bind[8]; + + myheader("test_bind_result_ext1"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_result"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_result(c1 tinyint, c2 smallint, \ + c3 int, c4 bigint, \ + c5 float, c6 double, \ + c7 varbinary(10), \ + c8 varchar(10))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"INSERT INTO test_bind_result VALUES(120,2999,3999,54,\ + 2.6,58.89,\ + '206','6.7')"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + bind[0].buffer_type=MYSQL_TYPE_STRING; + bind[0].buffer=(gptr)t_data; + + for (rc=0; rc <= 7; rc++) + bind[rc].length= &length[rc]; + + bind[1].buffer_type=MYSQL_TYPE_FLOAT; + bind[1].buffer=(gptr)&s_data; + + bind[2].buffer_type=MYSQL_TYPE_SHORT; + bind[2].buffer=(gptr)&i_data; + + bind[3].buffer_type=MYSQL_TYPE_TINY; + bind[3].buffer=(gptr)&b_data; + + bind[4].buffer_type=MYSQL_TYPE_LONG; + bind[4].buffer=(gptr)&f_data; + + bind[5].buffer_type=MYSQL_TYPE_STRING; + bind[5].buffer=(gptr)d_data; + + bind[6].buffer_type=MYSQL_TYPE_LONG; + bind[6].buffer=(gptr)&bData; + + bind[7].buffer_type=MYSQL_TYPE_DOUBLE; + bind[7].buffer=(gptr)&szData; + + strcpy((char *)query , "SELECT * FROM test_bind_result"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + rc = mysql_bind_result(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); rc = mysql_fetch(stmt); mystmt(stmt,rc); - printf("\n row 2:%d,%s",nData, szData); - assert(nData == 20); - assert(strcmp(szData,"MySQL")==0); + fprintf(stdout, "\n data (tiny) : %s(%ld)", t_data, length[0]); + fprintf(stdout, "\n data (short) : %f(%ld)", s_data, length[1]); + fprintf(stdout, "\n data (int) : %d(%ld)", i_data, length[2]); + fprintf(stdout, "\n data (big) : %d(%ld)", b_data, length[3]); + + fprintf(stdout, "\n data (float) : %d(%ld)", f_data, length[4]); + fprintf(stdout, "\n data (double) : %s(%ld)", d_data, length[5]); + + fprintf(stdout, "\n data (bin) : %ld(%ld)", bData, length[6]); + fprintf(stdout, "\n data (str) : %g(%ld)", szData, length[7]); + + myassert(strcmp(t_data,"120")==0); + myassert(i_data == 3999); + myassert(f_data == 2); + myassert(strcmp(d_data,"58.89")==0); + + myassert(length[0] == 3); + myassert(length[1] == 4); + myassert(length[2] == 2); + myassert(length[3] == 1); + myassert(length[4] == 4); + myassert(length[5] == 5); + myassert(length[6] == 4); + myassert(length[7] == 8); rc = mysql_fetch(stmt); - assert(rc == MYSQL_NO_DATA); + myassert(rc == MYSQL_NO_DATA); mysql_stmt_close(stmt); } /******************************************************** +* to test fetching of date, time and ts * +*********************************************************/ +static void test_fetch_date() +{ + MYSQL_STMT *stmt; + int rc, year; + char date[25], time[25], ts[25], ts_4[15], ts_6[20], dt[20]; + int d_length, t_length, ts_length, ts4_length, ts6_length, + dt_length, y_length; + + MYSQL_BIND bind[3]; + + myheader("test_fetch_date"); + + init_bind(bind); + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_bind_result"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_bind_result(c1 date, c2 time, \ + c3 timestamp(14), \ + c4 year, \ + c5 datetime, \ + c6 timestamp(4), \ + c7 timestamp(6))"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"INSERT INTO test_bind_result VALUES('2002-01-02',\ + '12:49:00',\ + '2002-01-02 17:46:59', \ + 2010,\ + '2010-07-10', \ + '2020','1999-12-29')"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + bind[0].buffer_type=MYSQL_TYPE_STRING; + bind[1]=bind[2]=bind[0]; + + bind[0].buffer=(gptr)&date; + bind[0].length=(long *)&d_length; + + bind[1].buffer=(gptr)&time; + bind[1].length=(long *)&t_length; + + bind[2].buffer=(gptr)&ts; + bind[2].length=(long *)&ts_length; + + bind[3].buffer_type=MYSQL_TYPE_LONG; + bind[3].buffer=(gptr)&year; + bind[3].length=(long *)&y_length; + + bind[4].buffer_type=MYSQL_TYPE_STRING; + bind[4].buffer=(gptr)&dt; + bind[4].length=(long *)&dt_length; + + bind[5].buffer_type=MYSQL_TYPE_STRING; + bind[5].buffer=(gptr)&ts_4; + bind[5].length=(long *)&ts4_length; + + bind[6].buffer_type=MYSQL_TYPE_STRING; + bind[6].buffer=(gptr)&ts_6; + bind[6].length=(long *)&ts6_length; + + stmt = mysql_prepare(mysql, "SELECT * FROM test_bind_result", 50); + mystmt_init(stmt); + + rc = mysql_bind_result(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + ts_4[0]='\0'; + rc = mysql_fetch(stmt); + mystmt(stmt,rc); + + fprintf(stdout, "\n date : %s(%d)", date, d_length); + fprintf(stdout, "\n time : %s(%d)", time, t_length); + fprintf(stdout, "\n ts : %s(%d)", ts, ts_length); + fprintf(stdout, "\n year : %d(%d)", year, y_length); + fprintf(stdout, "\n dt : %s(%d)", dt, dt_length); + fprintf(stdout, "\n ts(4) : %s(%d)", ts_4, ts4_length); + fprintf(stdout, "\n ts(6) : %s(%d)", ts_6, ts6_length); + + myassert(strcmp(date,"2002-01-02")==0); + myassert(d_length == 10); + + myassert(strcmp(time,"12:49:00")==0); + myassert(d_length == 8); + + myassert(strcmp(ts,"2002-01-02 17:46:59")==0); + myassert(ts_length == 19); + + myassert(year == 2010); + myassert(y_length == 4); + + myassert(strcmp(dt,"2010-07-10")==0); + myassert(dt_length == 10); + + myassert(ts_4[0] == '\0'); + myassert(ts4_length == 0); + + myassert(strcmp(ts_6,"1999-12-29")==0); + myassert(ts6_length == 10); + + rc = mysql_fetch(stmt); + myassert(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); +} + + +/******************************************************** * to test simple prepare with all possible types * *********************************************************/ -void test_prepare_ext() +static void test_prepare_ext() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char *sql; int nData=1; MYSQL_RES *result; @@ -2012,9 +2720,7 @@ void test_prepare_ext() stmt = mysql_prepare(mysql,query, strlen(query)); myquery(rc); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 6); + verify_param_count(stmt,6); /*tinyint*/ bind_int[0].buffer_type=FIELD_TYPE_TINY; @@ -2065,7 +2771,7 @@ void test_prepare_ext() result = mysql_store_result(mysql); mytest(result); - assert(nData == my_process_result_set(result)); + myassert(nData == my_process_result_set(result)); mysql_free_result(result); } @@ -2075,14 +2781,14 @@ void test_prepare_ext() /******************************************************** * to test real and alias names * *********************************************************/ -void test_field_names() +static void test_field_names() { int rc; MYSQL_RES *result; myheader("test_field_names"); - printf("\n%d,%d,%d",MYSQL_TYPE_DECIMAL,MYSQL_TYPE_NEWDATE,MYSQL_TYPE_ENUM); + fprintf(stdout,"\n %d,%d,%d",MYSQL_TYPE_DECIMAL,MYSQL_TYPE_NEWDATE,MYSQL_TYPE_ENUM); rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_field_names1"); myquery(rc); @@ -2108,7 +2814,7 @@ void test_field_names() result = mysql_use_result(mysql); mytest(result); - assert(0 == my_process_result_set(result)); + myassert(0 == my_process_result_set(result)); mysql_free_result(result); /* with table name included with true column name */ @@ -2118,23 +2824,20 @@ void test_field_names() result = mysql_use_result(mysql); mytest(result); - assert(0 == my_process_result_set(result)); + myassert(0 == my_process_result_set(result)); mysql_free_result(result); } /******************************************************** * to test warnings * *********************************************************/ -void test_warnings() +static void test_warnings() { int rc; MYSQL_RES *result; myheader("test_warnings"); - rc = mysql_query(mysql,"USE test"); - myquery(rc); - rc = mysql_query(mysql,"SHOW WARNINGS"); myquery(rc); @@ -2148,7 +2851,7 @@ void test_warnings() /******************************************************** * to test errors * *********************************************************/ -void test_errors() +static void test_errors() { int rc; MYSQL_RES *result; @@ -2170,10 +2873,10 @@ void test_errors() /******************************************************** * to test simple prepare-insert * *********************************************************/ -void test_insert() +static void test_insert() { MYSQL_STMT *stmt; - int rc,param_count, length; + int rc, length; char query[200]; char str_data[50]; char tiny_data; @@ -2199,11 +2902,9 @@ void test_insert() bzero(bind, sizeof(bind)); strcpy(query,"INSERT INTO test_prep_insert VALUES(?,?)"); stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,2); /* tinyint */ bind[0].buffer_type=FIELD_TYPE_TINY; @@ -2238,7 +2939,7 @@ void test_insert() result = mysql_store_result(mysql); mytest(result); - assert((int)tiny_data == my_process_result_set(result)); + myassert((int)tiny_data == my_process_result_set(result)); mysql_free_result(result); } @@ -2246,10 +2947,10 @@ void test_insert() /******************************************************** * to test simple prepare-resultset info * *********************************************************/ -void test_prepare_resultset() +static void test_prepare_resultset() { MYSQL_STMT *stmt; - int rc,param_count; + int rc; char query[200]; MYSQL_RES *result; @@ -2268,38 +2969,15 @@ void test_prepare_resultset() name varchar(50),extra double)"); myquery(rc); - /* insert by prepare */ - strcpy(query,"INSERT INTO test_prepare_resultset(id,name) VALUES(?,?)"); - stmt = mysql_prepare(mysql, query, strlen(query)); - myxquery(stmt); + strcpy(query,"SELECT * FROM test_prepare_resultset"); + stmt = PREPARE(mysql, query); + mystmt_init(stmt); - param_count = mysql_param_count(stmt); - fprintf(stdout," total parameters in insert:%d\n", param_count); - assert(param_count == 2); + verify_param_count(stmt,0); - rc = mysql_query(mysql,"SELECT * FROM test_prepare_resultset"); - myquery(rc); - - /* get the prepared-result */ result = mysql_prepare_result(stmt); - assert( result != 0); - - my_print_result_metadata(result); - mysql_free_result(result); - - result = mysql_store_result(mysql); mytest(result); - - assert(0 == my_process_result_set(result)); - mysql_free_result(result); - - /* get the prepared-result */ - result = mysql_prepare_result(stmt); - assert( result != 0); - my_print_result_metadata(result); - mysql_free_result(result); - mysql_stmt_close(stmt); } @@ -2307,7 +2985,7 @@ void test_prepare_resultset() * to test field flags (verify .NET provider) * *********************************************************/ -void test_field_flags() +static void test_field_flags() { int rc; MYSQL_RES *result; @@ -2348,22 +3026,459 @@ void test_field_flags() for(i=0; i< mysql_num_fields(result); i++) { field = mysql_fetch_field(result); - printf("\nfield:%d",i); + fprintf(stdout,"\n field:%d",i); if(field->flags & NOT_NULL_FLAG) - printf("\n NOT_NULL_FLAG"); + fprintf(stdout,"\n NOT_NULL_FLAG"); if(field->flags & PRI_KEY_FLAG) - printf("\n PRI_KEY_FLAG"); + fprintf(stdout,"\n PRI_KEY_FLAG"); if(field->flags & UNIQUE_KEY_FLAG) - printf("\n UNIQUE_KEY_FLAG"); + fprintf(stdout,"\n UNIQUE_KEY_FLAG"); if(field->flags & MULTIPLE_KEY_FLAG) - printf("\n MULTIPLE_KEY_FLAG"); + fprintf(stdout,"\n MULTIPLE_KEY_FLAG"); if(field->flags & AUTO_INCREMENT_FLAG) - printf("\n AUTO_INCREMENT_FLAG"); + fprintf(stdout,"\n AUTO_INCREMENT_FLAG"); } mysql_free_result(result); } +/************************************************************** + * Test mysql_stmt_close for open stmts * +**************************************************************/ +static void test_stmt_close() +{ + MYSQL *lmysql; + MYSQL_STMT *stmt1, *stmt2, *stmt3, *stmt_x; + MYSQL_BIND param[1]; + MYSQL_RES *result; + char query[100]; + unsigned int count; + int rc; + + myheader("test_stmt_close"); + + init_bind(param); + if(!(lmysql = mysql_init(NULL))) + { + myerror("mysql_init() failed"); + exit(0); + } + if (!(mysql_real_connect(lmysql,opt_host,opt_user, + opt_password, opt_db ? opt_db:"inter_client_test_db", opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + exit(0); + } + if (opt_db) + strcpy(current_db,opt_db); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(lmysql, true); + mysql_query(lmysql,"DROP TABLE IF EXISTS test_stmt_close"); + mysql_query(lmysql,"CREATE TABLE test_stmt_close(id int)"); + + strcpy(query,"ALTER TABLE test_stmt_close ADD name varchar(20)"); + stmt1= PREPARE(lmysql, query); + mystmt_init(stmt1); + count= mysql_param_count(stmt1); + fprintf(stdout,"\n total params in alter: %d", count); + myassert(count == 0); + strcpy(query,"INSERT INTO test_stmt_close(id) VALUES(?)"); + stmt_x= PREPARE(mysql, query); + mystmt_init(stmt_x); + count= mysql_param_count(stmt_x); + fprintf(stdout,"\n total params in insert: %d", count); + myassert(count == 1); + strcpy(query,"UPDATE test_stmt_close SET id=? WHERE id=?"); + stmt3= PREPARE(lmysql, query); + mystmt_init(stmt3); + count= mysql_param_count(stmt3); + fprintf(stdout,"\n total params in update: %d", count); + myassert(count == 2); + strcpy(query,"SELECT * FROM test_stmt_close WHERE id=?"); + stmt2= PREPARE(lmysql, query); + mystmt_init(stmt2); + count= mysql_param_count(stmt2); + fprintf(stdout,"\n total params in select: %d", count); + myassert(count == 1); + + rc= mysql_stmt_close(stmt1); + fprintf(stdout,"\n mysql_close_stmt(1) returned: %d", rc); + myassert(rc == 0); + mysql_close(lmysql); /* it should free all stmts */ +#if NOT_VALID + rc= mysql_stmt_close(stmt3); + fprintf(stdout,"\n mysql_close_stmt(3) returned: %d", rc); + myassert( rc == 1); + rc= mysql_stmt_close(stmt2); + fprintf(stdout,"\n mysql_close_stmt(2) returned: %d", rc); + myassert( rc == 1); +#endif + + count= 100; + param[0].buffer=(gptr)&count; + param[0].buffer_type=MYSQL_TYPE_LONG; + rc = mysql_bind_param(stmt_x, param); + mystmt(stmt_x, rc); + rc = mysql_execute(stmt_x); + mystmt(stmt_x, rc); + + rc= (ulong)mysql_affected_rows(stmt_x->mysql); + fprintf(stdout,"\n total rows affected: %d", rc); + myassert (rc == 1); + + rc= mysql_stmt_close(stmt_x); + fprintf(stdout,"\n mysql_close_stmt(x) returned: %d", rc); + myassert( rc == 0); + + /*verify_col_data("test_stmt_close", "id", "100");*/ + rc = mysql_query(mysql,"SELECT id FROM test_stmt_close"); + myquery(rc); + + result = mysql_store_result(mysql); + mytest(result); + + myassert(1 == my_process_result_set(result)); + mysql_free_result(result); +} + +/******************************************************** + * To test simple set-variable prepare * +*********************************************************/ +static void test_set_variable() +{ + MYSQL_STMT *stmt; + int rc, select_limit=88; + char query[200]; + MYSQL_BIND bind[1]; + MYSQL_RES *result; + + + myheader("test_set_variable"); + + rc = mysql_autocommit(mysql, true); + myquery(rc); + + strcpy(query,"SET GLOBAL delayed_insert_limit=?"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,1); + + result= mysql_param_result(stmt); + mytest_r(result); + + init_bind(bind); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer=(gptr)&select_limit; + + rc = mysql_bind_param(stmt, bind); + mystmt(stmt,rc); + + rc= mysql_execute(stmt); + mystmt(stmt,rc); + + mysql_store_result(mysql); + + strcpy(query,"show variables like 'delayed_insert_limit'"); + rc = mysql_query(mysql,query); + myquery(rc); + + verify_col_data(NullS, NullS, "88"); + +#if TO_BE_FIXED + + select_limit= 100;/* reset to default */ + rc= mysql_execute(stmt); + mystmt(stmt,rc); + + mysql_store_result(mysql); + mysql_stmt_close(stmt); + + rc = mysql_query(mysql,query); + myquery(rc); + + verify_col_data(NullS, NullS, "100"); +#endif + mysql_stmt_close(stmt); +} +#if NOT_USED +/* Insert meta info .. */ +static void test_insert_meta() +{ + MYSQL_STMT *stmt; + int rc; + char query[200]; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_insert_meta"); + + rc = mysql_autocommit(mysql, true); + myquery(rc); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_prep_insert"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_prep_insert(col1 tinyint,\ + col2 varchar(50), col3 varchar(30))"); + myquery(rc); + + strcpy(query,"INSERT INTO test_prep_insert VALUES(10,'venu1','test')"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,0); + + result= mysql_param_result(stmt); + mytest_r(result); + + strcpy(query,"INSERT INTO test_prep_insert VALUES(?,'venu',?)"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,2); + + result= mysql_param_result(stmt); + mytest(result); + + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + field= mysql_fetch_field(result); + mytest(field); + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", field->name, "col1"); + myassert(strcmp(field->name,"col1")==0); + + field= mysql_fetch_field(result); + mytest(field); + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", field->name, "col3"); + myassert(strcmp(field->name,"col3")==0); + + field= mysql_fetch_field(result); + mytest_r(field); + + mysql_free_result(result); + mysql_stmt_close(stmt); +} + +/* Update meta info .. */ +static void test_update_meta() +{ + MYSQL_STMT *stmt; + int rc; + char query[200]; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_update_meta"); + + rc = mysql_autocommit(mysql, true); + myquery(rc); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_prep_update"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_prep_update(col1 tinyint,\ + col2 varchar(50), col3 varchar(30))"); + myquery(rc); + + strcpy(query,"UPDATE test_prep_update SET col1=10, col2='venu1' WHERE col3='test'"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,0); + + result= mysql_param_result(stmt); + mytest_r(result); + + strcpy(query,"UPDATE test_prep_update SET col1=?, col2='venu' WHERE col3=?"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,2); + + result= mysql_param_result(stmt); + mytest(result); + + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + field= mysql_fetch_field(result); + mytest(field); + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col1"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_update"); + myassert(strcmp(field->name,"col1")==0); + myassert(strcmp(field->table,"test_prep_update")==0); + + field= mysql_fetch_field(result); + mytest(field); + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col3"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_update"); + myassert(strcmp(field->name,"col3")==0); + myassert(strcmp(field->table,"test_prep_update")==0); + + field= mysql_fetch_field(result); + mytest_r(field); + + mysql_free_result(result); + mysql_stmt_close(stmt); +} + +/* Select meta info .. */ +static void test_select_meta() +{ + MYSQL_STMT *stmt; + int rc; + char query[200]; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_select_meta"); + + rc = mysql_autocommit(mysql, true); + myquery(rc); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_prep_select"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_prep_select(col1 tinyint,\ + col2 varchar(50), col3 varchar(30))"); + myquery(rc); + + strcpy(query,"SELECT * FROM test_prep_select WHERE col1=10"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,0); + + result= mysql_param_result(stmt); + mytest_r(result); + + strcpy(query,"SELECT col1, col3 from test_prep_select WHERE col1=? AND col3='test' AND col2= ?"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,2); + + result= mysql_param_result(stmt); + mytest(result); + + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + field= mysql_fetch_field(result); + mytest(field); + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col1"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_select"); + myassert(strcmp(field->name,"col1")==0); + myassert(strcmp(field->table,"test_prep_select")==0); + + field= mysql_fetch_field(result); + mytest(field); + fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col2"); + fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_select"); + myassert(strcmp(field->name,"col2")==0); + myassert(strcmp(field->table,"test_prep_select")==0); + + field= mysql_fetch_field(result); + mytest_r(field); + + mysql_free_result(result); + mysql_stmt_close(stmt); +} +#endif + +/* Test FUNCTION field info / DATE_FORMAT() table_name . */ +static void test_func_fields() +{ + int rc; + MYSQL_RES *result; + MYSQL_FIELD *field; + + myheader("test_func_fields"); + + rc = mysql_autocommit(mysql, true); + myquery(rc); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_dateformat"); + myquery(rc); + + rc = mysql_commit(mysql); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_dateformat(id int, \ + ts timestamp)"); + myquery(rc); + + rc = mysql_query(mysql, "INSERT INTO test_dateformat(id) values(10)"); + myquery(rc); + + rc = mysql_query(mysql, "SELECT ts FROM test_dateformat"); + myquery(rc); + + result = mysql_store_result(mysql); + mytest(result); + + field = mysql_fetch_field(result); + mytest(field); + fprintf(stdout,"\n table name: `%s` (expected: `%s`)", field->table, + "test_dateformat"); + myassert(strcmp(field->table, "test_dateformat")==0); + + field = mysql_fetch_field(result); + mytest_r(field); /* no more fields */ + + mysql_free_result(result); + + /* DATE_FORMAT */ + rc = mysql_query(mysql, "SELECT DATE_FORMAT(ts,'%Y') AS 'venu' FROM test_dateformat"); + myquery(rc); + + result = mysql_store_result(mysql); + mytest(result); + + field = mysql_fetch_field(result); + mytest(field); + fprintf(stdout,"\n table name: `%s` (expected: `%s`)", field->table, ""); + myassert(field->table[0] == '\0'); + + field = mysql_fetch_field(result); + mytest_r(field); /* no more fields */ + + mysql_free_result(result); + + /* FIELD ALIAS TEST */ + rc = mysql_query(mysql, "SELECT DATE_FORMAT(ts,'%Y') AS 'YEAR' FROM test_dateformat"); + myquery(rc); + + result = mysql_store_result(mysql); + mytest(result); + + field = mysql_fetch_field(result); + mytest(field); + fprintf(stdout,"\n field name: `%s` (expected: `%s`)", field->name, "YEAR"); + fprintf(stdout,"\n field org name: `%s` (expected: `%s`)",field->org_name,""); + myassert(strcmp(field->name, "YEAR")==0); + myassert(field->org_name[0] == '\0'); + + field = mysql_fetch_field(result); + mytest_r(field); /* no more fields */ + + mysql_free_result(result); +} + static struct my_option myctest_long_options[] = { {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, @@ -2398,24 +3513,24 @@ static void usage(void) puts("and you are welcome to modify and redistribute it under the GPL license\n"); puts(" Copyright (C) 1995-2002 MySQL AB "); puts("-----------------------------------------------------------------------\n"); - printf("usage: %s [OPTIONS]\n\n", my_progname); - printf("\ + fprintf(stdout,"usage: %s [OPTIONS]\n\n", my_progname); + fprintf(stdout,"\ -?, --help Display this help message and exit.\n\ -D --database=... Database name to be used for test.\n\ -h, --host=... Connect to host.\n\ -p, --password[=...] Password to use when connecting to server.\n"); #ifdef __WIN__ - printf("\ + fprintf(stdout,"\ -W, --pipe Use named pipes to connect to server.\n"); #endif - printf("\ + fprintf(stdout,"\ -P, --port=... Port number to use for connection.\n\ -S, --socket=... Socket file to use for connection.\n"); #ifndef DONT_ALLOW_USER_CHANGE - printf("\ + fprintf(stdout,"\ -u, --user=# User for login if not current user.\n"); #endif - printf("*********************************************************************\n"); + fprintf(stdout,"*********************************************************************\n"); } static my_bool @@ -2471,24 +3586,52 @@ int main(int argc, char **argv) MY_INIT(argv[0]); get_options(argc,argv); - client_connect(); /* connect to server */ - + client_connect(); /* connect to server */ + test_select_prepare(); + test_prepare(); + test_prepare_simple(); + test_bind_result(); /* result bind test */ + test_fetch_null(); /* to fetch null data */ + test_fetch_date(); + test_bind_result_ext(); /* result bind test - extension */ + test_bind_result_ext1(); /* result bind test - extension */ + test_select_direct(); /* direct select - protocol_simple debug */ + test_select_prepare(); /* prepare select - protocol_prep debug */ + test_select_direct(); /* direct select - protocol_simple debug */ + test_select(); + test_select_version(); + test_set_variable(); /* set variable prepare */ +#if NOT_USED + test_select_meta(); /* select param meta information */ + test_update_meta(); /* update param meta information */ + test_insert_meta(); /* insert param meta information */ +#endif + test_simple_update(); /* simple update test */ + test_func_fields(); + test_long_data(); + test_insert(); + test_set_variable(); + test_tran_innodb(); + test_select_version(); + test_select_simple(); + test_debug_example(); + test_select(); + test_select_show(); test_null(); /* test null data handling */ - test_simple_update(); - //test_select_simple(); - //test_prepare_resultset(); - //test_select(); /* simple prepare-select */ + test_simple_update(); + test_prepare_resultset(); + test_prepare_noparam();/* prepare without parameters */ + test_select(); /* simple prepare-select */ test_insert(); /* prepare with insert */ - //test_bind_result(); /* result bind test */ - //test_long_data(); /* long data handling in pieces */ + test_bind_result(); /* result bind test */ + test_long_data(); /* long data handling in pieces */ test_prepare_simple();/* simple prepare */ test_prepare(); /* prepare test */ - test_prepare_simple();/* simple prepare */ test_null(); /* test null data handling */ test_debug_example(); /* some debugging case */ test_update(); /* prepare-update test */ test_simple_update(); /* simple prepare with update */ - //test_long_data(); /* long data handling in pieces */ + test_long_data(); /* long data handling in pieces */ test_simple_delete(); /* prepare with delete */ test_field_names(); /* test for field names */ test_double_compare();/* float comparision */ @@ -2499,20 +3642,23 @@ int main(int argc, char **argv) test_tran_innodb(); /* transaction test on InnoDB table type */ test_prepare_ext(); /* test prepare with all types conversion -- TODO */ test_prepare_syntax();/* syntax check for prepares */ - //test_prepare_field_result(); /* prepare meta info */ + test_prepare_field_result(); /* prepare meta info */ + test_prepare_resultset(); test_field_names(); /* test for field names */ test_field_flags(); /* test to help .NET provider team */ - //test_long_data_str(); /* long data handling */ - //test_long_data_str1();/* yet another long data handling */ - //test_long_data_bin(); /* long binary insertion */ + test_long_data_str(); /* long data handling */ + test_long_data_str1();/* yet another long data handling */ + test_long_data_bin(); /* long binary insertion */ test_warnings(); /* show warnings test */ test_errors(); /* show errors test */ - //test_select_simple(); /* simple select prepare */ - //test_prepare_resultset();/* prepare meta info test */ - + test_select_simple(); /* simple select prepare */ + test_prepare_resultset();/* prepare meta info test */ + test_func_fields(); /* FUNCTION field info */ + /*test_stmt_close(); */ /* mysql_stmt_close() test -- hangs */ + test_prepare_field_result(); /* prepare meta info */ client_disconnect(); /* disconnect from server */ - - fprintf(stdout,"\ndone !!!\n"); + + fprintf(stdout,"\n\nSUCCESS !!!\n"); return(0); } |