Added GIS extension

parent fc74d81b
......@@ -460,3 +460,5 @@ vio/test-sslserver
vio/viotest-ssl
Docs/mysql.xml
mysql-test/r/rpl000001.eval
myisam/rt_test
myisam/sp_test
......@@ -53,7 +53,8 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
sql_rename.cc sql_repl.cc sql_select.cc sql_do.cc sql_show.cc \
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
spatial.cc gstream.cc
EXTRA_DIST = lib_vio.c
......
......@@ -81,7 +81,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
slave.cc sql_repl.cc sql_union.cc \
mini_client.cc mini_client_errors.c \
stacktrace.c repl_failsafe.h repl_failsafe.cc
stacktrace.c repl_failsafe.h repl_failsafe.cc \
gstream.cc spatial.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
......
......@@ -3712,7 +3712,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
:Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
table_arg),
packlength(blob_pack_length),binary_flag(binary_arg)
packlength(blob_pack_length),binary_flag(binary_arg), geom_flag(true)
{
flags|= BLOB_FLAG;
if (binary_arg)
......@@ -3954,8 +3954,30 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
void Field_blob::get_key_image(char *buff,uint length)
void Field_blob::get_key_image(char *buff,uint length, imagetype type)
{
if(type == itMBR)
{
length-=HA_KEY_BLOB_LENGTH;
ulong blob_length=get_length(ptr);
char *blob;
get_ptr(&blob);
if(!blob_length)
{
return;
}
MBR mbr;
Geometry gobj;
gobj.create_from_wkb(blob,blob_length);
gobj.get_mbr(&mbr);
float8store(buff, mbr.xmin);
float8store(buff+8, mbr.xmax);
float8store(buff+16, mbr.ymin);
float8store(buff+24, mbr.ymax);
return;
}
length-=HA_KEY_BLOB_LENGTH;
uint32 blob_length=get_length(ptr);
char *blob;
......@@ -3977,6 +3999,31 @@ void Field_blob::set_key_image(char *buff,uint length)
Field_blob::store(buff+2,length);
}
void Field_geom::get_key_image(char *buff,uint length, imagetype type)
{
length-=HA_KEY_BLOB_LENGTH;
ulong blob_length=get_length(ptr);
char *blob;
get_ptr(&blob);
memcpy(buff+2,blob,length);
MBR mbr;
Geometry gobj;
gobj.create_from_wkb(blob,blob_length);
gobj.get_mbr(&mbr);
float8store(buff, mbr.xmin);
float8store(buff+8, mbr.xmax);
float8store(buff+16, mbr.ymin);
float8store(buff+24, mbr.ymax);
return;
}
void Field_geom::set_key_image(char *buff,uint length)
{
}
int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
{
char *blob1;
......@@ -4606,6 +4653,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_SET:
case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
default: return 0;
}
return 0; // This shouldn't happen
}
......@@ -4652,6 +4700,11 @@ Field *make_field(char *ptr, uint32 field_length,
return new Field_blob(ptr,null_pos,null_bit,
unireg_check, field_name, table,
pack_length,f_is_binary(pack_flag) != 0);
if (f_is_geom(pack_flag))
return new Field_geom(ptr,null_pos,null_bit,
unireg_check, field_name, table,
pack_length,f_is_binary(pack_flag) != 0);
if (interval)
{
if (f_is_enum(pack_flag))
......
......@@ -47,6 +47,9 @@ class Field {
enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
enum imagetype { itRAW, itMBR};
utype unireg_check;
uint32 field_length; // Length of field
uint16 flags;
......@@ -137,7 +140,7 @@ class Field {
{ memcpy(buff,ptr,length); }
inline void set_image(char *buff,uint length)
{ memcpy(ptr,buff,length); }
virtual void get_key_image(char *buff,uint length)
virtual void get_key_image(char *buff,uint length, imagetype type)
{ get_image(buff,length); }
virtual void set_key_image(char *buff,uint length)
{ set_image(buff,length); }
......@@ -825,6 +828,7 @@ class Field_blob :public Field_str {
uint packlength;
String value; // For temporaries
bool binary_flag;
bool geom_flag;
public:
Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
......@@ -834,7 +838,7 @@ class Field_blob :public Field_str {
struct st_table *table_arg, bool binary_arg)
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, table_arg),
packlength(3),binary_flag(binary_arg)
packlength(3),binary_flag(binary_arg), geom_flag(true)
{
flags|= BLOB_FLAG;
if (binary_arg)
......@@ -881,7 +885,7 @@ class Field_blob :public Field_str {
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
void get_key_image(char *buff,uint length);
void get_key_image(char *buff,uint length, imagetype type);
void set_key_image(char *buff,uint length);
void sql_type(String &str) const;
inline bool copy()
......@@ -910,6 +914,25 @@ class Field_blob :public Field_str {
};
class Field_geom :public Field_blob {
public:
Field_geom(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
bool binary_arg)
:Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
field_name_arg, table_arg, blob_pack_length,binary_arg) {}
Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, bool binary_arg)
:Field_blob(len_arg, maybe_null_arg, field_name_arg,
table_arg, binary_arg) {}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY; }
void get_key_image(char *buff,uint length, imagetype type);
void set_key_image(char *buff,uint length);
};
class Field_enum :public Field_str {
protected:
uint packlength;
......@@ -1059,6 +1082,8 @@ bool test_if_int(const char *str,int length);
#define FIELDFLAG_INTERVAL 256
#define FIELDFLAG_BITFIELD 512 // mangled with dec!
#define FIELDFLAG_BLOB 1024 // mangled with dec!
#define FIELDFLAG_GEOM 2048
#define FIELDFLAG_LEFT_FULLSCREEN 8192
#define FIELDFLAG_RIGHT_FULLSCREEN 16384
#define FIELDFLAG_FORMAT_NUMBER 16384 // predit: ###,,## in output
......@@ -1085,6 +1110,7 @@ bool test_if_int(const char *str,int length);
#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
#define f_is_bitfield(x) ((x) & FIELDFLAG_BITFIELD)
#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB)
#define f_is_geom(x) ((x) & FIELDFLAG_GEOM)
#define f_is_equ(x) ((x) & (1+2+FIELDFLAG_PACK+31*256))
#define f_settype(x) (((int) x) << FIELDFLAG_PACK_SHIFT)
#define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL)
#include "mysql_priv.h"
int GTextReadStream::get_next_toc_type() const
{
const char *cur = m_cur;
while((*cur)&&(strchr(" \t\r\n",*cur)))
{
cur++;
}
if(!(*cur))
{
return eostream;
}
if(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_'))
{
return word;
}
if(((*cur>='0') && (*cur<='9')) || (*cur=='-') || (*cur=='+') || (*cur=='.'))
{
return numeric;
}
if(*cur == '(')
{
return l_bra;
}
if(*cur == ')')
{
return r_bra;
}
if(*cur == ',')
{
return comma;
}
return unknown;
}
const char *GTextReadStream::get_next_word(int *word_len)
{
const char *cur = m_cur;
while((*cur)&&(strchr(" \t\r\n",*cur)))
{
cur++;
}
m_last_text_position = cur;
if(!(*cur))
{
return 0;
}
const char *wd_start = 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')))
{
++cur;
}
*word_len = cur - wd_start;
m_cur = cur;
return wd_start;
}
int GTextReadStream::get_next_number(double *d)
{
const char *cur = m_cur;
while((*cur)&&(strchr(" \t\r\n",*cur)))
{
cur++;
}
m_last_text_position = cur;
if(!(*cur))
{
set_error_msg("Numeric constant expected");
return 1;
}
if(((*cur<'0') || (*cur>'9')) && (*cur!='-') && (*cur!='+') && (*cur!='.'))
{
set_error_msg("Numeric constant expected");
return 1;
}
char *endptr;
*d = strtod(cur, &endptr);
if(endptr)
{
m_cur = endptr;
}
return 0;
}
char GTextReadStream::get_next_symbol()
{
const char *cur = m_cur;
while((*cur)&&(strchr(" \t\r\n",*cur)))
{
cur++;
}
if(!(*cur))
{
return 0;
}
m_cur = cur + 1;
m_last_text_position = cur;
return *cur;
}
void GTextReadStream::set_error_msg(const char *msg)
{
size_t len = strlen(msg);
m_err_msg = (char *)my_realloc(m_err_msg, len + 1, MYF(MY_ALLOW_ZERO_PTR));
memcpy(m_err_msg, msg, len + 1);
}
#ifndef GSTREAM_H
#define GSTREAM_H
#ifdef WITHOUT_MYSQL
#include ".\rtree\myisamdef.h"
#else
#include "mysql_priv.h"
#endif
class GTextReadStream
{
public:
enum TokTypes
{
unknown,
eostream,
word,
numeric,
l_bra,
r_bra,
comma,
};
GTextReadStream(const char *buffer, int size) :
m_cur(buffer), m_limit(buffer + size), m_last_text_position(buffer), m_err_msg(NULL) {}
GTextReadStream() : m_cur(NULL), m_limit(NULL), m_err_msg(NULL) {}
~GTextReadStream()
{
my_free(m_err_msg, MYF(MY_ALLOW_ZERO_PTR));
}
int get_next_toc_type() const;
const char *get_next_word(int *word_len);
int get_next_number(double *d);
char get_next_symbol();
const char *get_last_text_position() const
{
return m_last_text_position;
}
void set_error_msg(const char *msg);
// caller should free this pointer
char *get_error_msg()
{
char *err_msg = m_err_msg;
m_err_msg = NULL;
return err_msg;
}
protected:
const char *m_cur;
const char *m_limit;
const char *m_last_text_position;
char *m_err_msg;
};
#endif
......@@ -28,6 +28,7 @@
#include "../srclib/myisam/myisamdef.h"
#else
#include "../myisam/myisamdef.h"
#include "../myisam/rt_index.h"
#endif
ulong myisam_sort_buffer_size;
......@@ -763,7 +764,7 @@ int ha_myisam::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
statistic_increment(ha_read_key_count,&LOCK_status);
int error=mi_rkey(file,buf,active_index, key, key_len, find_flag);
int error=mi_rkey(file,buf,active_index, key, key_len, (enum ha_rkey_function)find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
......@@ -772,7 +773,7 @@ int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
statistic_increment(ha_read_key_count,&LOCK_status);
int error=mi_rkey(file,buf,index, key, key_len, find_flag);
int error=mi_rkey(file,buf,index, key, key_len, (enum ha_rkey_function)find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
......@@ -1008,7 +1009,8 @@ int ha_myisam::create(const char *name, register TABLE *table,
pos=table->key_info;
for (i=0; i < table->keys ; i++, pos++)
{
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT));
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
keydef[i].key_alg=pos->key_alg; // +BAR
keydef[i].seg=keyseg;
keydef[i].keysegs=pos->key_parts;
for (j=0 ; j < pos->key_parts ; j++)
......
......@@ -357,6 +357,7 @@ class Item_ref :public Item_ident
};
#include "spatial.h"
#include "item_sum.h"
#include "item_func.h"
#include "item_cmpfunc.h"
......
......@@ -24,6 +24,7 @@
#include "mysql_priv.h"
#include <m_ctype.h>
/*
** Test functions
** These returns 0LL if false and 1LL if true and null if some arg is null
......@@ -1348,3 +1349,83 @@ Item_func_regex::~Item_func_regex()
}
#endif /* USE_REGEX */
/****************************************************************
Classes and functions for spatial relations
*****************************************************************/
longlong Item_func_spatial_rel::val_int()
{
String *res1=args[0]->val_str(&tmp_value1);
String *res2=args[1]->val_str(&tmp_value2);
Geometry g1, g2;
MBR mbr1,mbr2;
if ((null_value=(args[0]->null_value ||
args[1]->null_value ||
g1.create_from_wkb(res1->ptr(),res1->length()) ||
g2.create_from_wkb(res2->ptr(),res2->length()) ||
g1.get_mbr(&mbr1) ||
g2.get_mbr(&mbr2))))
return 0;
switch (spatial_rel)
{
case SP_CONTAINS_FUNC:
return mbr1.contains(&mbr2);
case SP_WITHIN_FUNC:
return mbr1.within(&mbr2);
case SP_EQUALS_FUNC:
return mbr1.equals(&mbr2);
case SP_DISJOINT_FUNC:
return mbr1.disjoint(&mbr2);
case SP_INTERSECTS_FUNC:
return mbr1.intersects(&mbr2);
case SP_TOUCHES_FUNC:
return mbr1.touches(&mbr2);
case SP_OVERLAPS_FUNC:
return mbr1.overlaps(&mbr2);
case SP_CROSSES_FUNC:
return 0;
default:
break;
}
null_value=1;
return 0;
}
longlong Item_func_isempty::val_int()
{
String tmp;
null_value=0;
return args[0]->null_value ? 1 : 0;
}
longlong Item_func_issimple::val_int()
{
String tmp;
String *wkb=args[0]->val_str(&tmp);
if ((null_value= (!wkb || args[0]->null_value )))
return 0;
/* TODO: Ramil or Holyfoot, add real IsSimple calculation */
return 0;
}
longlong Item_func_isclosed::val_int()
{
String tmp;
String *wkb=args[0]->val_str(&tmp);
Geometry geom;
int isclosed;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,is_closed) ||
geom.is_closed(&isclosed));
return (longlong) isclosed;
}
......@@ -570,3 +570,82 @@ inline Item *and_conds(Item *a,Item *b)
cond->update_used_tables();
return cond;
}
/**************************************************************
Spatial relations
***************************************************************/
class Item_func_spatial_rel :public Item_bool_func2
{
enum Functype spatial_rel;
public:
Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) :
Item_bool_func2(a,b) { spatial_rel = sp_rel; }
longlong val_int();
enum Functype functype() const
{
switch (spatial_rel)
{
case SP_CONTAINS_FUNC:
return SP_WITHIN_FUNC;
case SP_WITHIN_FUNC:
return SP_CONTAINS_FUNC;
default:
return spatial_rel;
}
}
enum Functype rev_functype() const { return spatial_rel; }
const char *func_name() const
{
switch (spatial_rel)
{
case SP_CONTAINS_FUNC:
return "contains";
case SP_WITHIN_FUNC:
return "within";
case SP_EQUALS_FUNC:
return "equals";
case SP_DISJOINT_FUNC:
return "disjoint";
case SP_INTERSECTS_FUNC:
return "intersects";
case SP_TOUCHES_FUNC:
return "touches";
case SP_CROSSES_FUNC:
return "crosses";
case SP_OVERLAPS_FUNC:
return "overlaps";
default:
return "sp_unknown";
}
}
};
class Item_func_isempty :public Item_bool_func
{
public:
Item_func_isempty(Item *a) :Item_bool_func(a) {}
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "isempty"; }
};
class Item_func_issimple :public Item_bool_func
{
public:
Item_func_issimple(Item *a) :Item_bool_func(a) {}
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "issimple"; }
};
class Item_func_isclosed :public Item_bool_func
{
public:
Item_func_isclosed(Item *a) :Item_bool_func(a) {}
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "isclosed"; }
};
......@@ -413,3 +413,158 @@ Item *create_func_cast(Item *a, Item_cast cast_type)
}
return res;
}
Item *create_func_geometry_from_text(Item* a)
{
return new Item_func_geometry_from_text(a);
}
Item *create_func_as_text(Item* a)
{
return new Item_func_as_text(a);
}
Item *create_func_startpoint(Item* a)
{
return new Item_func_spatial_decomp(a, Item_func::SP_STARTPOINT);
}
Item *create_func_endpoint(Item* a)
{
return new Item_func_spatial_decomp(a, Item_func::SP_ENDPOINT);
}
Item *create_func_exteriorring(Item* a)
{
return new Item_func_spatial_decomp(a, Item_func::SP_EXTERIORRING);
}
Item *create_func_pointn(Item* a, Item* b)
{
return new Item_func_spatial_decomp_n(a,b,Item_func::SP_POINTN);
}
Item *create_func_interiorringn(Item* a, Item* b)
{
return new Item_func_spatial_decomp_n(a,b,Item_func::SP_INTERIORRINGN);
}
Item *create_func_geometryn(Item* a, Item* b)
{
return new Item_func_spatial_decomp_n(a,b,Item_func::SP_GEOMETRYN);
}
Item *create_func_centroid(Item* a)
{
return new Item_func_centroid(a);
}
Item *create_func_envelope(Item* a)
{
return new Item_func_envelope(a);
}
Item *create_func_equals(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_EQUALS_FUNC);
}
Item *create_func_disjoint(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_DISJOINT_FUNC);
}
Item *create_func_intersects(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_INTERSECTS_FUNC);
}
Item *create_func_touches(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_TOUCHES_FUNC);
}
Item *create_func_crosses(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_CROSSES_FUNC);
}
Item *create_func_within(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_WITHIN_FUNC);
}
Item *create_func_contains(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_CONTAINS_FUNC);
}
Item *create_func_overlaps(Item* a, Item* b)
{
return new Item_func_spatial_rel(a, b, Item_func::SP_OVERLAPS_FUNC);
}
Item *create_func_isempty(Item* a)
{
return new Item_func_isempty(a);
}
Item *create_func_issimple(Item* a)
{
return new Item_func_issimple(a);
}
Item *create_func_isclosed(Item* a)
{
return new Item_func_isclosed(a);
}
Item *create_func_geometry_type(Item* a)
{
return new Item_func_geometry_type(a);
}
Item *create_func_dimension(Item* a)
{
return new Item_func_dimension(a);
}
Item *create_func_x(Item* a)
{
return new Item_func_x(a);
}
Item *create_func_y(Item* a)
{
return new Item_func_y(a);
}
Item *create_func_numpoints(Item* a)
{
return new Item_func_numpoints(a);
}
Item *create_func_numinteriorring(Item* a)
{
return new Item_func_numinteriorring(a);
}
Item *create_func_numgeometries(Item* a)
{
return new Item_func_numgeometries(a);
}
Item *create_func_area(Item* a)
{
return new Item_func_area(a);
}
Item *create_func_glength(Item* a)
{
return new Item_func_glength(a);
}
Item *create_func_point(Item* a, Item* b)
{
return new Item_func_point(a,b);
}
......@@ -88,3 +88,41 @@ Item *create_func_version(void);
Item *create_func_weekday(Item* a);
Item *create_load_file(Item* a);
Item *create_wait_for_master_pos(Item* a, Item* b);
Item *create_func_geometry_from_text(Item* a);
Item *create_func_as_text(Item* a);
Item *create_func_startpoint(Item* a);
Item *create_func_endpoint(Item* a);
Item *create_func_exteriorring(Item* a);
Item *create_func_centroid(Item* a);
Item *create_func_envelope(Item* a);
Item *create_func_pointn(Item* a, Item* b);
Item *create_func_interiorringn(Item* a, Item* b);
Item *create_func_geometryn(Item* a, Item* b);
Item *create_func_equals(Item* a, Item* b);
Item *create_func_disjoint(Item* a, Item* b);
Item *create_func_intersects(Item* a, Item* b);
Item *create_func_touches(Item* a, Item* b);
Item *create_func_crosses(Item* a, Item* b);
Item *create_func_within(Item* a, Item* b);
Item *create_func_contains(Item* a, Item* b);
Item *create_func_overlaps(Item* a, Item* b);
Item *create_func_isempty(Item* a);
Item *create_func_issimple(Item* a);
Item *create_func_isclosed(Item* a);
Item *create_func_geometry_type(Item* a);
Item *create_func_dimension(Item* a);
Item *create_func_x(Item* a);
Item *create_func_y(Item* a);
Item *create_func_area(Item* a);
Item *create_func_glength(Item* a);
Item *create_func_numpoints(Item* a);
Item *create_func_numinteriorring(Item* a);
Item *create_func_numgeometries(Item* a);
Item *create_func_point(Item* a,Item* b);
......@@ -27,6 +27,8 @@
#include <time.h>
#include <ft_global.h>
#include "slave.h" // for wait_for_master_pos
#include "gstream.h"
/* return TRUE if item is a constant */
......@@ -2252,3 +2254,130 @@ Item *get_system_var(LEX_STRING name)
my_error(ER_UNKNOWN_SYSTEM_VARIABLE,MYF(0),name);
return 0;
}
/**************************************************************************
Spatial functions
***************************************************************************/
longlong Item_func_dimension::val_int()
{
uint32 dim;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
geom.dimension(&dim));
return (longlong) dim;
}
longlong Item_func_numinteriorring::val_int()
{
uint32 num;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,num_interior_ring) ||
geom.num_interior_ring(&num));
return (longlong) num;
}
longlong Item_func_numgeometries::val_int()
{
uint32 num;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,num_geometries) ||
geom.num_geometries(&num));
return (longlong) num;
}
longlong Item_func_numpoints::val_int()
{
uint32 num;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,num_points) ||
geom.num_points(&num));
return (longlong) num;
}
double Item_func_x::val()
{
double res;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,get_x) ||
geom.get_x(&res));
return res;
}
double Item_func_y::val()
{
double res;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,get_y) ||
geom.get_y(&res));
return res;
}
double Item_func_area::val()
{
double res;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,area) ||
geom.area(&res));
return res;
}
double Item_func_glength::val()
{
double res;
String *wkb=args[0]->val_str(&value);
Geometry geom;
null_value= (!wkb ||
args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,length) ||
geom.length(&res));
return res;
}
......@@ -39,7 +39,12 @@ class Item_func :public Item_result_field
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
GE_FUNC,GT_FUNC,FT_FUNC,
LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
COND_AND_FUNC,COND_OR_FUNC,BETWEEN,IN_FUNC,INTERVAL_FUNC};
COND_AND_FUNC,COND_OR_FUNC,BETWEEN,IN_FUNC,INTERVAL_FUNC,
SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN};
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
......@@ -944,6 +949,86 @@ class Item_func_match :public Item_real_func
void init_search(bool no_order);
};
class Item_func_dimension :public Item_int_func
{
String value;
public:
Item_func_dimension(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "dimension"; }
void fix_length_and_dec() { max_length=10; }
};
class Item_func_x :public Item_real_func
{
String value;
public:
Item_func_x(Item *a) :Item_real_func(a) {}
double val();
const char *func_name() const { return "x"; }
};
class Item_func_y :public Item_real_func
{
String value;
public:
Item_func_y(Item *a) :Item_real_func(a) {}
double val();
const char *func_name() const { return "y"; }
};
class Item_func_numgeometries :public Item_int_func
{
String value;
public:
Item_func_numgeometries(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "numgeometries"; }
void fix_length_and_dec() { max_length=10; }
};
class Item_func_numinteriorring :public Item_int_func
{
String value;
public:
Item_func_numinteriorring(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "numinteriorring"; }
void fix_length_and_dec() { max_length=10; }
};
class Item_func_numpoints :public Item_int_func
{
String value;
public:
Item_func_numpoints(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "numpoints"; }
void fix_length_and_dec() { max_length=10; }
};
class Item_func_area :public Item_real_func
{
String value;
public:
Item_func_area(Item *a) :Item_real_func(a) {}
double val();
const char *func_name() const { return "area"; }
};
class Item_func_glength :public Item_real_func
{
String value;
public:
Item_func_glength(Item *a) :Item_real_func(a) {}
double val();
const char *func_name() const { return "glength"; }
};
class Item_func_match_nl :public Item_func_match
{
public:
......
......@@ -1953,3 +1953,333 @@ String* Item_func_inet_ntoa::val_str(String* str)
str->length(str->length()-1); // Remove last '.';
return str;
}
/*******************************************************
General functions for spatial objects
********************************************************/
#include "gstream.h"
String *Item_func_geometry_from_text::val_str(String *str)
{
Geometry geom;
String *wkt = args[0]->val_str(str);
GTextReadStream trs(wkt->ptr(), wkt->length());
str->length(0);
if ((null_value=(args[0]->null_value || geom.create_from_wkt(&trs, str, 0))))
return 0;
return str;
}
void Item_func_geometry_from_text::fix_length_and_dec()
{
max_length=MAX_BLOB_WIDTH;
}
String *Item_func_as_text::val_str(String *str)
{
String *wkt = args[0]->val_str(str);
Geometry geom;
str->length(0);
if ((null_value=(args[0]->null_value ||
geom.create_from_wkb(wkt->ptr(),wkt->length()) ||
geom.as_wkt(str))))
return 0;
return str;
}
void Item_func_as_text::fix_length_and_dec()
{
max_length=MAX_BLOB_WIDTH;
}
String *Item_func_geometry_type::val_str(String *str)
{
String *wkt = args[0]->val_str(str);
Geometry geom;
if ((null_value=(args[0]->null_value ||
geom.create_from_wkb(wkt->ptr(),wkt->length()))))
return 0;
str->copy(geom.get_class_info()->m_name);
return str;
}
String *Item_func_envelope::val_str(String *str)
{
String *wkb = args[0]->val_str(str);
Geometry geom;
null_value = args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
geom.envelope(str);
return null_value ? 0 : str;
}
String *Item_func_centroid::val_str(String *str)
{
String *wkb = args[0]->val_str(str);
Geometry geom;
null_value = args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,centroid) ||
geom.centroid(str);
return null_value ? 0: str;
}
/***********************************************
Spatial decomposition functions
***********************************************/
String *Item_func_spatial_decomp::val_str(String *str)
{
String *wkb = args[0]->val_str(str);
Geometry geom;
if ((null_value = (args[0]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()))))
return 0;
null_value=1;
switch(decomp_func)
{
case SP_STARTPOINT:
if (!GEOM_METHOD_PRESENT(geom,start_point) || geom.start_point(str))
goto ret;
break;
case SP_ENDPOINT:
if (!GEOM_METHOD_PRESENT(geom,end_point) || geom.end_point(str))
goto ret;
break;
case SP_EXTERIORRING:
if (!GEOM_METHOD_PRESENT(geom,exterior_ring) || geom.exterior_ring(str))
goto ret;
break;
default:
goto ret;
}
null_value=0;
ret:
return null_value ? 0 : str;
}
String *Item_func_spatial_decomp_n::val_str(String *str)
{
String *wkb = args[0]->val_str(str);
long n = (long) args[1]->val_int();
Geometry geom;
if ((null_value = (args[0]->null_value ||
args[1]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) )))
return 0;
null_value=1;
switch(decomp_func_n)
{
case SP_POINTN:
if (!GEOM_METHOD_PRESENT(geom,point_n) ||
geom.point_n(n,str))
goto ret;
break;
case SP_GEOMETRYN:
if (!GEOM_METHOD_PRESENT(geom,geometry_n) ||
geom.geometry_n(n,str))
goto ret;
break;
case SP_INTERIORRINGN:
if (!GEOM_METHOD_PRESENT(geom,interior_ring_n) ||
geom.interior_ring_n(n,str))
goto ret;
break;
default:
goto ret;
}
null_value=0;
ret:
return null_value ? 0 : str;
}
/***********************************************
Functions to concatinate various spatial objects
************************************************/
/*
* Concatinate doubles into Point
*/
String *Item_func_point::val_str(String *str)
{
if ( (null_value = (args[0]->null_value ||
args[1]->null_value ||
str->realloc(1+4+8+8))))
return 0;
str->length(0);
str->q_append((char)Geometry::wkbNDR);
str->q_append((uint32)Geometry::wkbPoint);
str->q_append((double)args[0]->val());
str->q_append((double)args[1]->val());
return str;
}
/*
Concatinates various items into various collections
with checkings for valid wkb type of items.
For example, MultiPoint can be a collection of Points only.
coll_type contains wkb type of target collection.
item_type contains a valid wkb type of items.
In the case when coll_type is wkbGeometryCollection,
we do not check wkb type of items, any is valid.
*/
String *Item_func_spatial_collection::val_str(String *str)
{
uint i;
null_value=1;
str->length(0);
if(str->reserve(9,512))
return 0;
str->q_append((char)Geometry::wkbNDR);
str->q_append((uint32)coll_type);
str->q_append((uint32)arg_count);
for (i = 0; i < arg_count; ++i)
{
if (args[i]->null_value)
goto ret;
String *res = args[i]->val_str(str);
if ( coll_type == Geometry::wkbGeometryCollection )
{
/*
In the case of GeometryCollection we don't need
any checkings for item types, so just copy them
into target collection
*/
if ((null_value=(str->reserve(res->length(),512))))
goto ret;
str->q_append(res->ptr(),res->length());
}
else
{
uint32 wkb_type, len=res->length();
const char *data=res->ptr()+1;
/*
In the case of named collection we must to
check that items are of specific type, let's
do this checking now
*/
if (len<5)
goto ret;
wkb_type=uint4korr(data);
data+=4;
len-=5;
if ( wkb_type != item_type )
goto ret;
switch(coll_type)
{
case Geometry::wkbMultiPoint:
case Geometry::wkbMultiLineString:
case Geometry::wkbMultiPolygon:
if (len<WKB_HEADER_SIZE)
goto ret;
data+=WKB_HEADER_SIZE;
len-=WKB_HEADER_SIZE;
if (str->reserve(len,512))
goto ret;
str->q_append(data,len);
break;
case Geometry::wkbLineString:
if (str->reserve(POINT_DATA_SIZE,512))
goto ret;
str->q_append(data,POINT_DATA_SIZE);
break;
case Geometry::wkbPolygon:
{
uint32 n_points;
double x1, y1, x2, y2;
if (len < WKB_HEADER_SIZE + 4 + 8 + 8)
goto ret;
data+=WKB_HEADER_SIZE;
len-=WKB_HEADER_SIZE;
uint32 llen=len;
const char *ldata=data;
n_points=uint4korr(data);
data+=4;
float8get(x1,data);
data+=8;
float8get(y1,data);
data+=8;
len-= 4 + 8 + 8;
if (len < n_points * POINT_DATA_SIZE)
goto ret;
data+=(n_points-2) * POINT_DATA_SIZE;
float8get(x2,data);
float8get(y2,data+8);
if ((x1 != x2) || (y1 != y2))
goto ret;
if (str->reserve(llen,512))
goto ret;
str->q_append(ldata, llen);
}
break;
default:
goto ret;
}
}
}
if (str->length() > max_allowed_packet)
goto ret;
null_value = 0;
ret:
return null_value ? 0 : str;
}
......@@ -475,3 +475,196 @@ class Item_func_export_set: public Item_str_func
const char *func_name() const { return "inet_ntoa"; }
void fix_length_and_dec() { decimals = 0; max_length=3*8+7; }
};
/*******************************************************
Spatial functions
********************************************************/
class Item_func_geometry_from_text :public Item_str_func
{
public:
Item_func_geometry_from_text(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "geometryfromtext"; }
String *val_str(String *);
void fix_length_and_dec();
};
class Item_func_as_text :public Item_str_func
{
public:
Item_func_as_text(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "astext"; }
String *val_str(String *);
void fix_length_and_dec();
};
class Item_func_geometry_type :public Item_str_func
{
public:
Item_func_geometry_type(Item *a) :Item_str_func(a) {}
String *val_str(String *);
const char *func_name() const { return "geometrytype"; }
void fix_length_and_dec()
{
max_length=20; // "GeometryCollection" is the most long
};
};
class Item_func_centroid :public Item_str_func
{
public:
Item_func_centroid(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "centroid"; }
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
};
class Item_func_envelope :public Item_str_func
{
public:
Item_func_envelope(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "envelope"; }
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
};
class Item_func_point :public Item_str_func
{
public:
Item_func_point(Item *a,Item *b) :Item_str_func(a,b) {}
const char *func_name() const { return "point"; }
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
};
class Item_func_spatial_decomp :public Item_str_func
{
enum Functype decomp_func;
public:
Item_func_spatial_decomp(Item *a, Item_func::Functype ft) :
Item_str_func(a) { decomp_func = ft; }
const char *func_name() const
{
switch (decomp_func)
{
case SP_STARTPOINT:
return "startpoint";
case SP_ENDPOINT:
return "endpoint";
case SP_EXTERIORRING:
return "exteriorring";
default:
return "spatial_decomp_unknown";
}
}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
};
class Item_func_spatial_decomp_n :public Item_str_func
{
enum Functype decomp_func_n;
public:
Item_func_spatial_decomp_n(Item *a, Item *b, Item_func::Functype ft) :
Item_str_func(a, b) { decomp_func_n = ft; }
const char *func_name() const
{
switch (decomp_func_n)
{
case SP_POINTN:
return "pointn";
case SP_GEOMETRYN:
return "geometryn";
case SP_INTERIORRINGN:
return "interiorringn";
default:
return "spatial_decomp_n_unknown";
}
}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
};
class Item_func_spatial_collection :public Item_str_func
{
String tmp_value;
enum Geometry::wkbType coll_type;
enum Geometry::wkbType item_type;
public:
Item_func_spatial_collection(
List<Item> &list, enum Geometry::wkbType ct, enum Geometry::wkbType it) :
Item_str_func(list)
{
coll_type=ct;
item_type=it;
}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
const char *func_name() const { return "multipoint"; }
};
/*
class Item_func_multipoint :public Item_str_func
{
String tmp_value;
public:
Item_func_multipoint(List<Item> &list) :Item_str_func(list) {}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
const char *func_name() const { return "multipoint"; }
};
class Item_func_linestring :public Item_str_func
{
String tmp_value;
public:
Item_func_linestring(List<Item> &list) :Item_str_func(list) {}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
const char *func_name() const { return "linestring"; }
};
class Item_func_multilinestring :public Item_str_func
{
String tmp_value;
public:
Item_func_multilinestring(List<Item> &list) :Item_str_func(list) {}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
const char *func_name() const { return "multilinestring"; }
};
class Item_func_polygon :public Item_str_func
{
String tmp_value;
public:
Item_func_polygon(List<Item> &list) :Item_str_func(list) {}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
const char *func_name() const { return "polygon"; }
};
class Item_func_multipolygon :public Item_str_func
{
String tmp_value;
public:
Item_func_multipolygon(List<Item> &list) :Item_str_func(list) {}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
const char *func_name() const { return "multipolygon"; }
};
class Item_func_geometrycollection :public Item_str_func
{
String tmp_value;
public:
Item_func_geometrycollection(List<Item> &list) :Item_str_func(list) {}
String *val_str(String *);
void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
const char *func_name() const { return "geometrycollection"; }
};
*/
......@@ -75,6 +75,7 @@ static SYMBOL symbols[] = {
{ "BOOL", SYM(BOOL_SYM),0,0},
{ "BOOLEAN", SYM(BOOLEAN_SYM),0,0},
{ "BOTH", SYM(BOTH),0,0},
{ "BTREE", SYM(BTREE_SYM),0,0},
{ "BY", SYM(BY),0,0},
{ "CACHE", SYM(CACHE_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
......@@ -158,12 +159,14 @@ static SYMBOL symbols[] = {
{ "FULL", SYM(FULL),0,0},
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
{ "FUNCTION", SYM(UDF_SYM),0,0},
{ "GEOM", SYM(GEOM_SYM),0,0},
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
{ "GRANT", SYM(GRANT),0,0},
{ "GRANTS", SYM(GRANTS),0,0},
{ "GROUP", SYM(GROUP),0,0},
{ "HAVING", SYM(HAVING),0,0},
{ "HANDLER", SYM(HANDLER_SYM),0,0},
{ "HASH", SYM(HASH_SYM),0,0},
{ "HEAP", SYM(HEAP_SYM),0,0},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0},
{ "HOUR", SYM(HOUR_SYM),0,0},
......@@ -296,6 +299,7 @@ static SYMBOL symbols[] = {
{ "ROLLBACK", SYM(ROLLBACK_SYM),0,0},
{ "ROW", SYM(ROW_SYM),0,0},
{ "ROWS", SYM(ROWS_SYM),0,0},
{ "RTREE", SYM(RTREE_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
......@@ -308,6 +312,7 @@ static SYMBOL symbols[] = {
{ "SLAVE", SYM(SLAVE),0,0},
{ "SMALLINT", SYM(SMALLINT),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SQL_AUTO_IS_NULL", SYM(SQL_AUTO_IS_NULL),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BIG_SELECTS", SYM(SQL_BIG_SELECTS),0,0},
......@@ -384,8 +389,10 @@ static SYMBOL sql_functions[] = {
{ "ABS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_abs)},
{ "ACOS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_acos)},
{ "ADDDATE", SYM(DATE_ADD_INTERVAL),0,0},
{ "AREA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_area)},
{ "ASCII", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ascii)},
{ "ASIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_asin)},
{ "ASTEXT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_as_text)},
{ "ATAN", SYM(ATAN),0,0},
{ "ATAN2", SYM(ATAN),0,0},
{ "BENCHMARK", SYM(BENCHMARK_SYM),0,0},
......@@ -396,17 +403,20 @@ static SYMBOL sql_functions[] = {
{ "CAST", SYM(CAST_SYM),0,0},
{ "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
{ "BIT_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_length)},
{ "CENTROID", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_centroid)},
{ "CHAR_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "CHARACTER_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "COALESCE", SYM(COALESCE),0,0},
{ "CONCAT", SYM(CONCAT),0,0},
{ "CONCAT_WS", SYM(CONCAT_WS),0,0},
{ "CONNECTION_ID", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
{ "CONTAINS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_contains)},
{ "CONV", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
{ "CONVERT", SYM(CONVERT_SYM),0,0},
{ "COUNT", SYM(COUNT_SYM),0,0},
{ "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
{ "CROSSES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_crosses)},
{ "CURDATE", SYM(CURDATE),0,0},
{ "CURTIME", SYM(CURTIME),0,0},
{ "DATE_ADD", SYM(DATE_ADD_INTERVAL),0,0},
......@@ -420,9 +430,15 @@ static SYMBOL sql_functions[] = {
{ "DEGREES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_degrees)},
{ "DES_ENCRYPT", SYM(DES_ENCRYPT_SYM),0,0},
{ "DES_DECRYPT", SYM(DES_DECRYPT_SYM),0,0},
{ "DIMENSION", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dimension)},
{ "DISJOINT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_disjoint)},
{ "ELT", SYM(ELT_FUNC),0,0},
{ "ENCODE", SYM(ENCODE_SYM),0,0},
{ "ENCRYPT", SYM(ENCRYPT),0,0},
{ "ENDPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_endpoint)},
{ "ENVELOPE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_envelope)},
{ "EQUALS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_equals)},
{ "EXTERIORRING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exteriorring)},
{ "EXTRACT", SYM(EXTRACT_SYM),0,0},
{ "EXP", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exp)},
{ "EXPORT_SET", SYM(EXPORT_SET),0,0},
......@@ -434,6 +450,11 @@ static SYMBOL sql_functions[] = {
{ "FROM_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_from_days)},
{ "FROM_UNIXTIME", SYM(FROM_UNIXTIME),0,0},
{ "GET_LOCK", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_get_lock)},
{ "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),0,0},
{ "GEOMETRYN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_geometryn)},
{ "GEOMETRYTYPE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_geometry_type)},
{ "GEOMFROMTEXT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_geometry_from_text)},
{ "GLENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_glength)},
{ "GREATEST", SYM(GREATEST_SYM),0,0},
{ "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS),0,0},
{ "HEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_hex)},
......@@ -441,10 +462,16 @@ static SYMBOL sql_functions[] = {
{ "INET_ATON", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_aton)},
{ "INET_NTOA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_ntoa)},
{ "INSTR", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_instr)},
{ "INTERIORRINGN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_interiorringn)},
{ "INTERSECTS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_intersects)},
{ "ISCLOSED", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isclosed)},
{ "ISEMPTY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isempty)},
{ "ISNULL", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isnull)},
{ "ISSIMPLE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_issimple)},
{ "LCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_lcase)},
{ "LEAST", SYM(LEAST_SYM),0,0},
{ "LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
{ "LINESTRING", SYM(LINESTRING),0,0},
{ "LOAD_FILE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_load_file)},
{ "LOCATE", SYM(LOCATE),0,0},
{ "LOG", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_log)},
......@@ -460,15 +487,25 @@ static SYMBOL sql_functions[] = {
{ "MID", SYM(SUBSTRING),0,0}, /* unireg function */
{ "MIN", SYM(MIN_SYM),0,0},
{ "MOD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_mod)},
{ "MULTILINESTRING", SYM(MULTILINESTRING),0,0},
{ "MULTIPOINT", SYM(MULTIPOINT),0,0},
{ "MULTIPOLYGON", SYM(MULTIPOLYGON),0,0},
{ "MONTHNAME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_monthname)},
{ "NOW", SYM(NOW_SYM),0,0},
{ "NULLIF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_nullif)},
{ "NUMGEOMETRIES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numgeometries)},
{ "NUMINTERIORRING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numinteriorring)},
{ "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)},
{ "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
{ "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)},
{ "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
{ "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)},
{ "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
{ "PERIOD_DIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_diff)},
{ "PI", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_pi)},
{ "POINT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_point)},
{ "POINTN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pointn)},
{ "POLYGON", SYM(POLYGON),0,0},
{ "POSITION", SYM(POSITION_SYM),0,0},
{ "POW", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
{ "POWER", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
......@@ -489,6 +526,7 @@ static SYMBOL sql_functions[] = {
{ "SOUNDEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_soundex)},
{ "SPACE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_space)},
{ "SQRT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sqrt)},
{ "STARTPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_startpoint)},
{ "STD", SYM(STD_SYM),0,0},
{ "STDDEV", SYM(STD_SYM),0,0},
{ "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)},
......@@ -501,6 +539,7 @@ static SYMBOL sql_functions[] = {
{ "TIME_FORMAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_time_format)},
{ "TIME_TO_SEC", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_time_to_sec)},
{ "TO_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_to_days)},
{ "TOUCHES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_touches)},
{ "TRIM", SYM(TRIM),0,0},
{ "UCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
{ "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0},
......@@ -510,5 +549,9 @@ static SYMBOL sql_functions[] = {
{ "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
{ "WEEK", SYM(WEEK_SYM),0,0},
{ "WEEKDAY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)},
{ "WITHIN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_within)},
{ "X", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_x)},
{ "Y", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_y)},
{ "YEARWEEK", SYM(YEARWEEK),0,0}
};
......@@ -172,8 +172,9 @@ class SEL_ARG :public Sql_alloc
void store(uint length,char **min_key,uint min_key_flag,
char **max_key, uint max_key_flag)
{
if (!(min_flag & NO_MIN_RANGE) &&
!(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))
if ((min_flag & GEOM_FLAG) ||
(!(min_flag & NO_MIN_RANGE) &&
!(min_key_flag & (NO_MIN_RANGE | NEAR_MIN))))
{
if (maybe_null && *min_value)
{
......@@ -659,6 +660,8 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
key_parts->null_bit= key_info->key_part[part].null_bit;
if (key_parts->field->type() == FIELD_TYPE_BLOB)
key_parts->part_length+=HA_KEY_BLOB_LENGTH;
key_parts->image_type =
(key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
}
param.real_keynr[param.keys++]=idx;
}
......@@ -676,6 +679,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
{
SEL_ARG **key,**end,**best_key=0;
for (idx=0,key=tree->keys, end=key+param.keys ;
key != end ;
key++,idx++)
......@@ -1042,7 +1046,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(0);
if (maybe_null)
*str=0; // Not NULL
field->get_key_image(str+maybe_null,key_part->part_length);
field->get_key_image(str+maybe_null,key_part->part_length, key_part->image_type);
if (!(tree=new SEL_ARG(field,str,str)))
DBUG_RETURN(0);
......@@ -1067,6 +1071,41 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
case Item_func::GE_FUNC:
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_EQUALS_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_DISJOINT_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_INTERSECTS_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_TOUCHES_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_CROSSES_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_WITHIN_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_CONTAINS_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_OVERLAPS_FUNC:
tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
tree->max_flag=NO_MAX_RANGE;
break;
default:
break;
}
......@@ -2187,18 +2226,30 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
!memcmp(param->min_key,param->max_key,min_key_length))
tmp=1; // Max one record
else
{
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);
}
else
{
tmp=param->table->file->
records_in_range((int) keynr,
(byte*) (!min_key_length ? NullS :
param->min_key),
min_key_length,
(tmp_min_flag & NEAR_MIN ?
HA_READ_AFTER_KEY : HA_READ_KEY_EXACT),
tmp_min_flag & NEAR_MIN ?
HA_READ_AFTER_KEY : HA_READ_KEY_EXACT,
(byte*) (!max_key_length ? NullS :
param->max_key),
max_key_length,
(tmp_max_flag & NEAR_MAX ?
HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY));
}
}
end:
if (tmp == HA_POS_ERROR) // Impossible range
return tmp;
......@@ -2294,10 +2345,15 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
}
}
else
flag=key_tree->min_flag | key_tree->max_flag;
{
flag = (key_tree->min_flag & GEOM_FLAG) ?
key_tree->min_flag : key_tree->min_flag | key_tree->max_flag;
}
/* Ensure that some part of min_key and max_key are used. If not,
regard this as no lower/upper range */
if((flag & GEOM_FLAG) == 0)
{
if (tmp_min_key != param->min_key)
flag&= ~NO_MIN_RANGE;
else
......@@ -2306,7 +2362,7 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
flag&= ~NO_MAX_RANGE;
else
flag|= NO_MAX_RANGE;
}
if (flag == 0)
{
uint length= (uint) (tmp_min_key - param->min_key);
......@@ -2439,13 +2495,19 @@ int QUICK_SELECT::get_next()
int result;
if (range)
{ // Already read through key
result=((range->flag & EQ_RANGE) ?
/* result=((range->flag & EQ_RANGE) ?
file->index_next_same(record, (byte*) range->min_key,
range->min_length) :
file->index_next(record));
*/
result=((range->flag & (EQ_RANGE | GEOM_FLAG) ) ?
file->index_next_same(record, (byte*) range->min_key,
range->min_length) :
file->index_next(record));
if (!result)
{
if (!cmp_next(*it.ref()))
if ((range->flag & GEOM_FLAG) || !cmp_next(*it.ref()))
DBUG_RETURN(0);
}
else if (result != HA_ERR_END_OF_FILE)
......@@ -2454,6 +2516,23 @@ int QUICK_SELECT::get_next()
if (!(range=it++))
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
if(range->flag & GEOM_FLAG)
{
if ((result = file->index_read(record,
(byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)),
range->min_length,
(ha_rkey_function)(range->flag ^ GEOM_FLAG))))
{
if (result != HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(result);
range=0; // Not found, to next range
continue;
}
DBUG_RETURN(0);
}
if (range->flag & NO_MIN_RANGE) // Read first record
{
int error;
......@@ -2464,13 +2543,14 @@ int QUICK_SELECT::get_next()
range=0; // No matching records; go to next range
continue;
}
if ((result = file->index_read(record,(byte*) range->min_key,
if ((result = file->index_read(record,
(byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)),
range->min_length,
((range->flag & NEAR_MIN) ?
(range->flag & NEAR_MIN) ?
HA_READ_AFTER_KEY:
(range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT :
HA_READ_KEY_OR_NEXT))))
HA_READ_KEY_OR_NEXT)))
{
if (result != HA_ERR_KEY_NOT_FOUND)
......
......@@ -31,11 +31,14 @@
#define UNIQUE_RANGE 16
#define EQ_RANGE 32
#define NULL_RANGE 64
#define GEOM_FLAG 128
typedef struct st_key_part {
uint16 key,part,part_length;
uint8 null_bit;
Field *field;
Field::imagetype image_type;
} KEY_PART;
class QUICK_RANGE :public Sql_alloc {
......
......@@ -343,7 +343,7 @@ static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
// Save found constant
if (part->null_bit)
*key_ptr++= (byte) test(part->field->is_null());
part->field->get_key_image((char*) key_ptr,part->length);
part->field->get_key_image((char*) key_ptr,part->length, Field::itRAW);
key_ptr+=part->store_length - test(part->null_bit);
left_length-=part->store_length;
}
......
#include "mysql_priv.h"
#define MAX_DIGITS_IN_DOUBLE 16
/***************************** GClassInfo *******************************/
#define IMPLEMENT_GEOM(class_name, type_id, name) \
{ \
(GF_InitFromText) &class_name::init_from_text, \
(GF_GetDataAsText) &class_name::get_data_as_text, \
(GF_GetDataSize) &class_name::get_data_size, \
(GF_GetMBR) &class_name::get_mbr, \
(GF_GetD) &class_name::get_x, \
(GF_GetD) &class_name::get_y, \
(GF_GetD) &class_name::length, \
(GF_GetD) &class_name::area, \
(GF_GetI) &class_name::is_closed, \
(GF_GetUI) &class_name::num_interior_ring, \
(GF_GetUI) &class_name::num_points, \
(GF_GetUI) &class_name::num_geometries, \
(GF_GetUI) &class_name::dimension, \
(GF_GetWS) &class_name::start_point, \
(GF_GetWS) &class_name::end_point, \
(GF_GetWS) &class_name::exterior_ring, \
(GF_GetWS) &class_name::centroid, \
(GF_GetUIWS) &class_name::point_n, \
(GF_GetUIWS) &class_name::interior_ring_n, \
(GF_GetUIWS) &class_name::geometry_n, \
class_name::type_id, \
name, \
NULL \
},
static Geometry::GClassInfo ci_collection[] =
{
IMPLEMENT_GEOM(GPoint, wkbPoint, "POINT")
IMPLEMENT_GEOM(GLineString, wkbLineString, "LINESTRING")
IMPLEMENT_GEOM(GPolygon, wkbPolygon, "POLYGON")
IMPLEMENT_GEOM(GMultiPoint, wkbMultiPoint, "MULTIPOINT")
IMPLEMENT_GEOM(GMultiLineString, wkbMultiLineString, "MULTILINESTRING")
IMPLEMENT_GEOM(GMultiPolygon, wkbMultiPolygon, "MULTIPOLYGON")
IMPLEMENT_GEOM(GGeometryCollection, wkbGeometryCollection, "GEOMETRYCOLLECTION")
};
static Geometry::GClassInfo *ci_collection_end = ci_collection + sizeof(ci_collection);
/***************************** Geometry *******************************/
Geometry::GClassInfo *Geometry::find_class(int type_id)
{
for (GClassInfo *cur_rt = ci_collection; cur_rt < ci_collection_end; ++cur_rt)
{
if (cur_rt->m_type_id == type_id)
{
return cur_rt;
}
}
return NULL;
}
Geometry::GClassInfo *Geometry::find_class(const char *name, size_t len)
{
for (GClassInfo *cur_rt = ci_collection;
cur_rt < ci_collection_end; ++cur_rt)
{
if ((cur_rt->m_name[len] == 0) &&
(strncmp(cur_rt->m_name, name, len) == 0))
{
return cur_rt;
}
}
return NULL;
}
int Geometry::create_from_wkb(const char *data, uint32 data_len)
{
uint32 geom_type;
if (data_len < 1+4)
return 1;
data += sizeof(char);
//FIXME: check byte ordering
geom_type = uint4korr(data);
data += 4;
m_vmt = find_class(geom_type);
if (!m_vmt) return -1;
m_data = data;
m_data_end = data + data_len;
return 0;
}
int Geometry::create_from_wkt(GTextReadStream *trs, String *wkt, int init_stream)
{
int name_len;
const char *name = trs->get_next_word(&name_len);
if (!name)
{
trs->set_error_msg("Geometry name expected");
return -1;
}
if (!(m_vmt = find_class(name, name_len)))
return -1;
if (wkt->reserve(1 + 4, 512))
return 1;
wkt->q_append((char)wkbNDR);
wkt->q_append((uint32)get_class_info()->m_type_id);
if (trs->get_next_symbol() != '(')
{
trs->set_error_msg("'(' expected");
return -1;
}
if (init_from_text(trs, wkt)) return 1;
if (trs->get_next_symbol() != ')')
{
trs->set_error_msg("')' expected");
return -1;
}
if (init_stream)
{
init_from_wkb(wkt->ptr(), wkt->length());
shift_wkb_header();
}
return 0;
}
int Geometry::envelope(String *result) const
{
MBR mbr;
get_mbr(&mbr);
if (result->reserve(1+4*3+sizeof(double)*10))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbPolygon);
result->q_append((uint32)1);
result->q_append((uint32)5);
result->q_append(mbr.xmin);
result->q_append(mbr.ymin);
result->q_append(mbr.xmax);
result->q_append(mbr.ymin);
result->q_append(mbr.xmax);
result->q_append(mbr.ymax);
result->q_append(mbr.xmin);
result->q_append(mbr.ymax);
result->q_append(mbr.xmin);
result->q_append(mbr.ymin);
return 0;
}
/***************************** Point *******************************/
size_t GPoint::get_data_size() const
{
return POINT_DATA_SIZE;
}
int GPoint::init_from_text(GTextReadStream *trs, String *wkb)
{
double x, y;
if (wkb->reserve(sizeof(double)*2))
return 1;
if (trs->get_next_number(&x))
return 1;
if (trs->get_next_number(&y))
return 1;
wkb->q_append(x);
wkb->q_append(y);
return 0;
}
int GPoint::get_data_as_text(String *txt) const
{
double x, y;
if (get_xy(&x, &y))
return 1;
if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
return 1;
txt->qs_append(x);
txt->qs_append(' ');
txt->qs_append(y);
return 0;
}
int GPoint::get_mbr(MBR *mbr) const
{
double x, y;
if (get_xy(&x, &y))
return 1;
mbr->add_xy(x, y);
return 0;
}
/***************************** LineString *******************************/
size_t GLineString::get_data_size() const
{
uint32 n_points = uint4korr(m_data);
return 4 + n_points*POINT_DATA_SIZE;
}
int GLineString::init_from_text(GTextReadStream *trs, String *wkb)
{
uint32 n_points = 0;
int np_pos = wkb->length();
GPoint p;
if (wkb->reserve(4, 512))
return 1;
wkb->q_append((uint32)n_points);
for (;;)
{
if (p.init_from_text(trs, wkb))
return 1;
++n_points;
if (trs->get_next_toc_type() == GTextReadStream::comma)
trs->get_next_symbol();
else break;
}
if (n_points<2)
{
trs->set_error_msg("Too few points in LINESTRING");
return 1;
}
wkb->WriteAtPosition(np_pos, n_points);
return 0;
}
int GLineString::get_data_as_text(String *txt) const
{
uint32 n_points;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4;
if (no_data(data, sizeof(double) * 2 * n_points))
return 1;
if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
return 1;
for (; n_points>0; --n_points)
{
double x, y;
float8get(x, data);
data += sizeof(double);
float8get(y, data);
data += sizeof(double);
txt->qs_append(x);
txt->qs_append(' ');
txt->qs_append(y);
txt->qs_append(',');
}
txt->length(txt->length() - 1);
return 0;
}
int GLineString::get_mbr(MBR *mbr) const
{
uint32 n_points;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4;
if (no_data(data, sizeof(double) * 2 * n_points))
return 1;
for (; n_points>0; --n_points)
{
mbr->add_xy((double *)data, (double *)(data + 8));
data += 8+8;
}
return 0;
}
int GLineString::length(double *len) const
{
uint32 n_points;
double prev_x, prev_y;
const char *data = m_data;
*len=0;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4;
if (no_data(data, sizeof(double) * 2 * n_points))
return 1;
--n_points;
float8get(prev_x, data);
data += 8;
float8get(prev_y, data);
data += 8;
for (; n_points>0; --n_points)
{
double x, y;
float8get(x, data);
data += 8;
float8get(y, data);
data += 8;
*len+=sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
prev_x=x;
prev_y=y;
}
return 0;
}
int GLineString::is_closed(int *closed) const
{
uint32 n_points;
double x1, y1, x2, y2;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4;
if (no_data(data, (8+8) * n_points))
return 1;
float8get(x1, data);
data += 8;
float8get(y1, data);
data += 8 + (n_points-2)*POINT_DATA_SIZE;
float8get(x2, data);
data += 8;
float8get(y2, data);
*closed=(x1==x2)&&(y1==y2);
return 0;
}
int GLineString::num_points(uint32 *n_points) const
{
*n_points = uint4korr(m_data);
return 0;
}
int GLineString::start_point(String *result) const
{
const char *data = m_data + 4;
if (no_data(data, 8+8))
return 1;
if (result->reserve(1 + 4 + sizeof(double) * 2))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbPoint);
result->q_append((double *)data);
result->q_append((double *)(data + 8));
return 0;
}
int GLineString::end_point(String *result) const
{
const char *data = m_data;
uint32 n_points;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4 + (n_points-1)*POINT_DATA_SIZE;
if (no_data(data, 8+8))
return 1;
if (result->reserve(1 + 4 + sizeof(double) * 2))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbPoint);
result->q_append((double *)data);
result->q_append((double *)(data + 8));
return 0;
}
int GLineString::point_n(uint32 num, String *result) const
{
const char *data = m_data;
uint32 n_points;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
if ((uint32)(num-1) >= n_points) // really means (num > n_points || num < 1)
return 1;
data += 4 + (num - 1)*POINT_DATA_SIZE;
if (no_data(data, 8+8))
return 1;
if (result->reserve(1 + 4 + sizeof(double) * 2))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbPoint);
result->q_append((double *)data);
result->q_append((double *)(data + 8));
return 0;
}
/***************************** Polygon *******************************/
size_t GPolygon::get_data_size() const
{
uint32 n_linear_rings = 0;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_linear_rings = uint4korr(data);
data += 4;
for (; n_linear_rings>0; --n_linear_rings)
{
if (no_data(data, 4))
return 1;
data += 4 + uint4korr(data)*POINT_DATA_SIZE;
}
return data - m_data;
}
int GPolygon::init_from_text(GTextReadStream *trs, String *wkb)
{
uint32 n_linear_rings = 0;
int lr_pos = wkb->length();
if (wkb->reserve(4, 512))
return 1;
wkb->q_append((uint32)n_linear_rings);
for (;;)
{
GLineString ls;
size_t ls_pos=wkb->length();
if (trs->get_next_symbol() != '(')
{
trs->set_error_msg("'(' expected");
return 1;
}
if (ls.init_from_text(trs, wkb))
return 1;
if (trs->get_next_symbol() != ')')
{
trs->set_error_msg("')' expected");
return 1;
}
ls.init_from_wkb(wkb->ptr()+ls_pos, wkb->length()-ls_pos);
int closed;
ls.is_closed(&closed);
if (!closed)
{
trs->set_error_msg("POLYGON's linear ring isn't closed");
return 1;
}
++n_linear_rings;
if (trs->get_next_toc_type() == GTextReadStream::comma)
trs->get_next_symbol();
else
break;
}
wkb->WriteAtPosition(lr_pos, n_linear_rings);
return 0;
}
int GPolygon::get_data_as_text(String *txt) const
{
uint32 n_linear_rings;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_linear_rings = uint4korr(data);
data += 4;
for (; n_linear_rings>0; --n_linear_rings)
{
if(no_data(data, 4))
return 1;
uint32 n_points = uint4korr(data);
data += 4;
if (no_data(data, (8+8) * n_points))
return 1;
if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
return 1;
txt->qs_append('(');
for (; n_points>0; --n_points)
{
txt->qs_append((double *)data);
txt->qs_append(' ');
txt->qs_append((double *)(data + 8));
txt->qs_append(',');
data += 8+8;
}
(*txt)[txt->length()-1] = ')';
txt->qs_append(',');
}
txt->length(txt->length() - 1);
return 0;
}
int GPolygon::get_mbr(MBR *mbr) const
{
uint32 n_linear_rings;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_linear_rings = uint4korr(data);
data += 4;
for (; n_linear_rings>0; --n_linear_rings)
{
if (no_data(data, 4))
return 1;
uint32 n_points = uint4korr(data);
data += 4;
if (no_data(data, (8+8) * n_points))
return 1;
for (; n_points>0; --n_points)
{
mbr->add_xy((double *)data, (double *)(data + 8));
data += 8+8;
}
}
return 0;
}
int GPolygon::area(double *ar) const
{
uint32 n_linear_rings;
double result = -1.0;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_linear_rings = uint4korr(data);
data += 4;
for (; n_linear_rings>0; --n_linear_rings)
{
double prev_x, prev_y;
double lr_area=0;
if (no_data(data, 4))
return 1;
uint32 n_points = uint4korr(data);
if (no_data(data, (8+8) * n_points))
return 1;
float8get(prev_x, data+4);
float8get(prev_y, data+(4+8));
data += (4+8+8);
--n_points;
for (; n_points>0; --n_points)
{
double x, y;
float8get(x, data);
float8get(y, data + 8);
lr_area+=(prev_x+x)*(prev_y-y);
prev_x=x;
prev_y=y;
data += (8+8);
}
lr_area=fabs(lr_area)/2;
if(result==-1) result=lr_area;
else result-=lr_area;
}
*ar=fabs(result);
return 0;
}
int GPolygon::exterior_ring(String *result) const
{
uint32 n_points;
const char *data = m_data + 4; // skip n_linerings
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4;
if (no_data(data, n_points * POINT_DATA_SIZE))
return 1;
if (result->reserve(1+4+4+ n_points * POINT_DATA_SIZE))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbLineString);
result->q_append(n_points);
result->q_append(data, n_points * POINT_DATA_SIZE);
return 0;
}
int GPolygon::num_interior_ring(uint32 *n_int_rings) const
{
const char *data = m_data;
if (no_data(data, 4))
return 1;
*n_int_rings = uint4korr(data);
--(*n_int_rings);
return 0;
}
int GPolygon::interior_ring_n(uint32 num, String *result) const
{
const char *data = m_data;
uint32 n_linear_rings;
uint32 n_points;
if (no_data(data, 4))
return 1;
n_linear_rings = uint4korr(data);
data += 4;
if ((num >= n_linear_rings) || (num < 1))
return -1;
for (; num > 0; --num)
{
if (no_data(data, 4))
return 1;
data += 4 + uint4korr(data) * POINT_DATA_SIZE;
}
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
int points_size = n_points * POINT_DATA_SIZE;
data += 4;
if (no_data(data, points_size))
return 1;
if (result->reserve(1+4+4+ points_size))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbLineString);
result->q_append(n_points);
result->q_append(data, points_size);
return 0;
}
int GPolygon::centroid_xy(double *x, double *y) const
{
uint32 n_linear_rings;
uint32 i;
double res_area, res_cx, res_cy;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_linear_rings = uint4korr(data);
data += 4;
for(i = 0; i < n_linear_rings; ++i)
{
if (no_data(data, 4))
return 1;
uint32 n_points = uint4korr(data);
double prev_x, prev_y;
double cur_area = 0;
double cur_cx = 0;
double cur_cy = 0;
data += 4;
if (no_data(data, (8+8) * n_points))
return 1;
float8get(prev_x, data);
float8get(prev_y, data+8);
data += (8+8);
uint32 n = n_points - 1;
for (; n > 0; --n)
{
double x, y;
float8get(x, data);
float8get(y, data + 8);
cur_area += (prev_x + x) * (prev_y - y);
cur_cx += x;
cur_cy += y;
prev_x = x;
prev_y = y;
data += (8+8);
}
cur_area = fabs(cur_area) / 2;
cur_cx = cur_cx / (n_points - 1);
cur_cy = cur_cy / (n_points - 1);
if(i)
{
double d_area = res_area - cur_area;
if (d_area <= 0)
return 1;
res_cx = (res_area * res_cx - cur_area * cur_cx) / d_area;
res_cy = (res_area * res_cy - cur_area * cur_cy) / d_area;
}
else
{
res_area = cur_area;
res_cx = cur_cx;
res_cy = cur_cy;
}
}
*x = res_cx;
*y = res_cy;
return 0;
}
int GPolygon::centroid(String *result) const
{
double x, y;
this->centroid_xy(&x, &y);
if (result->reserve(1 + 4 + sizeof(double) * 2))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbPoint);
result->q_append(x);
result->q_append(y);
return 0;
}
/***************************** MultiPoint *******************************/
size_t GMultiPoint::get_data_size() const
{
return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
}
int GMultiPoint::init_from_text(GTextReadStream *trs, String *wkb)
{
uint32 n_points = 0;
int np_pos = wkb->length();
GPoint p;
if (wkb->reserve(4, 512))
return 1;
wkb->q_append((uint32)n_points);
for (;;)
{
if (wkb->reserve(1+4, 512))
return 1;
wkb->q_append((char)wkbNDR);
wkb->q_append((uint32)wkbPoint);
if (p.init_from_text(trs, wkb))
return 1;
++n_points;
if (trs->get_next_toc_type() == GTextReadStream::comma)
trs->get_next_symbol();
else
break;
}
wkb->WriteAtPosition(np_pos, n_points);
return 0;
}
int GMultiPoint::get_data_as_text(String *txt) const
{
uint32 n_points;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4;
if (no_data(data, n_points * (8+8+WKB_HEADER_SIZE)))
return 1;
if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
return 1;
for (; n_points>0; --n_points)
{
txt->qs_append((double *)(data + WKB_HEADER_SIZE));
txt->qs_append(' ');
txt->qs_append((double *)(data + (8 + WKB_HEADER_SIZE)));
txt->qs_append(',');
data += 8+8+WKB_HEADER_SIZE;
}
txt->length(txt->length()-1);
return 0;
}
int GMultiPoint::get_mbr(MBR *mbr) const
{
uint32 n_points;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_points = uint4korr(data);
data += 4;
if (no_data(data, n_points * (8+8+WKB_HEADER_SIZE)))
return 1;
for (; n_points>0; --n_points)
{
mbr->add_xy((double *)(data + WKB_HEADER_SIZE),
(double *)(data + 8 + WKB_HEADER_SIZE));
data += (8+8+WKB_HEADER_SIZE);
}
return 0;
}
/***************************** MultiLineString *******************************/
size_t GMultiLineString::get_data_size() const
{
uint32 n_line_strings = 0;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_line_strings = uint4korr(data);
data += 4;
for (; n_line_strings>0; --n_line_strings)
{
if (no_data(data, WKB_HEADER_SIZE + 4))
return 1;
data += WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) * POINT_DATA_SIZE;
}
return data - m_data;
}
int GMultiLineString::init_from_text(GTextReadStream *trs, String *wkb)
{
uint32 n_line_strings = 0;
int ls_pos = wkb->length();
if (wkb->reserve(4, 512))
return 1;
wkb->q_append((uint32)n_line_strings);
for (;;)
{
GLineString ls;
if (wkb->reserve(1+4, 512))
return 1;
wkb->q_append((char)wkbNDR);
wkb->q_append((uint32)wkbLineString);
if (trs->get_next_symbol() != '(')
{
trs->set_error_msg("'(' expected");
return 1;
}
if (ls.init_from_text(trs, wkb))
return 1;
if (trs->get_next_symbol() != ')')
{
trs->set_error_msg("')' expected");
return 1;
}
++n_line_strings;
if (trs->get_next_toc_type() == GTextReadStream::comma)
trs->get_next_symbol();
else
break;
}
wkb->WriteAtPosition(ls_pos, n_line_strings);
return 0;
}
int GMultiLineString::get_data_as_text(String *txt) const
{
uint32 n_line_strings;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_line_strings = uint4korr(data);
data += 4;
for (; n_line_strings>0; --n_line_strings)
{
if (no_data(data, (WKB_HEADER_SIZE + 4)))
return 1;
uint32 n_points = uint4korr(data + WKB_HEADER_SIZE);
data += WKB_HEADER_SIZE + 4;
if (no_data(data, n_points * (8+8)))
return 1;
if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
return 1;
txt->qs_append('(');
for (; n_points>0; --n_points)
{
txt->qs_append((double *)data);
txt->qs_append(' ');
txt->qs_append((double *)(data + 8));
txt->qs_append(',');
data += 8+8;
}
(*txt)[txt->length()-1] = ')';
txt->qs_append(',');
}
txt->length(txt->length() - 1);
return 0;
}
int GMultiLineString::get_mbr(MBR *mbr) const
{
uint32 n_line_strings;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_line_strings = uint4korr(data);
data += 4;
for (; n_line_strings>0; --n_line_strings)
{
if (no_data(data, WKB_HEADER_SIZE + 4))
return 1;
uint32 n_points = uint4korr(data + WKB_HEADER_SIZE);
data += 4+WKB_HEADER_SIZE;
if (no_data(data, (8+8)*n_points))
return 1;
for (; n_points>0; --n_points)
{
mbr->add_xy((double *)data, (double *)(data + 8));
data += 8+8;
}
}
return 0;
}
int GMultiLineString::length(double *len) const
{
uint32 n_line_strings;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_line_strings = uint4korr(data);
data += 4;
*len=0;
for (; n_line_strings>0; --n_line_strings)
{
double ls_len;
GLineString ls;
data += WKB_HEADER_SIZE;
ls.init_from_wkb(data, m_data_end - data);
if (ls.length(&ls_len))
return 1;
*len+=ls_len;
data += ls.get_data_size();
}
return 0;
}
int GMultiLineString::is_closed(int *closed) const
{
uint32 n_line_strings;
const char *data = m_data;
if (no_data(data, 1))
return 1;
n_line_strings = uint4korr(data);
data += 4 + WKB_HEADER_SIZE;
for (; n_line_strings>0; --n_line_strings)
{
GLineString ls;
ls.init_from_wkb(data, m_data_end - data);
if (ls.is_closed(closed))
return 1;
if (!*closed)
return 0;
data += ls.get_data_size() + WKB_HEADER_SIZE;
}
return 0;
}
/***************************** MultiPolygon *******************************/
size_t GMultiPolygon::get_data_size() const
{
uint32 n_polygons;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_polygons = uint4korr(data);
data += 4;
for (; n_polygons>0; --n_polygons)
{
if (no_data(data, 4 + WKB_HEADER_SIZE))
return 1;
uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE);
data += 4 + WKB_HEADER_SIZE;
for (; n_linear_rings > 0; --n_linear_rings)
{
data += 4 + uint4korr(data) * POINT_DATA_SIZE;
}
}
return data - m_data;
}
int GMultiPolygon::init_from_text(GTextReadStream *trs, String *wkb)
{
uint32 n_polygons = 0;
int np_pos = wkb->length();
GPolygon p;
if (wkb->reserve(4, 512))
return 1;
wkb->q_append((uint32)n_polygons);
for (;;)
{
if (wkb->reserve(1+4, 512))
return 1;
wkb->q_append((char)wkbNDR);
wkb->q_append((uint32)wkbPolygon);
if (trs->get_next_symbol() != '(')
{
trs->set_error_msg("'(' expected");
return 1;
}
if (p.init_from_text(trs, wkb))
return 1;
if (trs->get_next_symbol() != ')')
{
trs->set_error_msg("')' expected");
return 1;
}
++n_polygons;
if (trs->get_next_toc_type() == GTextReadStream::comma)
trs->get_next_symbol();
else
break;
}
wkb->WriteAtPosition(np_pos, n_polygons);
return 0;
}
int GMultiPolygon::get_data_as_text(String *txt) const
{
uint32 n_polygons;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_polygons = uint4korr(data);
data += 4;
for (; n_polygons>0; --n_polygons)
{
if (no_data(data, 4 + WKB_HEADER_SIZE))
return 1;
data += WKB_HEADER_SIZE;
uint32 n_linear_rings = uint4korr(data);
data += 4;
if (txt->reserve(1, 512))
return 1;
txt->q_append('(');
for (; n_linear_rings>0; --n_linear_rings)
{
if (no_data(data, 4))
return 1;
uint32 n_points = uint4korr(data);
data += 4;
if (no_data(data, (8+8)*n_points)) return 1;
if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points,
512)) return 1;
txt->qs_append('(');
for (; n_points>0; --n_points)
{
txt->qs_append((double *)data);
txt->qs_append(' ');
txt->qs_append((double *)(data + 8));
txt->qs_append(',');
data += 8+8;
}
(*txt)[txt->length()-1] = ')';
txt->qs_append(',');
}
(*txt)[txt->length()-1] = ')';
txt->qs_append(',');
}
txt->length(txt->length() - 1);
return 0;
}
int GMultiPolygon::get_mbr(MBR *mbr) const
{
uint32 n_polygons;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_polygons = uint4korr(data);
data += 4;
for (; n_polygons>0; --n_polygons)
{
if (no_data(data, 4+WKB_HEADER_SIZE))
return 1;
uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE);
data += WKB_HEADER_SIZE + 4;
for (; n_linear_rings>0; --n_linear_rings)
{
if (no_data(data, 4))
return 1;
uint32 n_points = uint4korr(data);
data += 4;
if (no_data(data, (8+8)*n_points))
return 1;
for (; n_points>0; --n_points)
{
mbr->add_xy((double *)data, (double *)(data + 8));
data += 8+8;
}
}
}
return 0;
}
int GMultiPolygon::area(double *ar) const
{
uint32 n_polygons;
const char *data = m_data;
double result = 0;
if (no_data(data, 4))
return 1;
n_polygons = uint4korr(data);
data += 4;
for (; n_polygons>0; --n_polygons)
{
double p_area;
GPolygon p;
data += WKB_HEADER_SIZE;
p.init_from_wkb(data, m_data_end - data);
if (p.area(&p_area))
return 1;
result += p_area;
data += p.get_data_size();
}
*ar = result;
return 0;
}
int GMultiPolygon::centroid(String *result) const
{
uint32 n_polygons;
uint i;
GPolygon p;
double res_area, res_cx, res_cy;
double cur_area, cur_cx, cur_cy;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_polygons = uint4korr(data);
data += 4;
for (i = 0; i < n_polygons; ++i)
{
data += WKB_HEADER_SIZE;
p.init_from_wkb(data, m_data_end - data);
if (p.area(&cur_area))
return 1;
if (p.centroid_xy(&cur_cx, &cur_cy))
return 1;
if(i)
{
double sum_area = res_area + cur_area;
res_cx = (res_area * res_cx + cur_area * cur_cx) / sum_area;
res_cy = (res_area * res_cy + cur_area * cur_cy) / sum_area;
}
else
{
res_area = cur_area;
res_cx = cur_cx;
res_cy = cur_cy;
}
data += p.get_data_size();
}
if (result->reserve(1 + 4 + sizeof(double) * 2))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkbPoint);
result->q_append(res_cx);
result->q_append(res_cy);
return 0;
}
/***************************** GeometryCollection *******************************/
size_t GGeometryCollection::get_data_size() const
{
uint32 n_objects;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_objects = uint4korr(data);
data += 4;
for (; n_objects>0; --n_objects)
{
if (no_data(data, WKB_HEADER_SIZE))
return 1;
uint32 wkb_type = uint4korr(data + sizeof(char));
data += WKB_HEADER_SIZE;
Geometry geom;
if (geom.init(wkb_type))
return 0;
geom.init_from_wkb(data, m_data_end - data);
size_t object_size=geom.get_data_size();
data += object_size;
}
return data - m_data;
}
int GGeometryCollection::init_from_text(GTextReadStream *trs, String *wkb)
{
uint32 n_objects = 0;
int no_pos = wkb->length();
Geometry g;
if (wkb->reserve(4, 512))
return 1;
wkb->q_append((uint32)n_objects);
for (;;)
{
if (g.create_from_wkt(trs, wkb))
return 1;
if (g.get_class_info()->m_type_id==wkbGeometryCollection)
{
trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
return 1;
}
++n_objects;
if (trs->get_next_toc_type() == GTextReadStream::comma)
trs->get_next_symbol();
else break;
}
wkb->WriteAtPosition(no_pos, n_objects);
return 0;
}
int GGeometryCollection::get_data_as_text(String *txt) const
{
uint32 n_objects;
const char *data = m_data;
Geometry geom;
if (no_data(data, 4))
return 1;
n_objects = uint4korr(data);
data += 4;
for (; n_objects>0; --n_objects)
{
if (no_data(data, WKB_HEADER_SIZE))
return 1;
uint32 wkb_type = uint4korr(data + sizeof(char));
data += WKB_HEADER_SIZE;
if (geom.init(wkb_type))
return 1;
geom.init_from_wkb(data, m_data_end - data);
if (geom.as_wkt(txt))
return 1;
data += geom.get_data_size();
txt->reserve(1, 512);
txt->q_append(',');
}
txt->length(txt->length() - 1);
return 0;
}
int GGeometryCollection::get_mbr(MBR *mbr) const
{
uint32 n_objects;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_objects = uint4korr(data);
data += 4;
for (; n_objects>0; --n_objects)
{
if(no_data(data, WKB_HEADER_SIZE))
return 1;
uint32 wkb_type = uint4korr(data + sizeof(char));
data += WKB_HEADER_SIZE;
Geometry geom;
if (geom.init(wkb_type))
return 1;
geom.init_from_wkb(data, m_data_end - data);
geom.get_mbr(mbr);
data += geom.get_data_size();
}
return 0;
}
int GGeometryCollection::num_geometries(uint32 *num) const
{
*num = uint4korr(m_data);
return 0;
}
int GGeometryCollection::geometry_n(uint32 num, String *result) const
{
const char *data = m_data;
uint32 n_objects;
if (no_data(data, 4))
return 1;
n_objects = uint4korr(data);
data += 4;
if ((num > n_objects) || (num < 1))
{
return -1;
}
for (; num > 0; --num)
{
if (no_data(data, WKB_HEADER_SIZE))
return 1;
uint32 wkb_type = uint4korr(data + sizeof(char));
data += WKB_HEADER_SIZE;
Geometry geom;
if (geom.init(wkb_type))
return 1;
geom.init_from_wkb(data, m_data_end - data);
if (num == 1)
{
if (result->reserve(1+4+geom.get_data_size()))
return 1;
result->q_append((char)wkbNDR);
result->q_append((uint32)wkb_type);
result->q_append(data, geom.get_data_size());
break;
}
else
{
data += geom.get_data_size();
}
}
return 0;
}
int GGeometryCollection::dimension(uint32 *dim) const
{
uint32 n_objects;
*dim = 0;
const char *data = m_data;
if (no_data(data, 4))
return 1;
n_objects = uint4korr(data);
data += 4;
for (; n_objects > 0; --n_objects)
{
if (no_data(data, WKB_HEADER_SIZE))
return 1;
uint32 wkb_type = uint4korr(data + sizeof(char));
data += WKB_HEADER_SIZE;
uint32 d;
Geometry geom;
if (geom.init(wkb_type))
return 1;
geom.init_from_wkb(data, m_data_end - data);
if (geom.dimension(&d))
return 1;
if (d > *dim)
*dim = d;
data += geom.get_data_size();
}
return 0;
}
/***************************** /objects *******************************/
#ifndef _spatial_h
#define _spatial_h
#include "gstream.h"
const int POINT_DATA_SIZE = 8+8;
const int WKB_HEADER_SIZE = 1+4;
struct stPoint2D
{
double x;
double y;
};
struct stLinearRing
{
size_t n_points;
stPoint2D points;
};
/***************************** MBR *******************************/
struct MBR
{
MBR()
{
xmin=DBL_MAX;
ymin=DBL_MAX;
xmax=-DBL_MAX;
ymax=-DBL_MAX;
}
MBR(const double &_xmin, const double &_ymin, const double &_xmax, const double &_ymax)
{
xmin=_xmin;
ymin=_ymin;
xmax=_xmax;
ymax=_ymax;
}
MBR(const stPoint2D &min, const stPoint2D &max)
{
xmin=min.x;
ymin=min.y;
xmax=max.x;
ymax=max.y;
}
double xmin;
double ymin;
double xmax;
double ymax;
void add_xy(double x, double y)
{ /* Not using "else" for proper one point MBR calculation */
if (x<xmin)
{
xmin=x;
}
if (x>xmax)
{
xmax=x;
}
if (y<ymin)
{
ymin=y;
}
if (y>ymax)
{
ymax=y;
}
}
void add_xy(double *px, double *py)
{ /* Not using "else" for proper one point MBR calculation */
double x, y;
float8get(x, px);
float8get(y, py);
if (x<xmin)
{
xmin=x;
}
if (x>xmax)
{
xmax=x;
}
if (y<ymin)
{
ymin=y;
}
if (y>ymax)
{
ymax=y;
}
}
void add_mbr(const MBR *mbr)
{
if (mbr->xmin<xmin)
{
xmin=mbr->xmin;
}
if (mbr->xmax>xmax)
{
xmax=mbr->xmax;
}
if (mbr->ymin<ymin)
{
ymin=mbr->ymin;
}
if (mbr->ymax>ymax)
{
ymax=mbr->ymax;
}
}
int equals(const MBR *mbr)
{
return (mbr->xmin==xmin)&&(mbr->ymin==ymin)&&(mbr->xmax==xmax)&&(mbr->ymax==ymax);
}
int disjoint(const MBR *mbr)
{
return (mbr->xmin>xmax)||(mbr->ymin>ymax)||(mbr->xmax<xmin)||(mbr->ymax<ymin);
}
int intersects(const MBR *mbr)
{
return !disjoint(mbr);
}
int touches(const MBR *mbr)
{
return (((mbr->xmin==xmax) || (mbr->xmax==xmin)) &&
((mbr->ymin>=ymin) && (mbr->ymin<=ymax) ||
(mbr->ymax>=ymin) && (mbr->ymax<=ymax))) ||
(((mbr->ymin==ymax) || (mbr->ymax==ymin)) &&
((mbr->xmin>=xmin) && (mbr->xmin<=xmax) ||
(mbr->xmax>=xmin)&&(mbr->xmax<=xmax)));
}
int within(const MBR *mbr)
{
return (mbr->xmin<=xmin) && (mbr->ymin<=ymin) &&
(mbr->xmax>=xmax) && (mbr->ymax>=ymax);
}
int contains(const MBR *mbr)
{
return (mbr->xmin>=xmin) && (mbr->ymin>=ymin) &&
(mbr->xmax<=xmax) && (mbr->ymax<=ymax);
}
bool inner_point(double x, double y) const
{
return (xmin<x) && (xmax>x) && (ymin<y) && (ymax>x);
}
int overlaps(const MBR *mbr)
{
int lb = mbr->inner_point(xmin, ymin);
int rb = mbr->inner_point(xmax, ymin);
int rt = mbr->inner_point(xmax, ymax);
int lt = mbr->inner_point(xmin, ymax);
int a = lb+rb+rt+lt;
return (a>0) && (a<4) && (!within(mbr));
}
};
/***************************** Geometry *******************************/
class Geometry;
typedef int (Geometry::*GF_InitFromText)(GTextReadStream *, String *);
typedef int (Geometry::*GF_GetDataAsText)(String *) const;
typedef size_t (Geometry::*GF_GetDataSize)() const;
typedef int (Geometry::*GF_GetMBR)(MBR *) const;
typedef int (Geometry::*GF_GetD)(double *) const;
typedef int (Geometry::*GF_GetI)(int *) const;
typedef int (Geometry::*GF_GetUI)(uint32 *) const;
typedef int (Geometry::*GF_GetWS)(String *) const;
typedef int (Geometry::*GF_GetUIWS)(uint32, String *) const;
#define GEOM_METHOD_PRESENT(geom_obj, method)\
(geom_obj.m_vmt->method != &Geometry::method)
class Geometry
{
public:
enum wkbType
{
wkbPoint = 1,
wkbLineString = 2,
wkbPolygon = 3,
wkbMultiPoint = 4,
wkbMultiLineString = 5,
wkbMultiPolygon = 6,
wkbGeometryCollection = 7
};
enum wkbByteOrder
{
wkbXDR = 0, /* Big Endian */
wkbNDR = 1 /* Little Endian */
};
class GClassInfo
{
public:
GF_InitFromText init_from_text;
GF_GetDataAsText get_data_as_text;
GF_GetDataSize get_data_size;
GF_GetMBR get_mbr;
GF_GetD get_x;
GF_GetD get_y;
GF_GetD length;
GF_GetD area;
GF_GetI is_closed;
GF_GetUI num_interior_ring;
GF_GetUI num_points;
GF_GetUI num_geometries;
GF_GetUI dimension;
GF_GetWS start_point;
GF_GetWS end_point;
GF_GetWS exterior_ring;
GF_GetWS centroid;
GF_GetUIWS point_n;
GF_GetUIWS interior_ring_n;
GF_GetUIWS geometry_n;
int m_type_id;
const char *m_name;
GClassInfo *m_next_rt;
};
GClassInfo *m_vmt;
const GClassInfo *get_class_info() const { return m_vmt; }
size_t get_data_size() const { return (this->*m_vmt->get_data_size)(); }
int init_from_text(GTextReadStream *trs, String *wkb)
{ return (this->*m_vmt->init_from_text)(trs, wkb); }
int get_data_as_text(String *txt) const
{ return (this->*m_vmt->get_data_as_text)(txt); }
int get_mbr(MBR *mbr) const { return (this->*m_vmt->get_mbr)(mbr); }
int dimension(uint32 *dim) const
{ return (this->*m_vmt->dimension)(dim); }
int get_x(double *x) const { return (this->*m_vmt->get_x)(x); }
int get_y(double *y) const { return (this->*m_vmt->get_y)(y); }
int length(double *len) const { return (this->*m_vmt->length)(len); }
int area(double *ar) const { return (this->*m_vmt->area)(ar); }
int is_closed(int *closed) const { return (this->*m_vmt->is_closed)(closed); }
int num_interior_ring(uint32 *n_int_rings) const
{ return (this->*m_vmt->num_interior_ring)(n_int_rings); }
int num_points(uint32 *n_points) const
{ return (this->*m_vmt->num_points)(n_points); }
int num_geometries(uint32 *num) const
{ return (this->*m_vmt->num_geometries)(num); }
int start_point(String *point) const
{ return (this->*m_vmt->start_point)(point); }
int end_point(String *point) const
{ return (this->*m_vmt->end_point)(point); }
int exterior_ring(String *ring) const
{ return (this->*m_vmt->exterior_ring)(ring); }
int centroid(String *point) const
{ return (this->*m_vmt->centroid)(point); }
int point_n(uint32 num, String *result) const
{ return (this->*m_vmt->point_n)(num, result); }
int interior_ring_n(uint32 num, String *result) const
{ return (this->*m_vmt->interior_ring_n)(num, result); }
int geometry_n(uint32 num, String *result) const
{ return (this->*m_vmt->geometry_n)(num, result); }
public:
int create_from_wkb(const char *data, uint32 data_len);
int create_from_wkt(GTextReadStream *trs, String *wkt, int init_stream=1);
int init(int type_id)
{
m_vmt = find_class(type_id);
return !m_vmt;
}
int new_geometry(const char *name, size_t len)
{
m_vmt = find_class(name, len);
return !m_vmt;
}
int as_wkt(String *wkt) const
{
if(wkt->reserve(strlen(get_class_info()->m_name) + 2, 512))
return 1;
wkt->qs_append(get_class_info()->m_name);
wkt->qs_append('(');
if(get_data_as_text(wkt))
return 1;
wkt->qs_append(')');
return 0;
}
void init_from_wkb(const char *data, uint32 data_len)
{
m_data = data;
m_data_end = data + data_len;
}
void shift_wkb_header()
{
m_data += WKB_HEADER_SIZE;
}
int envelope(String *result) const;
protected:
static GClassInfo *find_class(int type_id);
static GClassInfo *find_class(const char *name, size_t len);
bool no_data(const char *cur_data, uint32 data_amount) const
{
return cur_data + data_amount > m_data_end;
}
const char *m_data;
const char *m_data_end;
};
/***************************** Point *******************************/
class GPoint: public Geometry
{
public:
size_t get_data_size() const;
int init_from_text(GTextReadStream *trs, String *wkb);
int get_data_as_text(String *txt) const;
int get_mbr(MBR *mbr) const;
int get_xy(double *x, double *y) const
{
const char *data = m_data;
if(no_data(data, sizeof(double)) * 2) return 1;
float8get(*x, data);
float8get(*y, data + sizeof(double));
return 0;
}
int get_x(double *x) const
{
if(no_data(m_data, sizeof(double))) return 1;
float8get(*x, m_data);
return 0;
}
int get_y(double *y) const
{
const char *data = m_data;
if(no_data(data, sizeof(double)) * 2) return 1;
float8get(*y, data + sizeof(double));
return 0;
}
int dimension(uint32 *dim) const { *dim = 0; return 0; }
};
/***************************** LineString *******************************/
class GLineString: public Geometry
{
public:
size_t get_data_size() const;
int init_from_text(GTextReadStream *trs, String *wkb);
int get_data_as_text(String *txt) const;
int get_mbr(MBR *mbr) const;
int length(double *len) const;
int is_closed(int *closed) const;
int num_points(uint32 *n_points) const;
int start_point(String *point) const;
int end_point(String *point) const;
int point_n(uint32 n, String *result) const;
int dimension(uint32 *dim) const { *dim = 1; return 0; }
// IsRing
};
/***************************** Polygon *******************************/
class GPolygon: public Geometry
{
public:
size_t get_data_size() const;
int init_from_text(GTextReadStream *trs, String *wkb);
int get_data_as_text(String *txt) const;
int get_mbr(MBR *mbr) const;
int area(double *ar) const;
int exterior_ring(String *result) const;
int num_interior_ring(uint32 *n_int_rings) const;
int interior_ring_n(uint32 num, String *result) const;
int centroid_xy(double *x, double *y) const;
int centroid(String *result) const;
int dimension(uint32 *dim) const { *dim = 2; return 0; }
// PointOnSurface
};
/***************************** MultiPoint *******************************/
class GMultiPoint: public Geometry
{
public:
size_t get_data_size() const;
int init_from_text(GTextReadStream *trs, String *wkb);
int get_data_as_text(String *txt) const;
int get_mbr(MBR *mbr) const;
int dimension(uint32 *dim) const { *dim = 0; return 0; }
};
/***************************** MultiLineString *******************************/
class GMultiLineString: public Geometry
{
public:
size_t get_data_size() const;
int init_from_text(GTextReadStream *trs, String *wkb);
int get_data_as_text(String *txt) const;
int get_mbr(MBR *mbr) const;
int length(double *len) const;
int is_closed(int *closed) const;
int dimension(uint32 *dim) const { *dim = 1; return 0; }
};
/***************************** MultiPolygon *******************************/
class GMultiPolygon: public Geometry
{
public:
size_t get_data_size() const;
int init_from_text(GTextReadStream *trs, String *wkb);
int get_data_as_text(String *txt) const;
int get_mbr(MBR *mbr) const;
int area(double *ar) const;
int centroid(String *result) const;
int dimension(uint32 *dim) const { *dim = 2; return 0; }
// PointOnSurface
};
/***************************** GeometryCollection *******************************/
class GGeometryCollection: public Geometry
{
public:
size_t get_data_size() const;
int init_from_text(GTextReadStream *trs, String *wkb);
int get_data_as_text(String *txt) const;
int get_mbr(MBR *mbr) const;
int num_geometries(uint32 *num) const;
int geometry_n(uint32 num, String *result) const;
int dimension(uint32 *dim) const;
};
#endif
......@@ -198,13 +198,18 @@ class Alter_column :public Sql_alloc {
class Key :public Sql_alloc {
public:
enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT };
enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL };
enum Keytype type;
enum ha_key_alg alg; // +BAR
List<key_part_spec> columns;
const char *Name;
Key(enum Keytype type_par,const char *name_arg,List<key_part_spec> &cols)
:type(type_par), columns(cols),Name(name_arg) {}
Key(enum Keytype type_par, enum ha_key_alg alg_par, const char *name_arg,List<key_part_spec> &cols)
:type(type_par),alg(alg_par), columns(cols),Name(name_arg){} //+BAR
~Key() {}
const char *name() { return Name; }
};
......
......@@ -880,11 +880,17 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append("UNIQUE ", 7);
else if (key_info->flags & HA_FULLTEXT)
packet->append("FULLTEXT ", 9);
else if (key_info->flags & HA_SPATIAL)
packet->append("SPATIAL ", 8);
packet->append("KEY ", 4);
if (!found_primary)
append_identifier(thd,packet,key_info->name);
// +BAR: send USING only in non-default case: non-spatial rtree
if((key_info->key_alg == HA_KEY_ALG_RTREE) && !(key_info->flags & HA_SPATIAL))
packet->append(" USING RTREE",12);
packet->append(" (", 2);
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
......
......@@ -459,6 +459,44 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
return FALSE;
}
// added by Holyfoot for "geometry" needs
int String::reserve(uint32 space_needed, uint32 grow_by)
{
if (Alloced_length < str_length + space_needed)
{
if (realloc(Alloced_length + max(space_needed, grow_by) - 1))
return TRUE;
}
return FALSE;
}
void String::qs_append(const char *str)
{
int len = strlen(str);
memcpy(Ptr + str_length, str, len + 1);
str_length += len;
}
void String::qs_append(double d)
{
char *buff = Ptr + str_length;
sprintf(buff,"%.14g", d);
str_length += strlen(buff);
}
void String::qs_append(double *d)
{
double ld;
float8get(ld, d);
qs_append(ld);
}
void String::qs_append(const char &c)
{
Ptr[str_length] = c;
str_length += sizeof(c);
}
int sortcmp(const String *x,const String *y)
{
......@@ -805,3 +843,5 @@ int wild_compare(String &match,String &wild, char escape)
DBUG_RETURN(wild_compare(match.ptr(),match.ptr()+match.length(),
wild.ptr(), wild.ptr()+wild.length(),escape));
}
......@@ -188,4 +188,49 @@ class String
friend int wild_compare(String &match,String &wild,char escape);
uint32 numchars();
int charpos(int i,uint32 offset=0);
// added by Holyfoot for "geometry" needs
int reserve(uint32 space_needed)
{
return realloc(str_length + space_needed);
}
int reserve(uint32 space_needed, uint32 grow_by);
// these append operations do NOT check alloced memory
// q_*** methods writes values of parameters itself
// qs_*** methods writes string representation of value
void q_append(const char &c)
{
Ptr[str_length++] = c;
}
void q_append(const uint32 &n)
{
int4store(Ptr + str_length, n);
str_length += 4;
}
void q_append(double d)
{
float8store(Ptr + str_length, d);
str_length += 8;
}
void q_append(double *d)
{
float8store(Ptr + str_length, *d);
str_length += 8;
}
void q_append(const char *data, uint32 data_len)
{
memcpy(Ptr + str_length, data, data_len);
str_length += data_len;
}
void WriteAtPosition(int position, uint32 value)
{
int4store(Ptr + position,value);
}
void qs_append(const char *str);
void qs_append(double d);
void qs_append(double *d);
void qs_append(const char &c);
};
......@@ -438,8 +438,21 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
uint key_length=0;
key_part_spec *column;
key_info->flags= (key->type == Key::MULTIPLE) ? 0 :
(key->type == Key::FULLTEXT) ? HA_FULLTEXT : HA_NOSAME;
switch(key->type){
case Key::MULTIPLE:
key_info->flags = 0;
break;
case Key::FULLTEXT:
key_info->flags = HA_FULLTEXT;
break;
case Key::SPATIAL:
key_info->flags = HA_SPATIAL;
break;
default:
key_info->flags = HA_NOSAME;
}
key_info->key_alg = key->alg;
key_info->key_parts=(uint8) key->columns.elements;
key_info->key_part=key_part_info;
key_info->usable_key_parts= key_number;
......@@ -452,6 +465,30 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
}
/*
Make SPATIAL to be RTREE by default
SPATIAL only on BLOB or at least BINARY, this
actually should be replaced by special GEOM type
in near future when new frm file is ready
checking for proper key parts number:
*/
if(key_info->flags == HA_SPATIAL){
if(key_info->key_parts!=1){
my_printf_error(ER_WRONG_ARGUMENTS,
ER(ER_WRONG_ARGUMENTS),MYF(0),"SPATIAL INDEX");
DBUG_RETURN(-1);
}
}else
{
if(key_info->key_alg == HA_KEY_ALG_RTREE){
if((key_info->key_parts&1)==1){
my_printf_error(ER_WRONG_ARGUMENTS,
ER(ER_WRONG_ARGUMENTS),MYF(0),"RTREE INDEX");
DBUG_RETURN(-1);
}
}
}
List_iterator<key_part_spec> cols(key->columns);
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
......@@ -480,6 +517,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
{
if (key->type == Key::FULLTEXT)
column->length=1; /* ft-code ignores it anyway :-) */
else if (key->type == Key::SPATIAL)
{
/*
BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
Lately we'll extend this code to support more dimensions
*/
column->length=4*sizeof(double);
}
else
{
my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
......@@ -1471,11 +1516,13 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
key_part_length));
}
if (key_parts.elements)
key_list.push_back(new Key(key_info->flags & HA_NOSAME ?
key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
(key_info->flags & HA_NOSAME ?
(!my_strcasecmp(key_name, "PRIMARY") ?
Key::PRIMARY : Key::UNIQUE) :
(key_info->flags & HA_FULLTEXT ?
Key::FULLTEXT : Key::MULTIPLE),
Key::FULLTEXT : Key::MULTIPLE)),
key_info->key_alg,
key_name,key_parts));
}
key_it.rewind();
......
......@@ -54,6 +54,7 @@ inline Item *or_or_concat(Item* A, Item* B)
List<Item> *item_list;
List<String> *string_list;
Key::Keytype key_type;
enum ha_key_alg key_alg;
enum db_type db_type;
enum row_type row_type;
enum ha_rkey_function ha_rkey_mode;
......@@ -154,6 +155,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token BOOL_SYM
%token BOOLEAN_SYM
%token BOTH
%token BTREE_SYM
%token BY
%token CACHE_SYM
%token CASCADE
......@@ -200,6 +202,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token GREATEST_SYM
%token GROUP
%token HAVING
%token HASH_SYM
%token HEAP_SYM
%token HEX_NUM
%token HIGH_PRIORITY
......@@ -291,10 +294,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ROWS_SYM
%token ROW_FORMAT_SYM
%token ROW_SYM
%token RTREE_SYM
%token SET
%token SERIALIZABLE_SYM
%token SESSION_SYM
%token SHUTDOWN
%token SPATIAL_SYM
%token SQL_CACHE_SYM
%token SQL_NO_CACHE_SYM
%token SSL_SYM
......@@ -344,6 +349,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ENUM
%token FAST_SYM
%token FLOAT_SYM
%token GEOM_SYM
%token INT_SYM
%token LIMIT
%token LONGBLOB
......@@ -401,6 +407,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token FORMAT_SYM
%token FOR_SYM
%token FROM_UNIXTIME
%token GEOMETRYCOLLECTION
%token GROUP_UNIQUE_USERS
%token HOUR_MINUTE_SYM
%token HOUR_SECOND_SYM
......@@ -412,6 +419,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token INTERVAL_SYM
%token LAST_INSERT_ID
%token LEFT
%token LINESTRING
%token LOCATE
%token MAKE_SET_SYM
%token MINUTE_SECOND_SYM
......@@ -419,8 +427,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MODE_SYM
%token MODIFY_SYM
%token MONTH_SYM
%token MULTILINESTRING
%token MULTIPOINT
%token MULTIPOLYGON
%token NOW_SYM
%token PASSWORD
%token POLYGON
%token POSITION_SYM
%token PROCEDURE
%token RAND
......@@ -527,6 +539,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <key_type>
key_type opt_unique_or_fulltext
%type <key_alg>
key_alg opt_btree_or_rtree
%type <string_list>
key_usage_list
......@@ -713,11 +728,11 @@ create:
}
create2
| CREATE opt_unique_or_fulltext INDEX ident ON table_ident
| CREATE opt_unique_or_fulltext INDEX ident key_alg ON table_ident
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_INDEX;
if (!add_table_to_list($6,NULL,1))
if (!add_table_to_list($7,NULL,1))
YYABORT;
lex->create_list.empty();
lex->key_list.empty();
......@@ -727,7 +742,8 @@ create:
'(' key_list ')'
{
LEX *lex=Lex;
lex->key_list.push_back(new Key($2,$4.str,lex->col_list));
lex->key_list.push_back(new Key($2,$5,$4.str,lex->col_list));
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
......@@ -874,10 +890,10 @@ field_list_item:
{
Lex->col_list.empty(); /* Alloced by sql_alloc */
}
| key_type opt_ident '(' key_list ')'
| key_type opt_ident key_alg '(' key_list ')'
{
LEX *lex=Lex;
lex->key_list.push_back(new Key($1,$2,lex->col_list));
lex->key_list.push_back(new Key($1,$3,$2,lex->col_list));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
......@@ -942,6 +958,8 @@ type:
$$=FIELD_TYPE_TINY_BLOB; }
| BLOB_SYM { Lex->type|=BINARY_FLAG;
$$=FIELD_TYPE_BLOB; }
| GEOM_SYM { Lex->type|=BINARY_FLAG;
$$=FIELD_TYPE_GEOMETRY; }
| MEDIUMBLOB { Lex->type|=BINARY_FLAG;
$$=FIELD_TYPE_MEDIUM_BLOB; }
| LONGBLOB { Lex->type|=BINARY_FLAG;
......@@ -1083,6 +1101,8 @@ key_type:
| key_or_index { $$= Key::MULTIPLE; }
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
| FULLTEXT_SYM key_or_index { $$= Key::FULLTEXT; }
| SPATIAL_SYM { $$= Key::SPATIAL; }
| SPATIAL_SYM key_or_index { $$= Key::SPATIAL; }
| opt_constraint UNIQUE_SYM { $$= Key::UNIQUE; }
| opt_constraint UNIQUE_SYM key_or_index { $$= Key::UNIQUE; }
......@@ -1099,6 +1119,16 @@ opt_unique_or_fulltext:
/* empty */ { $$= Key::MULTIPLE; }
| UNIQUE_SYM { $$= Key::UNIQUE; }
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
| SPATIAL_SYM { $$= Key::SPATIAL; }
key_alg:
/* empty */ { $$= HA_KEY_ALG_BTREE; }
| USING opt_btree_or_rtree { $$= $2 }
opt_btree_or_rtree:
BTREE_SYM { $$= HA_KEY_ALG_BTREE; }
| RTREE_SYM { $$= HA_KEY_ALG_RTREE; }
| HASH_SYM { $$= HA_KEY_ALG_HASH; }
key_list:
key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
......@@ -1684,6 +1714,10 @@ simple_expr:
}
| FIELD_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_field($3, *$5); }
| GEOMETRYCOLLECTION '(' expr_list ')'
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbGeometryCollection,
Geometry::wkbPoint); }
| HOUR_SYM '(' expr ')'
{ $$= new Item_func_hour($3); }
| IF '(' expr ',' expr ',' expr ')'
......@@ -1708,6 +1742,9 @@ simple_expr:
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
| LINESTRING '(' expr_list ')'
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbLineString, Geometry::wkbPoint); }
| LOCATE '(' expr ',' expr ')'
{ $$= new Item_func_locate($5,$3); }
| LOCATE '(' expr ',' expr ',' expr ')'
......@@ -1720,6 +1757,15 @@ simple_expr:
{ $$= new Item_func_minute($3); }
| MONTH_SYM '(' expr ')'
{ $$= new Item_func_month($3); }
| MULTILINESTRING '(' expr_list ')'
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbMultiLineString, Geometry::wkbLineString); }
| MULTIPOINT '(' expr_list ')'
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbMultiPoint, Geometry::wkbPoint); }
| MULTIPOLYGON '(' expr_list ')'
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbMultiPolygon, Geometry::wkbPolygon ); }
| NOW_SYM optional_braces
{ $$= new Item_func_now(); current_thd->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
......@@ -1728,6 +1774,9 @@ simple_expr:
{
$$= new Item_func_password($3);
}
| POLYGON '(' expr_list ')'
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbPolygon, Geometry::wkbLineString); }
| POSITION_SYM '(' no_in_expr IN_SYM expr ')'
{ $$ = new Item_func_locate($5,$3); }
| RAND '(' expr ')'
......
......@@ -64,6 +64,7 @@ typedef struct st_key_part_info { /* Info about a key part */
typedef struct st_key {
uint key_length; /* Tot length of key */
uint flags; /* dupp key and pack flags */
enum ha_key_alg key_alg; /* +BAR Algorithm BTREE or RTREE */
uint key_parts; /* How many key_parts */
uint extra_length;
uint usable_key_parts; /* Should normally be = key_parts */
......
......@@ -153,7 +153,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{
keyinfo->flags= ((uint) strpos[0]) ^ HA_NOSAME;
keyinfo->key_length= (uint) uint2korr(strpos+1);
keyinfo->key_parts= (uint) strpos[3]; strpos+=4;
keyinfo->key_parts= (uint) strpos[3];
strpos+=4;
keyinfo->key_part= key_part;
keyinfo->rec_per_key= rec_per_key;
for (j=keyinfo->key_parts ; j-- ; key_part++)
......@@ -395,6 +397,26 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
}
keyinfo->key_alg=HA_KEY_ALG_BTREE; // BAR : btree by default
#define BAR_DIRTY_HACK
#ifdef BAR_DIRTY_HACK
// BAR FIXME: Dirty hack while waiting for new .frm format
switch(keyinfo->name[0]){
case 'R':
keyinfo->key_alg=HA_KEY_ALG_RTREE;
break;
case 'S':
keyinfo->key_alg = HA_KEY_ALG_RTREE;
keyinfo->flags |= HA_SPATIAL;
break;
case 'B':
default:
keyinfo->key_alg=HA_KEY_ALG_BTREE;
break;
}
#endif
for (i=0 ; i < keyinfo->key_parts ; key_part++,i++)
{
if (new_field_pack_flag <= 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment