mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			299 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (C) 2006 MySQL AB & Ramil Kalimullin
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation; version 2 of the License.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
 | |
| 
 | |
| #include "maria_def.h"
 | |
| #include "ma_blockrec.h"                        /* For ROW_FLAG_TRANSID */
 | |
| #include "trnman.h"
 | |
| 
 | |
| #include "ma_sp_defs.h"
 | |
| 
 | |
| static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                              uchar byte_order, double *mbr);
 | |
| static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                            uchar byte_order, double *mbr);
 | |
| static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                                 uchar byte_order, double *mbr);
 | |
| static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                              uchar byte_order, double *mbr);
 | |
| static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                               double *mbr, int top);
 | |
| static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr);
 | |
| 
 | |
| 
 | |
| /**
 | |
|    Create spatial key
 | |
| */
 | |
| 
 | |
| MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr,
 | |
|                            uchar *key, const uchar *record, my_off_t filepos,
 | |
|                            ulonglong trid)
 | |
| {
 | |
|   HA_KEYSEG *keyseg;
 | |
|   MARIA_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
 | |
|   uint len = 0;
 | |
|   const uchar *pos;
 | |
|   uint dlen;
 | |
|   uchar *dptr;
 | |
|   double mbr[SPDIMS * 2];
 | |
|   uint i;
 | |
|   DBUG_ENTER("_ma_sp_make_key");
 | |
| 
 | |
|   keyseg = &keyinfo->seg[-1];
 | |
|   pos = record + keyseg->start;
 | |
|   ret_key->data= key;
 | |
| 
 | |
|   dlen = _ma_calc_blob_length(keyseg->bit_start, pos);
 | |
|   memcpy(&dptr, pos + keyseg->bit_start, sizeof(char*));
 | |
|   if (!dptr)
 | |
|   {
 | |
|     my_errno= HA_ERR_NULL_IN_SPATIAL;
 | |
|     DBUG_RETURN(0);
 | |
|   }
 | |
| 
 | |
|   sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr);	/* SRID */
 | |
| 
 | |
|   for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
 | |
|   {
 | |
|     uint length = keyseg->length, start= keyseg->start;
 | |
|     double val;
 | |
| 
 | |
|     DBUG_ASSERT(length == 8);
 | |
|     DBUG_ASSERT(!(start % 8));
 | |
|     DBUG_ASSERT(start < sizeof(mbr));
 | |
|     DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
 | |
| 
 | |
|     val= mbr[start / sizeof (double)];
 | |
|     if (isnan(val))
 | |
|     {
 | |
|       bzero(key, length);
 | |
|       key+= length;
 | |
|       len+= length;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (keyseg->flag & HA_SWAP_KEY)
 | |
|     {
 | |
|       mi_float8store(key, val);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       float8store((uchar *)key, val);
 | |
|     }
 | |
|     key += length;
 | |
|     len+= length;
 | |
|   }
 | |
|   _ma_dpointer(info->s, key, filepos);
 | |
|   ret_key->keyinfo= keyinfo;
 | |
|   ret_key->data_length= len;
 | |
|   ret_key->ref_length= info->s->rec_reflength;
 | |
|   ret_key->flag= 0;
 | |
|   if (_ma_have_versioning(info) && trid)
 | |
|   {
 | |
|     ret_key->ref_length+= transid_store_packed(info,
 | |
|                                                key + ret_key->ref_length,
 | |
|                                                trid);
 | |
|   }
 | |
|   DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, ret_key););
 | |
|   DBUG_RETURN(ret_key);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Calculate minimal bounding rectangle (mbr) of the spatial object
 | |
|   stored in "well-known binary representation" (wkb) format.
 | |
| */
 | |
| 
 | |
| static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
 | |
| {
 | |
|   uint i;
 | |
| 
 | |
|   for (i=0; i < n_dims; ++i)
 | |
|   {
 | |
|     mbr[i * 2] = DBL_MAX;
 | |
|     mbr[i * 2 + 1] = -DBL_MAX;
 | |
|   }
 | |
| 
 | |
|   return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1);
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Add one point stored in wkb to mbr
 | |
| */
 | |
| 
 | |
| static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
| 			       uchar byte_order __attribute__((unused)),
 | |
| 			       double *mbr)
 | |
| {
 | |
|   double ord;
 | |
|   double *mbr_end= mbr + n_dims * 2;
 | |
| 
 | |
|   while (mbr < mbr_end)
 | |
|   {
 | |
|     if ((*wkb) > end - 8)
 | |
|       return -1;
 | |
|     float8get(ord, (const uchar*) *wkb);
 | |
|     (*wkb)+= 8;
 | |
|     if (ord < *mbr)
 | |
|       *mbr= ord;
 | |
|     mbr++;
 | |
|     if (ord > *mbr)
 | |
|       *mbr= ord;
 | |
|     mbr++;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                            uchar byte_order, double *mbr)
 | |
| {
 | |
|   return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
 | |
| }
 | |
| 
 | |
| 
 | |
| static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                                   uchar byte_order, double *mbr)
 | |
| {
 | |
|   uint n_points;
 | |
| 
 | |
|   n_points = uint4korr(*wkb);
 | |
|   (*wkb) += 4;
 | |
|   for (; n_points > 0; --n_points)
 | |
|   {
 | |
|     /* Add next point to mbr */
 | |
|     if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
 | |
|       return -1;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                                uchar byte_order, double *mbr)
 | |
| {
 | |
|   uint n_linear_rings;
 | |
|   uint n_points;
 | |
| 
 | |
|   n_linear_rings = uint4korr((*wkb));
 | |
|   (*wkb) += 4;
 | |
| 
 | |
|   for (; n_linear_rings > 0; --n_linear_rings)
 | |
|   {
 | |
|     n_points = uint4korr((*wkb));
 | |
|     (*wkb) += 4;
 | |
|     for (; n_points > 0; --n_points)
 | |
|     {
 | |
|       /* Add next point to mbr */
 | |
|       if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
 | |
|         return -1;
 | |
|     }
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
 | |
|                               double *mbr, int top)
 | |
| {
 | |
|   int res;
 | |
|   uchar byte_order;
 | |
|   uint wkb_type;
 | |
| 
 | |
|   byte_order = *(*wkb);
 | |
|   ++(*wkb);
 | |
| 
 | |
|   wkb_type = uint4korr((*wkb));
 | |
|   (*wkb) += 4;
 | |
| 
 | |
|   switch ((enum wkbType) wkb_type)
 | |
|   {
 | |
|     case wkbPoint:
 | |
|       res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
 | |
|       break;
 | |
|     case wkbLineString:
 | |
|       res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
 | |
|       break;
 | |
|     case wkbPolygon:
 | |
|       res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
 | |
|       break;
 | |
|     case wkbMultiPoint:
 | |
|     {
 | |
|       uint n_items;
 | |
|       n_items = uint4korr((*wkb));
 | |
|       (*wkb) += 4;
 | |
|       for (; n_items > 0; --n_items)
 | |
|       {
 | |
|         byte_order = *(*wkb);
 | |
|         ++(*wkb);
 | |
|         (*wkb) += 4;
 | |
|         if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
 | |
|           return -1;
 | |
|       }
 | |
|       res = 0;
 | |
|       break;
 | |
|     }
 | |
|     case wkbMultiLineString:
 | |
|     {
 | |
|       uint n_items;
 | |
|       n_items = uint4korr((*wkb));
 | |
|       (*wkb) += 4;
 | |
|       for (; n_items > 0; --n_items)
 | |
|       {
 | |
|         byte_order = *(*wkb);
 | |
|         ++(*wkb);
 | |
|         (*wkb) += 4;
 | |
|         if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
 | |
|           return -1;
 | |
|       }
 | |
|       res = 0;
 | |
|       break;
 | |
|     }
 | |
|     case wkbMultiPolygon:
 | |
|     {
 | |
|       uint n_items;
 | |
|       n_items = uint4korr((*wkb));
 | |
|       (*wkb) += 4;
 | |
|       for (; n_items > 0; --n_items)
 | |
|       {
 | |
|         byte_order = *(*wkb);
 | |
|         ++(*wkb);
 | |
|         (*wkb) += 4;
 | |
|         if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
 | |
|           return -1;
 | |
|       }
 | |
|       res = 0;
 | |
|       break;
 | |
|     }
 | |
|     case wkbGeometryCollection:
 | |
|     {
 | |
|       uint n_items;
 | |
| 
 | |
|       if (!top)
 | |
|         return -1;
 | |
| 
 | |
|       n_items = uint4korr((*wkb));
 | |
|       (*wkb) += 4;
 | |
|       for (; n_items > 0; --n_items)
 | |
|       {
 | |
|         if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
 | |
|           return -1;
 | |
|       }
 | |
|       res = 0;
 | |
|       break;
 | |
|     }
 | |
|     default:
 | |
|       res = -1;
 | |
|   }
 | |
|   return res;
 | |
| }
 | 
