Commit 788043cd authored by Alexey Botchkov's avatar Alexey Botchkov

Precise GIS functions added.

parent aaf9fb0d
......@@ -136,6 +136,7 @@ SET(LIBMYSQLD_SOURCES libmysqld.c emb_qcache.cc lib_sql.cc
../sql/sql_tablespace.cc ../sql/sql_table.cc ../sql/sql_test.cc
../sql/sql_trigger.cc ../sql/sql_udf.cc ../sql/sql_union.cc
../sql/sql_update.cc ../sql/sql_view.cc ../sql/sql_profile.cc
../sql/gcalc_tools.cc ../sql/gcalc_slicescan.cc
../sql/strfunc.cc ../sql/table.cc ../sql/thr_malloc.cc
../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc
../sql/partition_info.cc ../sql/sql_connect.cc
......
......@@ -62,6 +62,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
opt_sum.cc procedure.cc records.cc sql_acl.cc \
sql_load.cc discover.cc sql_locale.cc \
sql_profile.cc \
gcalc_slicescan.cc gcalc_tools.cc \
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \
sql_join_cache.cc \
......
......@@ -12,6 +12,156 @@ t1 CREATE TABLE `t1` (
PRIMARY KEY (`fid`),
SPATIAL KEY `g` (`g`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(148 148, 152 152)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(147 147, 153 153)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(146 146, 154 154)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(145 145, 155 155)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(144 144, 156 156)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(143 143, 157 157)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(142 142, 158 158)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(141 141, 159 159)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(140 140, 160 160)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(139 139, 161 161)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(138 138, 162 162)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(137 137, 163 163)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(136 136, 164 164)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(135 135, 165 165)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(134 134, 166 166)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(133 133, 167 167)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(132 132, 168 168)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(131 131, 169 169)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(130 130, 170 170)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(129 129, 171 171)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(128 128, 172 172)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(127 127, 173 173)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(126 126, 174 174)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(125 125, 175 175)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(124 124, 176 176)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(123 123, 177 177)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(122 122, 178 178)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(121 121, 179 179)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(120 120, 180 180)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(119 119, 181 181)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(118 118, 182 182)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(117 117, 183 183)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(116 116, 184 184)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(115 115, 185 185)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(114 114, 186 186)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(113 113, 187 187)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(112 112, 188 188)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(111 111, 189 189)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(110 110, 190 190)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(109 109, 191 191)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(108 108, 192 192)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(107 107, 193 193)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(106 106, 194 194)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(105 105, 195 195)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(104 104, 196 196)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(103 103, 197 197)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(102 102, 198 198)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(101 101, 199 199)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(100 100, 200 200)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(99 99, 201 201)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(98 98, 202 202)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(97 97, 203 203)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(96 96, 204 204)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(95 95, 205 205)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(94 94, 206 206)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(93 93, 207 207)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(92 92, 208 208)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(91 91, 209 209)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(90 90, 210 210)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(89 89, 211 211)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(88 88, 212 212)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(87 87, 213 213)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(86 86, 214 214)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(85 85, 215 215)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(84 84, 216 216)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(83 83, 217 217)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(82 82, 218 218)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(81 81, 219 219)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(80 80, 220 220)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(79 79, 221 221)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(78 78, 222 222)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(77 77, 223 223)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(76 76, 224 224)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(75 75, 225 225)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(74 74, 226 226)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(73 73, 227 227)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(72 72, 228 228)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(71 71, 229 229)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(70 70, 230 230)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(69 69, 231 231)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(68 68, 232 232)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(67 67, 233 233)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(66 66, 234 234)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(65 65, 235 235)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(64 64, 236 236)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(63 63, 237 237)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(62 62, 238 238)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(61 61, 239 239)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(60 60, 240 240)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(59 59, 241 241)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(58 58, 242 242)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(57 57, 243 243)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(56 56, 244 244)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(55 55, 245 245)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(54 54, 246 246)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(53 53, 247 247)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(52 52, 248 248)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(51 51, 249 249)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(50 50, 250 250)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(49 49, 251 251)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(48 48, 252 252)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(47 47, 253 253)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(46 46, 254 254)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(45 45, 255 255)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(44 44, 256 256)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(43 43, 257 257)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(42 42, 258 258)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(41 41, 259 259)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(40 40, 260 260)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(39 39, 261 261)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(38 38, 262 262)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(37 37, 263 263)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(36 36, 264 264)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(35 35, 265 265)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(34 34, 266 266)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(33 33, 267 267)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(32 32, 268 268)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(31 31, 269 269)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(30 30, 270 270)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(29 29, 271 271)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(28 28, 272 272)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(27 27, 273 273)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(26 26, 274 274)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(25 25, 275 275)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(24 24, 276 276)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(23 23, 277 277)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(22 22, 278 278)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(21 21, 279 279)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(20 20, 280 280)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(19 19, 281 281)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(18 18, 282 282)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(17 17, 283 283)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(16 16, 284 284)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(15 15, 285 285)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(14 14, 286 286)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(13 13, 287 287)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(12 12, 288 288)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(11 11, 289 289)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(10 10, 290 290)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(9 9, 291 291)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(8 8, 292 292)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(7 7, 293 293)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(6 6, 294 294)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(5 5, 295 295)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(4 4, 296 296)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(3 3, 297 297)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(2 2, 298 298)'));
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 1, 299 299)'));
SELECT count(*) FROM t1;
count(*)
150
......@@ -20,22 +170,112 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range g g 34 NULL 8 Using where
SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
fid AsText(g)
1 LINESTRING(150 150,150 150)
3 LINESTRING(148 148,152 152)
4 LINESTRING(147 147,153 153)
5 LINESTRING(146 146,154 154)
6 LINESTRING(145 145,155 155)
7 LINESTRING(144 144,156 156)
8 LINESTRING(143 143,157 157)
9 LINESTRING(142 142,158 158)
10 LINESTRING(141 141,159 159)
11 LINESTRING(140 140,160 160)
2 LINESTRING(149 149,151 151)
DROP TABLE t1;
CREATE TABLE t2 (
fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
g GEOMETRY NOT NULL
) ENGINE=MyISAM;
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10)));
INSERT INTO t2 (g) VALUES (LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10)));
ALTER TABLE t2 ADD SPATIAL KEY(g);
SHOW CREATE TABLE t2;
Table Create Table
......@@ -51,218 +291,414 @@ count(*)
EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range g g 34 NULL 4 Using where
1 SIMPLE t2 range g g 34 NULL 1 Using where
SELECT fid, AsText(g) FROM t2 WHERE Within(g,
GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
fid AsText(g)
46 LINESTRING(51 41,60 50)
56 LINESTRING(41 41,50 50)
45 LINESTRING(51 51,60 60)
55 LINESTRING(41 51,50 60)
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))));
SELECT count(*) FROM t2;
count(*)
100
DROP TABLE t2;
drop table if exists t1;
Warnings:
Note 1051 Unknown table 't1'
Note 1051 Unknown table 'test.t1'
CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a));
INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
......
......@@ -228,7 +228,7 @@ explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelo
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE gis_geometry ALL NULL NULL NULL NULL 21 100.00
Warnings:
Note 1003 select dimension(`test`.`gis_geometry`.`g`) AS `Dimension(g)`,geometrytype(`test`.`gis_geometry`.`g`) AS `GeometryType(g)`,isempty(`test`.`gis_geometry`.`g`) AS `IsEmpty(g)`,astext(envelope(`test`.`gis_geometry`.`g`)) AS `AsText(Envelope(g))` from `test`.`gis_geometry`
Note 1003 select st_dimension(`test`.`gis_geometry`.`g`) AS `Dimension(g)`,st_geometrytype(`test`.`gis_geometry`.`g`) AS `GeometryType(g)`,st_isempty(`test`.`gis_geometry`.`g`) AS `IsEmpty(g)`,st_astext(st_envelope(`test`.`gis_geometry`.`g`)) AS `AsText(Envelope(g))` from `test`.`gis_geometry`
SELECT fid, X(g) FROM gis_point;
fid X(g)
101 10
......@@ -245,7 +245,7 @@ explain extended select X(g),Y(g) FROM gis_point;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE gis_point ALL NULL NULL NULL NULL 4 100.00
Warnings:
Note 1003 select x(`test`.`gis_point`.`g`) AS `X(g)`,y(`test`.`gis_point`.`g`) AS `Y(g)` from `test`.`gis_point`
Note 1003 select st_x(`test`.`gis_point`.`g`) AS `X(g)`,st_y(`test`.`gis_point`.`g`) AS `Y(g)` from `test`.`gis_point`
SELECT fid, AsText(StartPoint(g)) FROM gis_line;
fid AsText(StartPoint(g))
105 POINT(0 0)
......@@ -258,7 +258,7 @@ fid AsText(EndPoint(g))
107 POINT(40 10)
SELECT fid, GLength(g) FROM gis_line;
fid GLength(g)
105 24.142135623731
105 24.14213562373095
106 40
107 30
SELECT fid, NumPoints(g) FROM gis_line;
......@@ -280,11 +280,11 @@ explain extended select AsText(StartPoint(g)),AsText(EndPoint(g)),GLength(g),Num
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE gis_line ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 select astext(startpoint(`test`.`gis_line`.`g`)) AS `AsText(StartPoint(g))`,astext(endpoint(`test`.`gis_line`.`g`)) AS `AsText(EndPoint(g))`,glength(`test`.`gis_line`.`g`) AS `GLength(g)`,numpoints(`test`.`gis_line`.`g`) AS `NumPoints(g)`,astext(pointn(`test`.`gis_line`.`g`,2)) AS `AsText(PointN(g, 2))`,isclosed(`test`.`gis_line`.`g`) AS `IsClosed(g)` from `test`.`gis_line`
Note 1003 select st_astext(st_startpoint(`test`.`gis_line`.`g`)) AS `AsText(StartPoint(g))`,st_astext(st_endpoint(`test`.`gis_line`.`g`)) AS `AsText(EndPoint(g))`,st_length(`test`.`gis_line`.`g`) AS `GLength(g)`,st_numpoints(`test`.`gis_line`.`g`) AS `NumPoints(g)`,st_astext(st_pointn(`test`.`gis_line`.`g`,2)) AS `AsText(PointN(g, 2))`,st_isclosed(`test`.`gis_line`.`g`) AS `IsClosed(g)` from `test`.`gis_line`
SELECT fid, AsText(Centroid(g)) FROM gis_polygon;
fid AsText(Centroid(g))
108 POINT(15 15)
109 POINT(25.4166666666667 25.4166666666667)
109 POINT(25.416666666666668 25.416666666666668)
110 POINT(20 10)
SELECT fid, Area(g) FROM gis_polygon;
fid Area(g)
......@@ -310,7 +310,7 @@ explain extended select AsText(Centroid(g)),Area(g),AsText(ExteriorRing(g)),NumI
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE gis_polygon ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 select astext(centroid(`test`.`gis_polygon`.`g`)) AS `AsText(Centroid(g))`,area(`test`.`gis_polygon`.`g`) AS `Area(g)`,astext(exteriorring(`test`.`gis_polygon`.`g`)) AS `AsText(ExteriorRing(g))`,numinteriorrings(`test`.`gis_polygon`.`g`) AS `NumInteriorRings(g)`,astext(interiorringn(`test`.`gis_polygon`.`g`,1)) AS `AsText(InteriorRingN(g, 1))` from `test`.`gis_polygon`
Note 1003 select st_astext(st_centroid(`test`.`gis_polygon`.`g`)) AS `AsText(Centroid(g))`,st_area(`test`.`gis_polygon`.`g`) AS `Area(g)`,st_astext(st_exteriorring(`test`.`gis_polygon`.`g`)) AS `AsText(ExteriorRing(g))`,st_numinteriorrings(`test`.`gis_polygon`.`g`) AS `NumInteriorRings(g)`,st_astext(st_interiorringn(`test`.`gis_polygon`.`g`,1)) AS `AsText(InteriorRingN(g, 1))` from `test`.`gis_polygon`
SELECT fid, IsClosed(g) FROM gis_multi_line;
fid IsClosed(g)
114 0
......@@ -318,8 +318,8 @@ fid IsClosed(g)
116 0
SELECT fid, AsText(Centroid(g)) FROM gis_multi_polygon;
fid AsText(Centroid(g))
117 POINT(55.5885277530424 17.426536064114)
118 POINT(55.5885277530424 17.426536064114)
117 POINT(55.58852775304245 17.426536064113982)
118 POINT(55.58852775304245 17.426536064113982)
119 POINT(2 2)
SELECT fid, Area(g) FROM gis_multi_polygon;
fid Area(g)
......@@ -349,7 +349,7 @@ explain extended SELECT fid, NumGeometries(g) from gis_multi_point;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,numgeometries(`test`.`gis_multi_point`.`g`) AS `NumGeometries(g)` from `test`.`gis_multi_point`
Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,st_numgeometries(`test`.`gis_multi_point`.`g`) AS `NumGeometries(g)` from `test`.`gis_multi_point`
SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
fid AsText(GeometryN(g, 2))
111 POINT(10 10)
......@@ -377,17 +377,17 @@ explain extended SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE gis_multi_point ALL NULL NULL NULL NULL 3 100.00
Warnings:
Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,astext(geometryn(`test`.`gis_multi_point`.`g`,2)) AS `AsText(GeometryN(g, 2))` from `test`.`gis_multi_point`
Note 1003 select `test`.`gis_multi_point`.`fid` AS `fid`,st_astext(st_geometryn(`test`.`gis_multi_point`.`g`,2)) AS `AsText(GeometryN(g, 2))` from `test`.`gis_multi_point`
SELECT g1.fid as first, g2.fid as second,
Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o,
Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t,
Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r
FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second;
first second w c o e d t i r
120 120 1 1 0 1 0 0 1 0
120 120 1 1 0 1 0 1 1 0
120 121 0 0 1 0 0 0 1 0
121 120 0 0 1 0 0 0 1 0
121 121 1 1 0 1 0 0 1 0
121 121 1 1 0 1 0 1 1 0
explain extended SELECT g1.fid as first, g2.fid as second,
Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o,
Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t,
......@@ -395,9 +395,9 @@ Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r
FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE g1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
1 SIMPLE g2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
1 SIMPLE g2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (BNL, regular buffers)
Warnings:
Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,within(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,contains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,overlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,equals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,disjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,intersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid`
Note 1003 select `test`.`g1`.`fid` AS `first`,`test`.`g2`.`fid` AS `second`,mbrwithin(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `w`,mbrcontains(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `c`,mbroverlaps(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `o`,mbrequals(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `e`,mbrdisjoint(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `d`,st_touches(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `t`,mbrintersects(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `i`,st_crosses(`test`.`g1`.`g`,`test`.`g2`.`g`) AS `r` from `test`.`gis_geometrycollection` `g1` join `test`.`gis_geometrycollection` `g2` order by `test`.`g1`.`fid`,`test`.`g2`.`fid`
DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
CREATE TABLE t1 (
gp point,
......@@ -439,12 +439,12 @@ explain extended SELECT AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select astext(geometryfromwkb(aswkb(geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)'))))`
Note 1003 select st_astext(st_geometryfromwkb(st_aswkb(st_geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)'))))`
explain extended SELECT AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)'))));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select astext(geometryfromwkb(aswkb(geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)'))))`
Note 1003 select st_astext(st_geometryfromwkb(st_aswkb(st_geometryfromtext('POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)'))))`
SELECT SRID(GeomFromText('LineString(1 1,2 2)',101));
SRID(GeomFromText('LineString(1 1,2 2)',101))
101
......@@ -452,12 +452,12 @@ explain extended SELECT SRID(GeomFromText('LineString(1 1,2 2)',101));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select srid(geometryfromtext('LineString(1 1,2 2)',101)) AS `SRID(GeomFromText('LineString(1 1,2 2)',101))`
Note 1003 select srid(st_geometryfromtext('LineString(1 1,2 2)',101)) AS `SRID(GeomFromText('LineString(1 1,2 2)',101))`
explain extended select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimple(Point(3, 6));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select issimple(multipoint(point(3,6),point(4,10))) AS `issimple(MultiPoint(Point(3, 6), Point(4, 10)))`,issimple(point(3,6)) AS `issimple(Point(3, 6))`
Note 1003 select st_issimple(st_multipoint(st_point(3,6),st_point(4,10))) AS `issimple(MultiPoint(Point(3, 6), Point(4, 10)))`,st_issimple(st_point(3,6)) AS `issimple(Point(3, 6))`
create table t1 (a geometry not null);
insert into t1 values (GeomFromText('Point(1 2)'));
insert into t1 values ('Garbage');
......@@ -651,11 +651,11 @@ insert into t1 values ('85984',GeomFromText('MULTIPOLYGON(((-115.006363
select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from
t1 where object_id=85998;
object_id geometrytype(geo) ISSIMPLE(GEO) ASTEXT(centroid(geo))
85998 MULTIPOLYGON 0 POINT(115.318773152032 -36.2374728210215)
85998 MULTIPOLYGON 1 POINT(115.31877315203187 -36.23747282102153)
select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from
t1 where object_id=85984;
object_id geometrytype(geo) ISSIMPLE(GEO) ASTEXT(centroid(geo))
85984 MULTIPOLYGON 0 POINT(-114.877871869233 36.3310176346905)
85984 MULTIPOLYGON 1 POINT(-114.87787186923313 36.33101763469059)
drop table t1;
create table t1 (fl geometry not null);
insert into t1 values (1);
......@@ -1014,12 +1014,392 @@ SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000
SET @a=POLYFROMWKB(@a);
SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440;
SET @a=POLYFROMWKB(@a);
create table t1(a polygon NOT NULL)engine=myisam;
insert into t1 values (geomfromtext("point(0 1)"));
insert into t1 values (geomfromtext("point(1 0)"));
select * from (select polygon(t1.a) as p from t1 order by t1.a) d;
p
NULL
NULL
drop table t1;
End of 5.1 tests
CREATE TABLE t1(
col0 BINARY NOT NULL,
col2 TIMESTAMP,
SPATIAL INDEX i1 (col0)
) ENGINE=MyISAM;
ERROR 42000: A SPATIAL index may only contain a geometrical type column
CREATE TABLE t1 (
col0 BINARY NOT NULL,
col2 TIMESTAMP
) ENGINE=MyISAM;
CREATE SPATIAL INDEX idx0 ON t1(col0);
ERROR 42000: A SPATIAL index may only contain a geometrical type column
ALTER TABLE t1 ADD SPATIAL INDEX i1 (col0);
ERROR 42000: A SPATIAL index may only contain a geometrical type column
CREATE TABLE t2 (
col0 INTEGER NOT NULL,
col1 POINT,
col2 POINT
);
CREATE SPATIAL INDEX idx0 ON t2 (col1, col2);
ERROR HY000: Incorrect arguments to SPATIAL INDEX
CREATE TABLE t3 (
col0 INTEGER NOT NULL,
col1 POINT,
col2 LINESTRING,
SPATIAL INDEX i1 (col1, col2)
);
ERROR HY000: Incorrect arguments to SPATIAL INDEX
DROP TABLE t1;
DROP TABLE t2;
DROP DATABASE IF EXISTS gis_ogs;
CREATE DATABASE gis_ogs;
USE gis_ogs;
#
# C.3.3.1 Geometry types and functions schema construction
#
CREATE TABLE lakes (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
shore POLYGON);
CREATE TABLE road_segments (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
aliases CHARACTER VARYING(64),
num_lanes INTEGER,
centerline LINESTRING);
CREATE TABLE divided_routes (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
num_lanes INTEGER,
centerlines MULTILINESTRING);
CREATE TABLE forests (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
boundary MULTIPOLYGON);
CREATE TABLE bridges (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
position POINT);
CREATE TABLE streams (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
centerline LINESTRING);
CREATE TABLE buildings (
fid INTEGER NOT NULL PRIMARY KEY,
address CHARACTER VARYING(64),
position POINT,
footprint POLYGON);
CREATE TABLE ponds (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
type CHARACTER VARYING(64),
shores MULTIPOLYGON);
CREATE TABLE named_places (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
boundary POLYGON);
CREATE TABLE map_neatlines (
fid INTEGER NOT NULL PRIMARY KEY,
neatline POLYGON);
#
# C.3.3.2 Geometry types and functions schema data loading
#
# Lakes
INSERT INTO lakes VALUES (
101, 'BLUE LAKE',
PolyFromText(
'POLYGON(
(52 18,66 23,73 9,48 6,52 18),
(59 18,67 18,67 13,59 13,59 18)
)',
101));
# Road Segments
INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2,
LineFromText(
'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4,
LineFromText(
'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2,
LineFromText(
'LINESTRING( 70 38, 72 48 )' ,101));
INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4,
LineFromText(
'LINESTRING( 70 38, 84 42 )' ,101));
INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL,
1,
LineFromText(
'LINESTRING( 28 26, 28 0 )',101));
# DividedRoutes
INSERT INTO divided_routes VALUES(119, 'Route 75', 4,
MLineFromText(
'MULTILINESTRING((10 48,10 21,10 0),
(16 0,16 23,16 48))', 101));
# Forests
INSERT INTO forests VALUES(109, 'Green Forest',
MPolyFromText(
'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),
(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))',
101));
# Bridges
INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText(
'POINT( 44 31 )', 101));
# Streams
INSERT INTO streams VALUES(111, 'Cam Stream',
LineFromText(
'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
INSERT INTO streams VALUES(112, NULL,
LineFromText(
'LINESTRING( 76 0, 78 4, 73 9 )', 101));
# Buildings
INSERT INTO buildings VALUES(113, '123 Main Street',
PointFromText(
'POINT( 52 30 )', 101),
PolyFromText(
'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101));
INSERT INTO buildings VALUES(114, '215 Main Street',
PointFromText(
'POINT( 64 33 )', 101),
PolyFromText(
'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101));
# Ponds
INSERT INTO ponds VALUES(120, NULL, 'Stock Pond',
MPolyFromText(
'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ),
( ( 26 44, 26 40, 28 42, 26 44) ) )', 101));
# Named Places
INSERT INTO named_places VALUES(117, 'Ashton',
PolyFromText(
'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
INSERT INTO named_places VALUES(118, 'Goose Island',
PolyFromText(
'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
# Map Neatlines
INSERT INTO map_neatlines VALUES(115,
PolyFromText(
'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101));
#
# C.3.3.3 Geometry types and functions schema test queries
# Conformance Item T6
SELECT Dimension(shore)
FROM lakes
WHERE name = 'Blue Lake';
Dimension(shore)
2
# Conformance Item T7
SELECT GeometryType(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
GeometryType(centerlines)
MULTILINESTRING
# Conformance Item T8
SELECT AsText(boundary)
FROM named_places
WHERE name = 'Goose Island';
AsText(boundary)
POLYGON((67 13,67 18,59 18,59 13,67 13))
# Conformance Item T9
SELECT AsText(PolyFromWKB(AsBinary(boundary),101))
FROM named_places
WHERE name = 'Goose Island';
AsText(PolyFromWKB(AsBinary(boundary),101))
POLYGON((67 13,67 18,59 18,59 13,67 13))
# Conformance Item T10
SELECT SRID(boundary)
FROM named_places
WHERE name = 'Goose Island';
SRID(boundary)
101
# Conformance Item T11
SELECT IsEmpty(centerline)
FROM road_segments
WHERE name = 'Route 5'
AND aliases = 'Main Street';
IsEmpty(centerline)
0
# Conformance Item T14
SELECT AsText(Envelope(boundary))
FROM named_places
WHERE name = 'Goose Island';
AsText(Envelope(boundary))
POLYGON((59 13,67 13,67 18,59 18,59 13))
# Conformance Item T15
SELECT X(position)
FROM bridges
WHERE name = 'Cam Bridge';
X(position)
44
# Conformance Item T16
SELECT Y(position)
FROM bridges
WHERE name = 'Cam Bridge';
Y(position)
31
# Conformance Item T17
SELECT AsText(StartPoint(centerline))
FROM road_segments
WHERE fid = 102;
AsText(StartPoint(centerline))
POINT(0 18)
# Conformance Item T18
SELECT AsText(EndPoint(centerline))
FROM road_segments
WHERE fid = 102;
AsText(EndPoint(centerline))
POINT(44 31)
# Conformance Item T21
SELECT GLength(centerline)
FROM road_segments
WHERE fid = 106;
GLength(centerline)
26
# Conformance Item T22
SELECT NumPoints(centerline)
FROM road_segments
WHERE fid = 102;
NumPoints(centerline)
5
# Conformance Item T23
SELECT AsText(PointN(centerline, 1))
FROM road_segments
WHERE fid = 102;
AsText(PointN(centerline, 1))
POINT(0 18)
# Conformance Item T24
SELECT AsText(Centroid(boundary))
FROM named_places
WHERE name = 'Goose Island';
AsText(Centroid(boundary))
POINT(63 15.5)
# Conformance Item T26
SELECT Area(boundary)
FROM named_places
WHERE name = 'Goose Island';
Area(boundary)
40
# Conformance Item T27
SELECT AsText(ExteriorRing(shore))
FROM lakes
WHERE name = 'Blue Lake';
AsText(ExteriorRing(shore))
LINESTRING(52 18,66 23,73 9,48 6,52 18)
# Conformance Item T28
SELECT NumInteriorRings(shore)
FROM lakes
WHERE name = 'Blue Lake';
NumInteriorRings(shore)
1
# Conformance Item T29
SELECT AsText(InteriorRingN(shore, 1))
FROM lakes
WHERE name = 'Blue Lake';
AsText(InteriorRingN(shore, 1))
LINESTRING(59 18,67 18,67 13,59 13,59 18)
# Conformance Item T30
SELECT NumGeometries(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
NumGeometries(centerlines)
2
# Conformance Item T31
SELECT AsText(GeometryN(centerlines, 2))
FROM divided_routes
WHERE name = 'Route 75';
AsText(GeometryN(centerlines, 2))
LINESTRING(16 0,16 23,16 48)
# Conformance Item T32
SELECT IsClosed(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
IsClosed(centerlines)
0
# Conformance Item T33
SELECT GLength(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
GLength(centerlines)
96
# Conformance Item T34
SELECT AsText(Centroid(shores))
FROM ponds
WHERE fid = 120;
AsText(Centroid(shores))
POINT(25 42)
# Conformance Item T36
SELECT Area(shores)
FROM ponds
WHERE fid = 120;
Area(shores)
8
# Conformance Item T37
SELECT ST_Equals(boundary,
PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
FROM named_places
WHERE name = 'Goose Island';
ST_Equals(boundary,
PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
1
# Conformance Item T38
SELECT ST_Disjoint(centerlines, boundary)
FROM divided_routes, named_places
WHERE divided_routes.name = 'Route 75'
AND named_places.name = 'Ashton';
ST_Disjoint(centerlines, boundary)
1
# Conformance Item T39
SELECT ST_Touches(centerline, shore)
FROM streams, lakes
WHERE streams.name = 'Cam Stream'
AND lakes.name = 'Blue Lake';
ST_Touches(centerline, shore)
1
# Conformance Item T42
SELECT Crosses(road_segments.centerline, divided_routes.centerlines)
FROM road_segments, divided_routes
WHERE road_segments.fid = 102
AND divided_routes.name = 'Route 75';
Crosses(road_segments.centerline, divided_routes.centerlines)
1
# Conformance Item T43
SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines)
FROM road_segments, divided_routes
WHERE road_segments.fid = 102
AND divided_routes.name = 'Route 75';
ST_Intersects(road_segments.centerline, divided_routes.centerlines)
1
# Conformance Item T44
SELECT ST_Contains(forests.boundary, named_places.boundary)
FROM forests, named_places
WHERE forests.name = 'Green Forest'
AND named_places.name = 'Ashton';
ST_Contains(forests.boundary, named_places.boundary)
0
# Conformance Item T46
SELECT ST_Distance(position, boundary)
FROM bridges, named_places
WHERE bridges.name = 'Cam Bridge'
AND named_places.name = 'Ashton';
ST_Distance(position, boundary)
12
# Conformance Item T48
SELECT AsText(ST_Difference(named_places.boundary, forests.boundary))
FROM named_places, forests
WHERE named_places.name = 'Ashton'
AND forests.name = 'Green Forest';
AsText(ST_Difference(named_places.boundary, forests.boundary))
POLYGON((56 34,62 48,84 48,84 42,56 34))
SELECT AsText(ST_Union(shore, boundary))
FROM lakes, named_places
WHERE lakes.name = 'Blue Lake'
AND named_places.name = 'Goose Island';
AsText(ST_Union(shore, boundary))
POLYGON((48 6,52 18,66 23,73 9,48 6))
# Conformance Item T50
SELECT AsText(ST_SymDifference(shore, boundary))
FROM lakes, named_places
WHERE lakes.name = 'Blue Lake'
AND named_places.name = 'Ashton';
AsText(ST_SymDifference(shore, boundary))
MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(67 13,59 13,59 18,67 18,67 13)),((56 30,56 34,62 48,84 48,84 30,56 30)))
# Conformance Item T51
SELECT count(*)
FROM buildings, bridges
WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
count(*)
1
DROP DATABASE gis_ogs;
......@@ -17,16 +17,12 @@ SHOW CREATE TABLE t1;
let $1=150;
let $2=150;
--disable_query_log
begin;
while ($1)
{
eval INSERT INTO t1 (g) VALUES (GeomFromText('LineString($1 $1, $2 $2)'));
dec $1;
inc $2;
}
commit;
--enable_query_log
SELECT count(*) FROM t1;
EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
......@@ -39,8 +35,6 @@ CREATE TABLE t2 (
g GEOMETRY NOT NULL
) ENGINE=MyISAM;
--disable_query_log
begin;
let $1=10;
while ($1)
{
......@@ -52,8 +46,6 @@ while ($1)
}
dec $1;
}
commit;
--enable_query_log
ALTER TABLE t2 ADD SPATIAL KEY(g);
SHOW CREATE TABLE t2;
......@@ -63,8 +55,6 @@ EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
SELECT fid, AsText(g) FROM t2 WHERE Within(g,
GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
--disable_query_log
begin;
let $1=10;
while ($1)
{
......@@ -77,8 +67,6 @@ while ($1)
}
dec $1;
}
commit;
--enable_query_log
DROP TABLE t2;
......
......@@ -353,6 +353,9 @@ insert into t1 values ('85984',GeomFromText('MULTIPOLYGON(((-115.006363
36.248666,-115.263639 36.247466,-115.263839 36.252766,-115.261439
36.252666,-115.261439 36.247366,-115.247239 36.247066)))'));
# Expected result is 115.31877315203187, but IA64 returns 115.31877315203188
# due to fused multiply-add instructions.
--replace_result 115.31877315203188 115.31877315203187
select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from
t1 where object_id=85998;
......@@ -535,18 +538,6 @@ create table t1 (g geometry not null);
insert into t1 values(default);
drop table t1;
#
# Bug #27300: create view with geometry functions lost columns types
#
CREATE TABLE t1 (a GEOMETRY);
CREATE VIEW v1 AS SELECT GeomFromwkb(ASBINARY(a)) FROM t1;
CREATE VIEW v2 AS SELECT a FROM t1;
DESCRIBE v1;
DESCRIBE v2;
DROP VIEW v1,v2;
DROP TABLE t1;
#
# Bug#24563: MBROverlaps does not seem to function propertly
# Bug#54888: MBROverlaps missing in 5.1?
......@@ -744,14 +735,574 @@ SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000
SET @a=POLYFROMWKB(@a);
--echo End of 5.1 tests
#
# Bug #57321 crashes and valgrind errors from spatial types
# Bug #50574 5.5.x allows spatial indexes on non-spatial
# columns, causing crashes!
#
--error ER_SPATIAL_MUST_HAVE_GEOM_COL
CREATE TABLE t1(
col0 BINARY NOT NULL,
col2 TIMESTAMP,
SPATIAL INDEX i1 (col0)
) ENGINE=MyISAM;
# Test other ways to add indices
CREATE TABLE t1 (
col0 BINARY NOT NULL,
col2 TIMESTAMP
) ENGINE=MyISAM;
create table t1(a polygon NOT NULL)engine=myisam;
insert into t1 values (geomfromtext("point(0 1)"));
insert into t1 values (geomfromtext("point(1 0)"));
select * from (select polygon(t1.a) as p from t1 order by t1.a) d;
drop table t1;
--error ER_SPATIAL_MUST_HAVE_GEOM_COL
CREATE SPATIAL INDEX idx0 ON t1(col0);
--echo End of 5.1 tests
--error ER_SPATIAL_MUST_HAVE_GEOM_COL
ALTER TABLE t1 ADD SPATIAL INDEX i1 (col0);
CREATE TABLE t2 (
col0 INTEGER NOT NULL,
col1 POINT,
col2 POINT
);
--error ER_WRONG_ARGUMENTS
CREATE SPATIAL INDEX idx0 ON t2 (col1, col2);
--error ER_WRONG_ARGUMENTS
CREATE TABLE t3 (
col0 INTEGER NOT NULL,
col1 POINT,
col2 LINESTRING,
SPATIAL INDEX i1 (col1, col2)
);
# cleanup
DROP TABLE t1;
DROP TABLE t2;
# Conformance tests
#
# C.3.3 Geometry types and functions
#
--disable_warnings
DROP DATABASE IF EXISTS gis_ogs;
--enable_warnings
CREATE DATABASE gis_ogs;
USE gis_ogs;
--echo #
--echo # C.3.3.1 Geometry types and functions schema construction
--echo #
# TODO: WL#2377
#CREATE TABLE spatial_ref_sys (
#srid INTEGER NOT NULL PRIMARY KEY,
#auth_name CHARACTER VARYING,
#auth_srid INTEGER,
#srtext CHARACTER VARYING(2048));
CREATE TABLE lakes (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
shore POLYGON);
CREATE TABLE road_segments (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
aliases CHARACTER VARYING(64),
num_lanes INTEGER,
centerline LINESTRING);
CREATE TABLE divided_routes (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
num_lanes INTEGER,
centerlines MULTILINESTRING);
CREATE TABLE forests (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
boundary MULTIPOLYGON);
CREATE TABLE bridges (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
position POINT);
CREATE TABLE streams (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
centerline LINESTRING);
CREATE TABLE buildings (
fid INTEGER NOT NULL PRIMARY KEY,
address CHARACTER VARYING(64),
position POINT,
footprint POLYGON);
CREATE TABLE ponds (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
type CHARACTER VARYING(64),
shores MULTIPOLYGON);
CREATE TABLE named_places (
fid INTEGER NOT NULL PRIMARY KEY,
name CHARACTER VARYING(64),
boundary POLYGON);
CREATE TABLE map_neatlines (
fid INTEGER NOT NULL PRIMARY KEY,
neatline POLYGON);
--echo #
--echo # C.3.3.2 Geometry types and functions schema data loading
--echo #
# TODO: WL#2377
#-- Spatial Reference System
#INSERT INTO spatial_ref_sys VALUES
#(101, 'POSC', 32214, 'PROJCS["UTM_ZONE_14N",
#GEOGCS["World Geodetic System 72",
#DATUM["WGS_72",
#ELLIPSOID["NWL_10D", 6378135, 298.26]],
#PRIMEM["Greenwich", 0],
#UNIT["Meter", 1.0]],
#PROJECTION["Transverse_Mercator"],
#PARAMETER["False_Easting", 500000.0],
#PARAMETER["False_Northing", 0.0],
#PARAMETER["Central_Meridian", -99.0],
#PARAMETER["Scale_Factor", 0.9996],
#PARAMETER["Latitude_of_origin", 0.0],
#UNIT["Meter", 1.0]]');
--echo # Lakes
INSERT INTO lakes VALUES (
101, 'BLUE LAKE',
PolyFromText(
'POLYGON(
(52 18,66 23,73 9,48 6,52 18),
(59 18,67 18,67 13,59 13,59 18)
)',
101));
--echo # Road Segments
INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2,
LineFromText(
'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4,
LineFromText(
'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2,
LineFromText(
'LINESTRING( 70 38, 72 48 )' ,101));
INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4,
LineFromText(
'LINESTRING( 70 38, 84 42 )' ,101));
INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL,
1,
LineFromText(
'LINESTRING( 28 26, 28 0 )',101));
--echo # DividedRoutes
INSERT INTO divided_routes VALUES(119, 'Route 75', 4,
MLineFromText(
'MULTILINESTRING((10 48,10 21,10 0),
(16 0,16 23,16 48))', 101));
--echo # Forests
INSERT INTO forests VALUES(109, 'Green Forest',
MPolyFromText(
'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),
(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))',
101));
--echo # Bridges
INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText(
'POINT( 44 31 )', 101));
--echo # Streams
INSERT INTO streams VALUES(111, 'Cam Stream',
LineFromText(
'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
INSERT INTO streams VALUES(112, NULL,
LineFromText(
'LINESTRING( 76 0, 78 4, 73 9 )', 101));
--echo # Buildings
INSERT INTO buildings VALUES(113, '123 Main Street',
PointFromText(
'POINT( 52 30 )', 101),
PolyFromText(
'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101));
INSERT INTO buildings VALUES(114, '215 Main Street',
PointFromText(
'POINT( 64 33 )', 101),
PolyFromText(
'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101));
--echo # Ponds
INSERT INTO ponds VALUES(120, NULL, 'Stock Pond',
MPolyFromText(
'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ),
( ( 26 44, 26 40, 28 42, 26 44) ) )', 101));
--echo # Named Places
INSERT INTO named_places VALUES(117, 'Ashton',
PolyFromText(
'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
INSERT INTO named_places VALUES(118, 'Goose Island',
PolyFromText(
'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
--echo # Map Neatlines
INSERT INTO map_neatlines VALUES(115,
PolyFromText(
'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101));
--echo #
--echo # C.3.3.3 Geometry types and functions schema test queries
--echo
# TODO: WL#2377
#--echo # Conformance Item T1
#SELECT f_table_name
#FROM geometry_columns;
#
#--echo # Conformance Item T2
#SELECT f_geometry_column
#FROM geometry_columns
#WHERE f_table_name = 'streams';
#
#--echo # Conformance Item T3
#SELECT coord_dimension
#FROM geometry_columns
#WHERE f_table_name = 'streams';
#
#--echo # Conformance Item T4
#
#SELECT srid
#FROM geometry_columns
#WHERE f_table_name = 'streams';
#
#--echo # Conformance Item T5
#
#SELECT srtext
#FROM SPATIAL_REF_SYS
#WHERE SRID = 101;
#
--echo # Conformance Item T6
# TODO: ST_Dimension() alias
SELECT Dimension(shore)
FROM lakes
WHERE name = 'Blue Lake';
--echo # Conformance Item T7
# TODO: ST_GeometryType() alias
SELECT GeometryType(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
--echo # Conformance Item T8
# TODO: ST_AsText() alias
SELECT AsText(boundary)
FROM named_places
WHERE name = 'Goose Island';
--echo # Conformance Item T9
# TODO: ST_AsBinary(), ST_PolyFromWKB() aliases
SELECT AsText(PolyFromWKB(AsBinary(boundary),101))
FROM named_places
WHERE name = 'Goose Island';
--echo # Conformance Item T10
# TODO: ST_SRID() alias
SELECT SRID(boundary)
FROM named_places
WHERE name = 'Goose Island';
--echo # Conformance Item T11
# TODO: ST_IsEmpty() alias
SELECT IsEmpty(centerline)
FROM road_segments
WHERE name = 'Route 5'
AND aliases = 'Main Street';
# FIXME: get wrong result:0, expected 1.
#--echo # Conformance Item T12
# TODO: ST_IsSimple() alias
#SELECT IsSimple(shore)
#FROM lakes
#WHERE name = 'Blue Lake';
# TODO: WL#2377
#--echo # Conformance Item T13
#SELECT AsText(Boundary((boundary),101)
#FROM named_places
#WHERE name = 'Goose Island';
--echo # Conformance Item T14
# TODO: ST_Envelope( ) alias
# FIXME: we get anticlockwise, GIS suggests clockwise
SELECT AsText(Envelope(boundary))
FROM named_places
WHERE name = 'Goose Island';
--echo # Conformance Item T15
# TODO: ST_X() alias
SELECT X(position)
FROM bridges
WHERE name = 'Cam Bridge';
--echo # Conformance Item T16
# TODO: ST_Y() alias
SELECT Y(position)
FROM bridges
WHERE name = 'Cam Bridge';
--echo # Conformance Item T17
# TODO: ST_StartPoint() alias
SELECT AsText(StartPoint(centerline))
FROM road_segments
WHERE fid = 102;
--echo # Conformance Item T18
# TODO: ST_EndPoint
SELECT AsText(EndPoint(centerline))
FROM road_segments
WHERE fid = 102;
# TODO: WL#2377
#--echo # Conformance Item T19
# TODO: ST_LineFromWKB() alias
#SELECT IsClosed(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary)))
#FROM named_places
#WHERE name = 'Goose Island';
# TODO: WL#2377
#--echo # Conformance Item T20
#SELECT IsRing(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary)))
#FROM named_places
#WHERE name = 'Goose Island';
--echo # Conformance Item T21
# TODO: ST_Length() alias
SELECT GLength(centerline)
FROM road_segments
WHERE fid = 106;
--echo # Conformance Item T22
# TODO: ST_NumPoints() alias
SELECT NumPoints(centerline)
FROM road_segments
WHERE fid = 102;
--echo # Conformance Item T23
# TODO: ST_PointN() alias
SELECT AsText(PointN(centerline, 1))
FROM road_segments
WHERE fid = 102;
--echo # Conformance Item T24
# TODO: ST_Centroid() alias
SELECT AsText(Centroid(boundary))
FROM named_places
WHERE name = 'Goose Island';
# TODO: WL#2377
#--echo # Conformance Item T25
#SELECT Contains(boundary, PointOnSurface(boundary))
#FROM named_places
#WHERE name = 'Goose Island';
--echo # Conformance Item T26
# TODO: ST_Area() alias
SELECT Area(boundary)
FROM named_places
WHERE name = 'Goose Island';
--echo # Conformance Item T27
# TODO: ST_ExteriorRing() alias
SELECT AsText(ExteriorRing(shore))
FROM lakes
WHERE name = 'Blue Lake';
--echo # Conformance Item T28
# TODO: ST_NumInteriorRings() alias
SELECT NumInteriorRings(shore)
FROM lakes
WHERE name = 'Blue Lake';
--echo # Conformance Item T29
# TODO: ST_InteriorRingN() alias
SELECT AsText(InteriorRingN(shore, 1))
FROM lakes
WHERE name = 'Blue Lake';
--echo # Conformance Item T30
# TODO: ST_NumGeometries() alias
SELECT NumGeometries(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
--echo # Conformance Item T31
# TODO: ST_GeometryN() alias
SELECT AsText(GeometryN(centerlines, 2))
FROM divided_routes
WHERE name = 'Route 75';
--echo # Conformance Item T32
# TODO: ST_IsClosed() alias
SELECT IsClosed(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
--echo # Conformance Item T33
# TODO: ST_Length() alias
SELECT GLength(centerlines)
FROM divided_routes
WHERE name = 'Route 75';
--echo # Conformance Item T34
# TODO: ST_Centroid() alias
SELECT AsText(Centroid(shores))
FROM ponds
WHERE fid = 120;
# TODO: WL#2377
#--echo # Conformance Item T35
#SELECT Contains(shores, PointOnSurface(shores))
#FROM ponds
#WHERE fid = 120;
--echo # Conformance Item T36
# TODO: ST_Area() alias
SELECT Area(shores)
FROM ponds
WHERE fid = 120;
--echo # Conformance Item T37
# TODO: ST_PolyFromText() alias
SELECT ST_Equals(boundary,
PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
FROM named_places
WHERE name = 'Goose Island';
--echo # Conformance Item T38
SELECT ST_Disjoint(centerlines, boundary)
FROM divided_routes, named_places
WHERE divided_routes.name = 'Route 75'
AND named_places.name = 'Ashton';
--echo # Conformance Item T39
SELECT ST_Touches(centerline, shore)
FROM streams, lakes
WHERE streams.name = 'Cam Stream'
AND lakes.name = 'Blue Lake';
# FIXME: wrong result: get 0, expected 1
#--echo # Conformance Item T40
#SELECT ST_Within(boundary, footprint)
#FROM named_places, buildings
#WHERE named_places.name = 'Ashton'
#AND buildings.address = '215 Main Street';
# FIXME: wrong result: get 0, expected 1
#--echo # Conformance Item T41
#SELECT ST_Overlaps(forests.boundary, named_places.boundary)
#FROM forests, named_places
#WHERE forests.name = 'Green Forest'
#AND named_places.name = 'Ashton';
--echo # Conformance Item T42
# FIXME: TODO: ST_Crosses() alias
SELECT Crosses(road_segments.centerline, divided_routes.centerlines)
FROM road_segments, divided_routes
WHERE road_segments.fid = 102
AND divided_routes.name = 'Route 75';
--echo # Conformance Item T43
SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines)
FROM road_segments, divided_routes
WHERE road_segments.fid = 102
AND divided_routes.name = 'Route 75';
--echo # Conformance Item T44
SELECT ST_Contains(forests.boundary, named_places.boundary)
FROM forests, named_places
WHERE forests.name = 'Green Forest'
AND named_places.name = 'Ashton';
# TODO: WL#2377
#--echo # Conformance Item T45
#SELECT Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT')
#FROM forests, named_places
#WHERE forests.name = 'Green Forest'
#AND named_places.name = 'Ashton';
--echo # Conformance Item T46
SELECT ST_Distance(position, boundary)
FROM bridges, named_places
WHERE bridges.name = 'Cam Bridge'
AND named_places.name = 'Ashton';
# FIXME: wrong result: NULL, expected 12
#--echo # Conformance Item T47
#SELECT AsText(ST_Intersection(centerline, shore))
#FROM streams, lakes
#WHERE streams.name = 'Cam Stream'
#AND lakes.name = 'Blue Lake';
--echo # Conformance Item T48
SELECT AsText(ST_Difference(named_places.boundary, forests.boundary))
FROM named_places, forests
WHERE named_places.name = 'Ashton'
AND forests.name = 'Green Forest';
#--echo # Conformance Item T49
SELECT AsText(ST_Union(shore, boundary))
FROM lakes, named_places
WHERE lakes.name = 'Blue Lake'
AND named_places.name = 'Goose Island';
--echo # Conformance Item T50
SELECT AsText(ST_SymDifference(shore, boundary))
FROM lakes, named_places
WHERE lakes.name = 'Blue Lake'
AND named_places.name = 'Ashton';
--echo # Conformance Item T51
SELECT count(*)
FROM buildings, bridges
WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
# TODO: WL#2377
#--echo # Conformance Item T52
#SELECT AsText(ConvexHull(shore))
#FROM lakes
#WHERE lakes.name = 'Blue Lake';
DROP DATABASE gis_ogs;
......@@ -78,6 +78,7 @@ SET (SQL_SOURCE
rpl_rli.cc rpl_mi.cc sql_servers.cc
sql_connect.cc scheduler.cc
sql_profile.cc event_parse_data.cc opt_table_elimination.cc
gcalc_slicescan.cc gcalc_tools.cc
multi_range_read.cc
opt_subselect.cc
opt_index_cond_pushdown.cc
......
......@@ -56,6 +56,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
sql_map.h sql_string.h unireg.h \
sql_error.h field.h handler.h mysqld_suffix.h \
sql_profile.h \
gcalc_slicescan.h gcalc_tools.h \
ha_ndbcluster.h ha_ndbcluster_cond.h \
ha_ndbcluster_binlog.h ha_ndbcluster_tables.h \
ha_partition.h rpl_constants.h \
......@@ -101,6 +102,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
sql_join_cache.cc \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
sql_profile.cc \
gcalc_slicescan.cc gcalc_tools.cc \
sql_prepare.cc sql_error.cc sql_locale.cc \
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
procedure.cc sql_test.cc \
......
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#ifdef HAVE_SPATIAL
#include "gcalc_slicescan.h"
#define PH_DATA_OFFSET 8
#define coord_to_float(d) ((double) d)
typedef int (*sc_compare_func)(const void*, const void*);
#define LS_LIST_ITEM Gcalc_dyn_list::Item
#define LS_COMPARE_FUNC_DECL sc_compare_func compare,
#define LS_COMPARE_FUNC_CALL(list_el1, list_el2) (*compare)(list_el1, list_el2)
#define LS_NEXT(A) (A)->next
#define LS_SET_NEXT(A,val) (A)->next= val
#define LS_P_NEXT(A) &(A)->next
#define LS_NAME sort_list
#define LS_SCOPE static
#define LS_STRUCT_NAME sort_list_stack_struct
#include "plistsort.c"
Gcalc_dyn_list::Gcalc_dyn_list(size_t blk_size, size_t sizeof_item):
m_blk_size(blk_size - ALLOC_ROOT_MIN_BLOCK_SIZE),
m_sizeof_item(ALIGN_SIZE(sizeof_item)),
m_points_per_blk((m_blk_size - PH_DATA_OFFSET) / m_sizeof_item),
m_blk_hook(&m_first_blk),
m_free(NULL),
m_keep(NULL)
{}
void Gcalc_dyn_list::format_blk(void* block)
{
Item *pi_end, *cur_pi, *first_pi;
DBUG_ASSERT(m_free == NULL);
first_pi= cur_pi= (Item *)(((char *)block) + PH_DATA_OFFSET);
pi_end= ptr_add(first_pi, m_points_per_blk - 1);
do {
cur_pi= cur_pi->next= ptr_add(cur_pi, 1);
} while (cur_pi<pi_end);
cur_pi->next= m_free;
m_free= first_pi;
}
Gcalc_dyn_list::Item *Gcalc_dyn_list::alloc_new_blk()
{
void *new_block= my_malloc(m_blk_size, MYF(MY_WME));
if (!new_block)
return NULL;
*m_blk_hook= new_block;
m_blk_hook= (void**)new_block;
format_blk(new_block);
return new_item();
}
static void free_blk_list(void *list)
{
void *next_blk;
while (list)
{
next_blk= *((void **)list);
my_free(list, MYF(0));
list= next_blk;
}
}
void Gcalc_dyn_list::cleanup()
{
*m_blk_hook= NULL;
free_blk_list(m_first_blk);
m_first_blk= NULL;
m_blk_hook= &m_first_blk;
m_free= NULL;
}
Gcalc_dyn_list::~Gcalc_dyn_list()
{
cleanup();
}
void Gcalc_dyn_list::reset()
{
*m_blk_hook= NULL;
if (m_first_blk)
{
free_blk_list(*((void **)m_first_blk));
m_blk_hook= (void**)m_first_blk;
m_free= NULL;
format_blk(m_first_blk);
}
}
static inline void trim_node(Gcalc_heap::Info *node, Gcalc_heap::Info *prev_node)
{
if (!node)
return;
DBUG_ASSERT((node->left == prev_node) || (node->right == prev_node));
if (node->left == prev_node)
node->left= node->right;
node->right= NULL;
}
static double find_first_different(const Gcalc_heap::Info *p)
{
if (p->left && (p->left->y != p->y))
return p->left->y;
if (p->right && (p->right->y != p->y))
return p->right->y;
if (p->left && p->left->left && (p->left->left->y != p->y))
return p->left->left->y;
if (p->right && p->right->right && (p->right->right->y != p->y))
return p->right->right->y;
return p->y;
}
static int compare_point_info(const void *e0, const void *e1)
{
const Gcalc_heap::Info *i0= (const Gcalc_heap::Info *)e0;
const Gcalc_heap::Info *i1= (const Gcalc_heap::Info *)e1;
if (i0->y != i1->y)
return i0->y > i1->y;
return find_first_different(i0) > find_first_different(i1);
}
void Gcalc_heap::prepare_operation()
{
DBUG_ASSERT(m_hook);
*m_hook= NULL;
m_first= sort_list(compare_point_info, m_first, m_n_points);
m_hook= NULL; /* just to check it's not called twice */
/* TODO - move this to the 'normal_scan' loop */
for (Info *cur= get_first(); cur; cur= cur->get_next())
{
trim_node(cur->left, cur);
trim_node(cur->right, cur);
}
}
void Gcalc_heap::reset()
{
if (!m_hook)
{
m_hook= &m_first;
for (; *m_hook; m_hook= &(*m_hook)->next)
{}
}
*m_hook= m_free;
m_free= m_first;
m_hook= &m_first;
m_n_points= 0;
}
int Gcalc_shape_transporter::int_single_point(gcalc_shape_info Info,
double x, double y)
{
Gcalc_heap::Info *point= m_heap->new_point_info(x, y, Info);
if (!point)
return 1;
point->left= point->right= 0;
return 0;
}
int Gcalc_shape_transporter::int_add_point(gcalc_shape_info Info,
double x, double y)
{
Gcalc_heap::Info *point;
if (!(point= m_heap->new_point_info(x, y, Info)))
return 1;
if (m_first)
{
m_prev->left= point;
point->right= m_prev;
}
else
m_first= point;
m_prev= point;
return 0;
}
void Gcalc_shape_transporter::int_complete()
{
DBUG_ASSERT(m_shape_started == 1 || m_shape_started == 3);
if (!m_first)
return;
/* simple point */
if (m_first == m_prev)
{
m_first->right= m_first->left= NULL;
return;
}
/* line */
if (m_shape_started == 1)
{
m_first->right= NULL;
m_prev->left= m_prev->right;
m_prev->right= NULL;
return;
}
/* polygon */
m_first->right= m_prev;
m_prev->left= m_first;
}
inline int GET_DX_DY(double *dxdy,
const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1)
{
double dy= p1->y - p0->y;
*dxdy= p1->x - p0->x;
return (dy == 0.0) ||
(*dxdy/= dy)>DBL_MAX ||
(*dxdy)<-DBL_MAX;
}
Gcalc_scan_iterator::Gcalc_scan_iterator(size_t blk_size) :
Gcalc_dyn_list(blk_size,
(sizeof(point) > sizeof(intersection)) ?
sizeof(point) : sizeof(intersection)),
m_slice0(NULL), m_slice1(NULL)
{}
Gcalc_scan_iterator::point
*Gcalc_scan_iterator::new_slice(Gcalc_scan_iterator::point *example)
{
point *result= NULL;
Gcalc_dyn_list::Item **result_hook= (Gcalc_dyn_list::Item **)&result;
while (example)
{
*result_hook= new_slice_point();
result_hook= &(*result_hook)->next;
example= example->get_next();
}
*result_hook= NULL;
return result;
}
void Gcalc_scan_iterator::init(Gcalc_heap *points)
{
DBUG_ASSERT(points->ready());
DBUG_ASSERT(!m_slice0 && !m_slice1);
if (!(m_cur_pi= points->get_first()))
return;
m_cur_thread= 0;
m_sav_slice= NULL;
m_intersections= NULL;
m_cur_intersection= NULL;
m_y1= m_cur_pi->y;
m_next_is_top_point= true;
m_bottom_points_count= 0;
}
void Gcalc_scan_iterator::reset()
{
if (m_slice0)
free_list(m_slice0);
if (m_slice1)
free_list(m_slice1);
m_slice0= m_slice1= NULL;
Gcalc_dyn_list::reset();
}
static bool slice_first_equal_x(const Gcalc_scan_iterator::point *p0,
const Gcalc_scan_iterator::point *p1)
{
if (p0->horiz_dir == p1->horiz_dir)
return p0->dx_dy <= p1->dx_dy;
if (p0->horiz_dir)
return p0->dx_dy < 0;
return p1->dx_dy > 0; /* p1->horiz_dir case */
}
static inline bool slice_first(const Gcalc_scan_iterator::point *p0,
const Gcalc_scan_iterator::point *p1)
{
if (p0->x != p1->x)
return p0->x < p1->x;
return slice_first_equal_x(p0, p1);
}
int Gcalc_scan_iterator::insert_top_point()
{
point *sp= m_slice1;
Gcalc_dyn_list::Item **prev_hook= (Gcalc_dyn_list::Item **)&m_slice1;
point *sp1;
point *sp0= new_slice_point();
if (!sp0)
return 1;
sp0->pi= m_cur_pi;
sp0->next_pi= m_cur_pi->left;
sp0->thread= m_cur_thread++;
sp0->x= coord_to_float(m_cur_pi->x);
if (m_cur_pi->left)
{
sp0->horiz_dir= GET_DX_DY(&sp0->dx_dy, m_cur_pi, m_cur_pi->left);
m_event1= scev_thread;
/*Now just to increase the size of m_slice0 to be same*/
if (!(sp1= new_slice_point()))
return 1;
sp1->next= m_slice0;
m_slice0= sp1;
}
else
{
m_event1= scev_single_point;
sp0->horiz_dir= 0;
sp0->dx_dy= 0.0;
}
/* First we need to find the place to insert.
Binary search could probably make things faster here,
but structures used aren't suitable, and the
scan is usually not really long */
for (; sp && slice_first(sp, sp0);
prev_hook= &sp->next, sp=sp->get_next())
{}
if (m_cur_pi->right)
{
m_event1= scev_two_threads;
/*We have two threads so should decide which one will be first*/
sp1= new_slice_point();
if (!sp1)
return 1;
sp1->pi= m_cur_pi;
sp1->next_pi= m_cur_pi->right;
sp1->thread= m_cur_thread++;
sp1->x= sp0->x;
sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->right);
if (slice_first_equal_x(sp1, sp0))
{
point *tmp= sp0;
sp0= sp1;
sp1= tmp;
}
sp1->next= sp;
sp0->next= sp1;
/*Now just to increase the size of m_slice0 to be same*/
if (!(sp1= new_slice_point()))
return 1;
sp1->next= m_slice0;
m_slice0= sp1;
}
else
sp0->next= sp;
*prev_hook= sp0;
m_event_position1= sp0;
return 0;
}
enum
{
intersection_normal= 1,
intersection_forced= 2
};
static int intersection_found(const Gcalc_scan_iterator::point *sp0,
const Gcalc_scan_iterator::point *sp1,
unsigned int bottom_points_count)
{
if (sp1->x < sp0->x)
return intersection_normal;
if (sp1->is_bottom() && !sp0->is_bottom() &&
(bottom_points_count > 1))
return intersection_forced;
return 0;
}
int Gcalc_scan_iterator::normal_scan()
{
if (m_next_is_top_point)
if (insert_top_point())
return 1;
point *tmp= m_slice0;
m_slice0= m_slice1;
m_slice1= tmp;
m_event0= m_event1;
m_event_position0= m_event_position1;
m_y0= m_y1;
if (!(m_cur_pi= m_cur_pi->get_next()))
{
free_list(m_slice1);
m_slice1= NULL;
return 0;
}
Gcalc_heap::Info *cur_pi= m_cur_pi;
m_y1= coord_to_float(cur_pi->y);
m_h= m_y1 - m_y0;
point *sp0= m_slice0;
point *sp1= m_slice1;
point *prev_sp1= NULL;
m_bottom_points_count= 0;
m_next_is_top_point= true;
bool intersections_found= false;
for (; sp0; sp0= sp0->get_next())
{
if (sp0->next_pi == cur_pi) /* End of the segment */
{
sp1->x= coord_to_float(cur_pi->x);
sp1->pi= cur_pi;
sp1->thread= sp0->thread;
sp1->next_pi= cur_pi->left;
if (cur_pi->left)
sp1->horiz_dir= GET_DX_DY(&sp1->dx_dy, m_cur_pi, m_cur_pi->left);
m_next_is_top_point= false;
if (sp1->is_bottom())
{
++m_bottom_points_count;
if (m_bottom_points_count == 1)
{
m_event1= scev_end;
m_event_position1= sp1;
}
else
m_event1= scev_two_ends;
}
else
{
m_event1= scev_point;
m_event_position1= sp1;
}
}
else if (!sp0->is_bottom())
{
/* Cut current string with the height of the new point*/
sp1->copy_core(sp0);
sp1->x= sp1->horiz_dir ? sp0->x :
(coord_to_float(sp1->pi->x) +
(m_y1-coord_to_float(sp1->pi->y)) * sp1->dx_dy);
}
else /* Skip the bottom point in slice0 */
continue;
intersections_found= intersections_found ||
(prev_sp1 && intersection_found(prev_sp1, sp1, m_bottom_points_count));
prev_sp1= sp1;
sp1= sp1->get_next();
}
if (sp1)
{
if (prev_sp1)
prev_sp1->next= NULL;
else
m_slice1= NULL;
free_list(sp1);
}
if (intersections_found)
return handle_intersections();
return 0;
}
int Gcalc_scan_iterator::add_intersection(const point *a, const point *b,
int isc_kind, Gcalc_dyn_list::Item ***p_hook)
{
intersection *isc= new_intersection();
if (!isc)
return 1;
m_n_intersections++;
**p_hook= isc;
*p_hook= &isc->next;
isc->thread_a= a->thread;
isc->thread_b= b->thread;
if (isc_kind == intersection_forced)
{
isc->y= m_y1;
isc->x= a->x;
return 0;
}
/* intersection_normal */
const point *a0= a->precursor;
const point *b0= b->precursor;
if (!a0->horiz_dir && !b0->horiz_dir)
{
double dk= a0->dx_dy - b0->dx_dy;
double dy= (b0->x - a0->x)/dk;
isc->y= m_y0 + dy;
isc->x= a0->x + dy*a0->dx_dy;
return 0;
}
isc->y= m_y1;
isc->x= a0->horiz_dir ? b->x : a->x;
return 0;
}
int Gcalc_scan_iterator::find_intersections()
{
point *sp1= m_slice1;
Gcalc_dyn_list::Item **hook;
m_n_intersections= 0;
{
/* Set links between slicepoints */
point *sp0= m_slice0;
for (; sp1; sp0= sp0->get_next(),sp1= sp1->get_next())
{
while (sp0->is_bottom())
sp0= sp0->get_next();
DBUG_ASSERT(sp0->thread == sp1->thread);
sp1->precursor= sp0;
}
}
hook= (Gcalc_dyn_list::Item **)&m_intersections;
bool intersections_found;
point *last_possible_isc= NULL;
do
{
sp1= m_slice1;
point **pprev_s1= &m_slice1;
intersections_found= false;
unsigned int bottom_points_count= sp1->is_bottom() ? 1:0;
sp1= m_slice1->get_next();
int isc_kind;
point *cur_possible_isc= NULL;
for (; sp1 != last_possible_isc;
pprev_s1= (point **)(&(*pprev_s1)->next), sp1= sp1->get_next())
{
if (sp1->is_bottom())
++bottom_points_count;
if (!(isc_kind=intersection_found(*pprev_s1, sp1, bottom_points_count)))
continue;
point *prev_s1= *pprev_s1;
intersections_found= true;
if (add_intersection(prev_s1, sp1, isc_kind, &hook))
return 1;
*pprev_s1= sp1;
prev_s1->next= sp1->next;
sp1->next= prev_s1;
sp1= prev_s1;
cur_possible_isc= sp1;
}
last_possible_isc= cur_possible_isc;
} while (intersections_found);
*hook= NULL;
return 0;
}
static int compare_intersections(const void *e0, const void *e1)
{
Gcalc_scan_iterator::intersection *i0= (Gcalc_scan_iterator::intersection *)e0;
Gcalc_scan_iterator::intersection *i1= (Gcalc_scan_iterator::intersection *)e1;
return i0->y > i1->y;
}
inline void Gcalc_scan_iterator::sort_intersections()
{
m_intersections= (intersection *)sort_list(compare_intersections,
m_intersections,m_n_intersections);
}
int Gcalc_scan_iterator::handle_intersections()
{
DBUG_ASSERT(m_slice1->next);
if (find_intersections())
return 1;
sort_intersections();
m_sav_slice= m_slice1;
m_sav_y= m_y1;
m_slice1= new_slice(m_sav_slice);
m_cur_intersection= m_intersections;
m_pre_intersection_hook= NULL;
return intersection_scan();
}
void Gcalc_scan_iterator::pop_suitable_intersection()
{
intersection *prev_i= m_cur_intersection;
intersection *cur_i= prev_i->get_next();
for (; cur_i; prev_i= cur_i, cur_i= cur_i->get_next())
{
point *prev_p= m_slice0;
point *sp= prev_p->get_next();
for (; sp; prev_p= sp, sp= sp->get_next())
{
if ((prev_p->thread == cur_i->thread_a) &&
(sp->thread == cur_i->thread_b))
{
/* Move cur_t on the top of the list */
if (prev_i == m_cur_intersection)
{
m_cur_intersection->next= cur_i->next;
cur_i->next= m_cur_intersection;
m_cur_intersection= cur_i;
}
else
{
Gcalc_dyn_list::Item *tmp= m_cur_intersection->next;
m_cur_intersection->next= cur_i->next;
prev_i->next= m_cur_intersection;
m_cur_intersection= cur_i;
cur_i->next= tmp;
}
return;
}
}
}
DBUG_ASSERT(0);
}
int Gcalc_scan_iterator::intersection_scan()
{
if (m_pre_intersection_hook) /*Skip the first point*/
{
point *next= (*m_pre_intersection_hook)->get_next();
(*m_pre_intersection_hook)->next= next->next;
next->next= *m_pre_intersection_hook;
*m_pre_intersection_hook= next;
m_event0= scev_intersection;
m_event_position0= next;
point *tmp= m_slice1;
m_slice1= m_slice0;
m_slice0= tmp;
m_y0= m_y1;
m_cur_intersection= m_cur_intersection->get_next();
if (!m_cur_intersection)
{
m_h= m_sav_y - m_y1;
m_y1= m_sav_y;
free_list(m_slice1);
m_slice1= m_sav_slice;
free_list(m_intersections);
return 0;
}
}
m_y1= m_cur_intersection->y;
m_h= m_y1 - m_y0;
point *sp0;
point **psp1;
redo_loop:
sp0= m_slice0;
psp1= &m_slice1;
for (; sp0; sp0= sp0->get_next())
{
point *sp1= *psp1;
if (sp0->thread == m_cur_intersection->thread_a)
{
point *next_s0= sp0;
/* Skip Bottom points */
do
next_s0= next_s0->get_next();
while(next_s0->is_bottom()); /* We always find nonbottom point here*/
/* If the next point's thread isn't the thread of intersection,
we try to find suitable intersection */
if (next_s0->thread != m_cur_intersection->thread_b)
{
/* It's really rare case - sometimes happen when
there's two intersections with the same Y
Move suitable one to the beginning of the list
*/
pop_suitable_intersection();
goto redo_loop;
}
m_pre_intersection_hook= psp1;
sp1->copy_core(sp0);
sp1->x= m_cur_intersection->x;
sp0= next_s0;
sp1= sp1->get_next();
sp1->copy_core(sp0);
sp1->x= m_cur_intersection->x;
psp1= (point **)&sp1->next;
continue;
}
if (!sp0->is_bottom())
{
sp1->copy_core(sp0);
sp1->x= sp1->horiz_dir ? sp0->x :
(coord_to_float(sp1->pi->x) +
(m_y1-coord_to_float(sp1->pi->y)) * sp1->dx_dy);
}
else
/* Skip bottom point */
continue;
psp1= (point **)&sp1->next;
}
if (*psp1)
{
free_list(*psp1);
*psp1= NULL;
}
return 0;
}
#endif /* HAVE_SPATIAL */
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef GCALC_SLICESCAN_INCLUDED
#define GCALC_SLICESCAN_INCLUDED
/*
Gcalc_dyn_list class designed to manage long lists of same-size objects
with the possible efficiency.
It allocates fixed-size blocks of memory (blk_size specified at the time
of creation). When new object is added to the list, it occupies part of
this block until it's full. Then the new block is allocated.
Freed objects are chained to the m_free list, and if it's not empty, the
newly added object is taken from this list instead the block.
*/
class Gcalc_dyn_list
{
public:
class Item
{
public:
Item *next;
};
Gcalc_dyn_list(size_t blk_size, size_t sizeof_item);
~Gcalc_dyn_list();
Item *new_item()
{
Item *result;
if (m_free)
{
result= m_free;
m_free= m_free->next;
}
else
result= alloc_new_blk();
return result;
}
inline void free_item(Item *item)
{
item->next= m_free;
m_free= item;
}
inline void free_list(Item *list, Item **hook)
{
*hook= m_free;
m_free= list;
}
void free_list(Item *list)
{
Item **hook= &list;
while (*hook)
hook= &(*hook)->next;
free_list(list, hook);
}
void reset();
void cleanup();
protected:
size_t m_blk_size;
size_t m_sizeof_item;
unsigned int m_points_per_blk;
void *m_first_blk;
void **m_blk_hook;
Item *m_free;
Item *m_keep;
Item *alloc_new_blk();
void format_blk(void* block);
inline Item *ptr_add(Item *ptr, int n_items)
{
return (Item *)(((char*)ptr) + n_items * m_sizeof_item);
}
};
typedef uint gcalc_shape_info;
/*
Gcalc_heap represents the 'dynamic list' of Info objects, that
contain information about vertexes of all the shapes that take
part in some spatial calculation. Can become quite long.
After filled, the list is usually sorted and then walked through
in the slicescan algorithm.
The Gcalc_heap and the algorithm can only operate with two
kinds of shapes - polygon and polyline. So all the spatial
objects should be represented as sets of these two.
*/
class Gcalc_heap : public Gcalc_dyn_list
{
public:
class Info : public Gcalc_dyn_list::Item
{
public:
gcalc_shape_info shape;
Info *left;
Info *right;
double x,y;
inline bool is_bottom() const { return !left; }
inline Info *get_next() { return (Info *)next; }
inline const Info *get_next() const { return (const Info *)next; }
};
Gcalc_heap(size_t blk_size=8192) :
Gcalc_dyn_list(blk_size, sizeof(Info)), m_hook(&m_first), m_n_points(0) {}
Info *new_point_info(double x, double y, gcalc_shape_info shape)
{
Info *result= (Info *)new_item();
if (!result)
return NULL;
*m_hook= result;
m_hook= &result->next;
m_n_points++;
result->x= x;
result->y= y;
result->shape= shape;
return result;
}
void prepare_operation();
inline bool ready() const { return m_hook == NULL; }
Info *get_first() { return (Info *)m_first; }
const Info *get_first() const { return (const Info *)m_first; }
Gcalc_dyn_list::Item **get_last_hook() { return m_hook; }
void reset();
private:
Gcalc_dyn_list::Item *m_first;
Gcalc_dyn_list::Item **m_hook;
int m_n_points;
};
/*
the spatial object has to be represented as a set of
simple polygones and polylines to be sent to the slicescan.
Gcalc_shape_transporter class and his descendants are used to
simplify storing the information about the shape into necessary structures.
This base class only fills the Gcalc_heap with the information about
shapes and vertices.
Normally the Gcalc_shape_transporter family object is sent as a parameter
to the 'get_shapes' method of an 'spatial' object so it can pass
the spatial information about itself. The virtual methods are
treating this data in a way the caller needs.
*/
class Gcalc_shape_transporter
{
private:
Gcalc_heap::Info *m_first;
Gcalc_heap::Info *m_prev;
int m_shape_started;
void int_complete();
protected:
Gcalc_heap *m_heap;
int int_single_point(gcalc_shape_info Info, double x, double y);
int int_add_point(gcalc_shape_info Info, double x, double y);
void int_start_line()
{
DBUG_ASSERT(!m_shape_started);
m_shape_started= 1;
m_first= m_prev= NULL;
}
void int_complete_line()
{
DBUG_ASSERT(m_shape_started== 1);
int_complete();
m_shape_started= 0;
}
void int_start_ring()
{
DBUG_ASSERT(m_shape_started== 2);
m_shape_started= 3;
m_first= m_prev= NULL;
}
void int_complete_ring()
{
DBUG_ASSERT(m_shape_started== 3);
int_complete();
m_shape_started= 2;
}
void int_start_poly()
{
DBUG_ASSERT(!m_shape_started);
m_shape_started= 2;
}
void int_complete_poly()
{
DBUG_ASSERT(m_shape_started== 2);
m_shape_started= 0;
}
bool line_started() { return m_shape_started == 1; };
public:
Gcalc_shape_transporter(Gcalc_heap *heap) :
m_shape_started(0), m_heap(heap) {}
virtual int single_point(double x, double y)=0;
virtual int start_line()=0;
virtual int complete_line()=0;
virtual int start_poly()=0;
virtual int complete_poly()=0;
virtual int start_ring()=0;
virtual int complete_ring()=0;
virtual int add_point(double x, double y)=0;
virtual int start_collection(int n_objects) { return 0; }
int start_simple_poly()
{
return start_poly() || start_ring();
}
int complete_simple_poly()
{
return complete_ring() || complete_poly();
}
virtual ~Gcalc_shape_transporter() {}
};
enum Gcalc_scan_events
{
scev_point= 1, /* Just a new point in thread */
scev_thread= 2, /* Start of the new thread */
scev_two_threads= 4, /* A couple of new threads started */
scev_intersection= 8, /* Intersection happened */
scev_end= 16, /* Single thread finished */
scev_two_ends= 32, /* A couple of threads finished */
scev_single_point= 64 /* Got single point */
};
typedef int sc_thread_id;
/*
Gcalc_scan_iterator incapsulates the slisescan algorithm.
It takes filled Gcalc_heap as an datasource. Then can be
iterated trought the vertexes and intersection points with
the step() method. After the 'step()' one usually observes
the current 'slice' to do the necessary calculations, like
looking for intersections, calculating the area, whatever.
*/
class Gcalc_scan_iterator : public Gcalc_dyn_list
{
public:
class point : public Gcalc_dyn_list::Item
{
public:
double x;
double dx_dy;
int horiz_dir;
Gcalc_heap::Info *pi;
Gcalc_heap::Info *next_pi;
sc_thread_id thread;
const point *precursor; /* used as a temporary field */
inline const point *c_get_next() const
{ return (const point *)next; }
inline bool is_bottom() const { return pi->is_bottom(); }
gcalc_shape_info get_shape() const { return pi->shape; }
inline point *get_next() { return (point *)next; }
inline const point *get_next() const { return (const point *)next; }
/* copies all but 'next' 'x' and 'precursor' */
void copy_core(const point *from)
{
dx_dy= from->dx_dy;
horiz_dir= from->horiz_dir;
pi= from->pi;
next_pi= from->next_pi;
thread= from->thread;
}
#ifndef DBUG_OFF
void dbug_print();
#endif /*DBUG_OFF*/
};
class intersection : public Gcalc_dyn_list::Item
{
public:
sc_thread_id thread_a;
sc_thread_id thread_b;
double x;
double y;
inline intersection *get_next() { return (intersection *)next; }
};
public:
Gcalc_scan_iterator(size_t blk_size= 8192);
void init(Gcalc_heap *points); /* Iterator can be reused */
void reset();
int step()
{
DBUG_ASSERT(more_points());
return m_cur_intersection ? intersection_scan() : normal_scan();
}
inline Gcalc_heap::Info *more_points() { return m_cur_pi; }
inline bool more_trapezoids()
{ return m_cur_pi && m_cur_pi->next; }
inline Gcalc_scan_events get_event() const { return m_event0; }
inline const point *get_event_position() const
{ return m_event_position0; }
inline const point *get_b_slice() const { return m_slice0; }
inline const point *get_t_slice() const { return m_slice1; }
inline double get_h() const { return m_h; }
inline double get_y() const { return m_y0; }
private:
Gcalc_heap::Info *m_cur_pi;
point *m_slice0;
point *m_slice1;
point *m_sav_slice;
intersection *m_intersections;
int m_n_intersections;
intersection *m_cur_intersection;
point **m_pre_intersection_hook;
double m_h;
double m_y0;
double m_y1;
double m_sav_y;
bool m_next_is_top_point;
unsigned int m_bottom_points_count;
sc_thread_id m_cur_thread;
Gcalc_scan_events m_event0, m_event1;
point *m_event_position0;
point *m_event_position1;
int normal_scan();
int intersection_scan();
void sort_intersections();
int handle_intersections();
int insert_top_point();
int add_intersection(const point *a, const point *b,
int isc_kind, Gcalc_dyn_list::Item ***p_hook);
int find_intersections();
void pop_suitable_intersection();
intersection *new_intersection()
{
return (intersection *)new_item();
}
point *new_slice_point()
{
return (point *)new_item();
}
point *new_slice(point *example);
};
/*
Gcalc_trapezoid_iterator simplifies the calculations on
the current slice of the Gcalc_scan_iterator.
One can walk through the trapezoids formed between
previous and current slices.
*/
class Gcalc_trapezoid_iterator
{
protected:
const Gcalc_scan_iterator::point *sp0;
const Gcalc_scan_iterator::point *sp1;
public:
Gcalc_trapezoid_iterator(const Gcalc_scan_iterator *scan_i) :
sp0(scan_i->get_b_slice()),
sp1(scan_i->get_t_slice())
{}
inline bool more() const { return sp1 && sp1->next; }
const Gcalc_scan_iterator::point *lt() const { return sp1; }
const Gcalc_scan_iterator::point *lb() const { return sp0; }
const Gcalc_scan_iterator::point *rb() const
{
const Gcalc_scan_iterator::point *result= sp0;
while ((result= result->c_get_next())->is_bottom())
{}
return result;
}
const Gcalc_scan_iterator::point *rt() const
{ return sp1->c_get_next(); }
void operator++()
{
sp0= rb();
sp1= rt();
}
};
/*
Gcalc_point_iterator simplifies the calculations on
the current slice of the Gcalc_scan_iterator.
One can walk through the points on the current slice.
*/
class Gcalc_point_iterator
{
protected:
const Gcalc_scan_iterator::point *sp;
public:
Gcalc_point_iterator(const Gcalc_scan_iterator *scan_i):
sp(scan_i->get_b_slice())
{}
inline bool more() const { return sp != NULL; }
inline void operator++() { sp= sp->c_get_next(); }
inline const Gcalc_scan_iterator::point *point() const { return sp; }
inline const Gcalc_heap::Info *get_pi() const { return sp->pi; }
inline gcalc_shape_info get_shape() const { return sp->get_shape(); }
inline double get_x() const { return sp->x; }
};
#endif /*GCALC_SLICESCAN_INCLUDED*/
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#ifdef HAVE_SPATIAL
#include "gcalc_tools.h"
#include "spatial.h"
#define float_to_coord(d) ((double) d)
/*
Adds new shape to the relation.
After that it can be used as an argument of an operation.
*/
gcalc_shape_info Gcalc_function::add_new_shape(uint32 shape_id,
shape_type shape_kind)
{
shapes_buffer.q_append((uint32) shape_kind);
return n_shapes++;
}
/*
Adds new operation to the constructed relation.
To construct the complex relation one has to specify operations
in prefix style.
*/
void Gcalc_function::add_operation(op_type operation, uint32 n_operands)
{
uint32 op_code= (uint32 ) operation + n_operands;
function_buffer.q_append(op_code);
}
/*
Sometimes the number of arguments is unknown at the moment the operation
is added. That allows to specify it later.
*/
void Gcalc_function::add_operands_to_op(uint32 operation_pos, uint32 n_operands)
{
uint32 op_code= uint4korr(function_buffer.ptr() + operation_pos) + n_operands;
function_buffer.write_at_position(operation_pos, op_code);
}
/*
Just like the add_operation() but the result will be the inverted
value of an operation.
*/
void Gcalc_function::add_not_operation(op_type operation, uint32 n_operands)
{
uint32 op_code= ((uint32) op_not | (uint32 ) operation) + n_operands;
function_buffer.q_append(op_code);
}
int Gcalc_function::single_shape_op(shape_type shape_kind, gcalc_shape_info *si)
{
if (reserve_shape_buffer(1) || reserve_op_buffer(1))
return 1;
*si= add_new_shape(0, shape_kind);
add_operation(op_shape, *si);
return 0;
}
/*
Specify how many arguments we're going to have.
*/
int Gcalc_function::reserve_shape_buffer(uint n_shapes)
{
return shapes_buffer.reserve(n_shapes * 4, 512);
}
/*
Specify how many operations we're going to have.
*/
int Gcalc_function::reserve_op_buffer(uint n_ops)
{
return function_buffer.reserve(n_ops * 4, 512);
}
int Gcalc_function::alloc_states()
{
if (function_buffer.reserve((n_shapes+1) * sizeof(int)))
return 1;
i_states= (int *) (function_buffer.ptr() + ALIGN_SIZE(function_buffer.length()));
return 0;
}
int Gcalc_function::count_internal()
{
int c_op= uint4korr(cur_func);
op_type next_func= (op_type) (c_op & op_any);
int mask= (c_op & op_not) ? 1:0;
int n_ops= c_op & ~op_any;
int result;
cur_func+= 4;
if (next_func == op_shape)
return i_states[c_op & ~(op_any | op_not)] ^ mask;
result= count_internal();
while (--n_ops)
{
int next_res= count_internal();
switch (next_func)
{
case op_union:
result= result | next_res;
break;
case op_intersection:
result= result & next_res;
break;
case op_symdifference:
result= result ^ next_res;
break;
case op_difference:
result= result & !next_res;
break;
case op_backdifference:
result= !result & next_res;
break;
default:
DBUG_ASSERT(FALSE);
};
}
return result ^ mask;
}
/*
Clear the state of the object.
*/
void Gcalc_function::reset()
{
n_shapes= 0;
shapes_buffer.length(0);
function_buffer.length(0);
}
int Gcalc_function::find_function(Gcalc_scan_iterator &scan_it)
{
while (scan_it.more_points())
{
if (scan_it.step())
return -1;
Gcalc_scan_events ev= scan_it.get_event();
const Gcalc_scan_iterator::point *evpos= scan_it.get_event_position();
if (ev & (scev_point | scev_end | scev_two_ends))
continue;
clear_state();
for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit)
{
gcalc_shape_info si= pit.point()->get_shape();
if ((get_shape_kind(si) == Gcalc_function::shape_polygon))
invert_state(si);
}
invert_state(evpos->get_shape());
if (ev == scev_intersection)
{
const Gcalc_scan_iterator::point *evnext= evpos->c_get_next();
if ((get_shape_kind(evpos->get_shape()) !=
Gcalc_function::shape_polygon) ||
(get_shape_kind(evnext->get_shape()) !=
Gcalc_function::shape_polygon))
invert_state(evnext->get_shape());
}
if (count())
return 1;
}
return 0;
}
int Gcalc_operation_transporter::single_point(double x, double y)
{
gcalc_shape_info si;
return m_fn->single_shape_op(Gcalc_function::shape_point, &si) ||
int_single_point(si, x, y);
}
int Gcalc_operation_transporter::start_line()
{
int_start_line();
return m_fn->single_shape_op(Gcalc_function::shape_line, &m_si);
}
int Gcalc_operation_transporter::complete_line()
{
int_complete_line();
return 0;
}
int Gcalc_operation_transporter::start_poly()
{
int_start_poly();
return m_fn->single_shape_op(Gcalc_function::shape_polygon, &m_si);
}
int Gcalc_operation_transporter::complete_poly()
{
int_complete_poly();
return 0;
}
int Gcalc_operation_transporter::start_ring()
{
int_start_ring();
return 0;
}
int Gcalc_operation_transporter::complete_ring()
{
int_complete_ring();
return 0;
}
int Gcalc_operation_transporter::add_point(double x, double y)
{
return int_add_point(m_si, x, y);
}
int Gcalc_operation_transporter::start_collection(int n_objects)
{
if (m_fn->reserve_shape_buffer(n_objects) || m_fn->reserve_op_buffer(1))
return 1;
m_fn->add_operation(Gcalc_function::op_union, n_objects);
return 0;
}
int Gcalc_result_receiver::start_shape(Gcalc_function::shape_type shape)
{
if (buffer.reserve(4*2, 512))
return 1;
cur_shape= shape;
shape_pos= buffer.length();
buffer.length(shape_pos + ((shape == Gcalc_function::shape_point) ? 4:8));
n_points= 0;
shape_area= 0.0;
return 0;
}
int Gcalc_result_receiver::add_point(double x, double y)
{
if (n_points && x == prev_x && y == prev_y)
return 0;
if (!n_points++)
{
prev_x= first_x= x;
prev_y= first_y= y;
return 0;
}
shape_area+= prev_x*y - prev_y*x;
if (buffer.reserve(8*2, 512))
return 1;
buffer.q_append(prev_x);
buffer.q_append(prev_y);
prev_x= x;
prev_y= y;
return 0;
}
int Gcalc_result_receiver::complete_shape()
{
if (n_points == 0)
{
buffer.length(shape_pos);
return 0;
}
if (n_points == 1)
{
if (cur_shape != Gcalc_function::shape_point)
{
cur_shape= Gcalc_function::shape_point;
buffer.length(buffer.length()-4);
}
}
else
{
DBUG_ASSERT(cur_shape != Gcalc_function::shape_point);
if (cur_shape == Gcalc_function::shape_hole)
{
shape_area+= prev_x*first_y - prev_y*first_x;
if (fabs(shape_area) < 1e-8)
{
buffer.length(shape_pos);
return 0;
}
}
if ((cur_shape == Gcalc_function::shape_polygon ||
cur_shape == Gcalc_function::shape_hole) &&
prev_x == first_x && prev_y == first_y)
{
n_points--;
buffer.write_at_position(shape_pos+4, n_points);
goto do_complete;
}
buffer.write_at_position(shape_pos+4, n_points);
}
if (buffer.reserve(8*2, 512))
return 1;
buffer.q_append(prev_x);
buffer.q_append(prev_y);
do_complete:
buffer.write_at_position(shape_pos, (uint32) cur_shape);
if (!n_shapes++)
{
DBUG_ASSERT(cur_shape != Gcalc_function::shape_hole);
common_shapetype= cur_shape;
}
else if (cur_shape == Gcalc_function::shape_hole)
{
++n_holes;
}
else if (!collection_result && (cur_shape != common_shapetype))
{
collection_result= true;
}
return 0;
}
int Gcalc_result_receiver::single_point(double x, double y)
{
return start_shape(Gcalc_function::shape_point) ||
add_point(x, y) ||
complete_shape();
}
int Gcalc_result_receiver::done()
{
return 0;
}
void Gcalc_result_receiver::reset()
{
buffer.length(0);
collection_result= FALSE;
n_shapes= n_holes= 0;
}
int Gcalc_result_receiver::get_result_typeid()
{
if (!n_shapes)
return 0;
if (collection_result)
return Geometry::wkb_geometrycollection;
switch (common_shapetype)
{
case Gcalc_function::shape_polygon:
return (n_shapes - n_holes == 1) ?
Geometry::wkb_polygon : Geometry::wkb_multipolygon;
case Gcalc_function::shape_point:
return (n_shapes == 1) ? Geometry::wkb_point : Geometry::wkb_multipoint;
case Gcalc_function::shape_line:
return (n_shapes == 1) ? Geometry::wkb_linestring :
Geometry::wkb_multilinestring;
default:
DBUG_ASSERT(0);
}
return 0;
}
int Gcalc_result_receiver::move_hole(uint32 dest_position, uint32 source_position,
uint32 *new_dest_position)
{
char *ptr;
int source_len;
if (dest_position == source_position)
{
*new_dest_position= position();
return 0;
}
source_len= buffer.length() - source_position;
if (buffer.reserve(source_len, MY_ALIGN(source_len, 512)))
return 1;
ptr= (char *) buffer.ptr();
memmove(ptr + dest_position + source_len, ptr + dest_position,
buffer.length() - dest_position);
memcpy(ptr + dest_position, ptr + buffer.length(), source_len);
*new_dest_position= dest_position + source_len;
return 0;
}
Gcalc_operation_reducer::Gcalc_operation_reducer(size_t blk_size) :
Gcalc_dyn_list(blk_size, sizeof(res_point)),
m_res_hook((Gcalc_dyn_list::Item **)&m_result),
m_first_active_thread(NULL)
{}
void Gcalc_operation_reducer::init(Gcalc_function *fn, modes mode)
{
m_fn= fn;
m_mode= mode;
m_first_active_thread= NULL;
}
Gcalc_operation_reducer::
Gcalc_operation_reducer(Gcalc_function *fn, modes mode, size_t blk_size) :
Gcalc_dyn_list(blk_size, sizeof(res_point)),
m_res_hook((Gcalc_dyn_list::Item **)&m_result)
{
init(fn, mode);
}
inline int Gcalc_operation_reducer::continue_range(active_thread *t,
const Gcalc_heap::Info *p)
{
DBUG_ASSERT(t->result_range);
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= NULL;
rp->down= t->rp;
t->rp->up= rp;
rp->intersection_point= false;
rp->pi= p;
t->rp= rp;
return 0;
}
inline int Gcalc_operation_reducer::continue_i_range(active_thread *t,
const Gcalc_heap::Info *p,
double x, double y)
{
DBUG_ASSERT(t->result_range);
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= NULL;
rp->down= t->rp;
t->rp->up= rp;
rp->intersection_point= true;
rp->x= x;
rp->pi= p;
rp->y= y;
t->rp= rp;
return 0;
}
inline int Gcalc_operation_reducer::start_range(active_thread *t,
const Gcalc_heap::Info *p)
{
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= rp->down= NULL;
rp->intersection_point= false;
rp->pi= p;
t->result_range= 1;
t->rp= rp;
return 0;
}
inline int Gcalc_operation_reducer::start_i_range(active_thread *t,
const Gcalc_heap::Info *p,
double x, double y)
{
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= rp->down= NULL;
rp->intersection_point= true;
rp->x= x;
rp->y= y;
rp->pi= p;
t->result_range= 1;
t->rp= rp;
return 0;
}
inline int Gcalc_operation_reducer::end_range(active_thread *t,
const Gcalc_heap::Info *p)
{
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= rp->up= NULL;
rp->down= t->rp;
rp->intersection_point= false;
rp->pi= p;
t->rp->up= rp;
t->result_range= 0;
return 0;
}
inline int Gcalc_operation_reducer::end_i_range(active_thread *t,
const Gcalc_heap::Info *p,
double x, double y)
{
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= rp->up= NULL;
rp->down= t->rp;
rp->intersection_point= true;
rp->x= x;
rp->pi= p;
rp->y= y;
t->rp->up= rp;
t->result_range= 0;
return 0;
}
int Gcalc_operation_reducer::start_couple(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p,
const active_thread *prev_range)
{
res_point *rp0, *rp1;
if (!(rp0= add_res_point()) || !(rp1= add_res_point()))
return 1;
rp0->glue= rp1;
rp1->glue= rp0;
rp0->intersection_point= rp1->intersection_point= false;
rp0->down= rp1->down= NULL;
rp0->pi= rp1->pi= p;
t0->rp= rp0;
t1->rp= rp1;
if (prev_range)
{
rp0->outer_poly= prev_range->thread_start;
t1->thread_start= prev_range->thread_start;
}
else
{
rp0->outer_poly= 0;
t0->thread_start= rp0;
}
return 0;
}
int Gcalc_operation_reducer::start_i_couple(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p0,
const Gcalc_heap::Info *p1,
double x, double y,
const active_thread *prev_range)
{
res_point *rp0, *rp1;
if (!(rp0= add_res_point()) || !(rp1= add_res_point()))
return 1;
rp0->glue= rp1;
rp1->glue= rp0;
rp0->pi= p0;
rp1->pi= p1;
rp0->intersection_point= rp1->intersection_point= true;
rp0->down= rp1->down= NULL;
rp0->x= rp1->x= x;
rp0->y= rp1->y= y;
t0->result_range= t1->result_range= 1;
t0->rp= rp0;
t1->rp= rp1;
if (prev_range)
{
rp0->outer_poly= prev_range->thread_start;
t1->thread_start= prev_range->thread_start;
}
else
{
rp0->outer_poly= 0;
t0->thread_start= rp0;
}
return 0;
}
int Gcalc_operation_reducer::end_couple(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p)
{
res_point *rp0, *rp1;
DBUG_ASSERT(t1->result_range);
if (!(rp0= add_res_point()) || !(rp1= add_res_point()))
return 1;
rp0->down= t0->rp;
rp1->down= t1->rp;
rp1->glue= rp0;
rp0->glue= rp1;
rp0->up= rp1->up= NULL;
t0->rp->up= rp0;
t1->rp->up= rp1;
rp0->intersection_point= rp1->intersection_point= false;
rp0->pi= rp1->pi= p;
t0->result_range= t1->result_range= 0;
return 0;
}
int Gcalc_operation_reducer::end_i_couple(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p0,
const Gcalc_heap::Info *p1,
double x, double y)
{
res_point *rp0, *rp1;
if (!(rp0= add_res_point()) || !(rp1= add_res_point()))
return 1;
rp0->down= t0->rp;
rp1->down= t1->rp;
rp0->pi= p0;
rp1->pi= p1;
rp1->glue= rp0;
rp0->glue= rp1;
rp0->up= rp1->up= NULL;
rp0->intersection_point= rp1->intersection_point= true;
rp0->x= rp1->x= x;
rp0->y= rp1->y= y;
t0->result_range= t1->result_range= 0;
t0->rp->up= rp0;
t1->rp->up= rp1;
return 0;
}
int Gcalc_operation_reducer::add_single_point(const Gcalc_heap::Info *p)
{
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= rp->up= rp->down= NULL;
rp->intersection_point= false;
rp->pi= p;
rp->x= p->x;
rp->y= p->y;
return 0;
}
int Gcalc_operation_reducer::add_i_single_point(const Gcalc_heap::Info *p,
double x, double y)
{
res_point *rp= add_res_point();
if (!rp)
return 1;
rp->glue= rp->up= rp->down= NULL;
rp->intersection_point= true;
rp->x= x;
rp->pi= p;
rp->y= y;
return 0;
}
int Gcalc_operation_reducer::
handle_lines_intersection(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p0, const Gcalc_heap::Info *p1,
double x, double y)
{
m_fn->invert_state(p0->shape);
m_fn->invert_state(p1->shape);
int intersection_state= m_fn->count();
if ((t0->result_range | t1->result_range) == intersection_state)
return 0;
if (t0->result_range &&
(end_i_range(t0, p1, x, y) || start_i_range(t0, p1, x, y)))
return 1;
if (t1->result_range &&
(end_i_range(t1, p0, x, y) || start_i_range(t1, p0, x, y)))
return 1;
if (intersection_state &&
add_i_single_point(p0, x, y))
return 1;
return 0;
}
inline int Gcalc_operation_reducer::
handle_line_polygon_intersection(active_thread *l, const Gcalc_heap::Info *pl,
int line_state, int poly_state,
double x, double y)
{
int range_after= ~poly_state & line_state;
if (l->result_range == range_after)
return 0;
return range_after ? start_i_range(l, pl, x, y) : end_i_range(l, pl, x, y);
}
static inline void switch_athreads(Gcalc_operation_reducer::active_thread *t0,
Gcalc_operation_reducer::active_thread *t1,
Gcalc_dyn_list::Item **hook)
{
*hook= t1;
t0->next= t1->next;
t1->next= t0;
}
inline int Gcalc_operation_reducer::
handle_polygons_intersection(active_thread *t0, active_thread *t1,
Gcalc_dyn_list::Item **t_hook,
const Gcalc_heap::Info *p0,
const Gcalc_heap::Info *p1,
int prev_state, double x, double y,
const active_thread *prev_range)
{
m_fn->invert_state(p0->shape);
int state_11= m_fn->count();
m_fn->invert_state(p1->shape);
int state_2= m_fn->count();
int state_01= prev_state ^ t0->result_range;
if ((prev_state == state_01) && (prev_state == state_2))
{
if (state_11 == prev_state)
{
switch_athreads(t0, t1, t_hook);
return 0;
}
return start_i_couple(t0, t1, p0, p1, x, y, prev_range);
}
if (prev_state == state_2)
{
if (state_01 == state_11)
{
if (m_mode & polygon_selfintersections_allowed)
{
switch_athreads(t0, t1, t_hook);
return 0;
}
if (prev_state != (m_mode & prefer_big_with_holes))
return continue_i_range(t0, p0, x, y) || continue_i_range(t1, p1, x, y);
return end_i_couple(t0, t1, p0, p1, x, y) ||
start_i_couple(t0, t1, p0, p1, x, y, prev_range);
}
else
return end_i_couple(t0, t1, p0, p1, x, y);
}
if (state_01 ^ state_11)
{
switch_athreads(t0, t1, t_hook);
return 0;
}
active_thread *thread_to_continue;
const Gcalc_heap::Info *way_to_go;
if (prev_state == state_01)
{
thread_to_continue= t1;
way_to_go= p1;
}
else
{
thread_to_continue= t0;
way_to_go= p0;
}
return continue_i_range(thread_to_continue, way_to_go, x, y);
}
int Gcalc_operation_reducer::count_slice(Gcalc_scan_iterator *si)
{
Gcalc_point_iterator pi(si);
active_thread *cur_t= m_first_active_thread;
Gcalc_dyn_list::Item **at_hook= (Gcalc_dyn_list::Item **)&m_first_active_thread;
const active_thread *prev_range;
int prev_state;
if (si->get_event() & (scev_point | scev_end | scev_two_ends))
{
for (; pi.point() != si->get_event_position(); ++pi, cur_t= cur_t->get_next())
at_hook= &cur_t->next;
switch (si->get_event())
{
case scev_point:
{
if (cur_t->result_range &&
continue_range(cur_t, pi.get_pi()))
return 1;
break;
}
case scev_end:
{
if (cur_t->result_range &&
end_range(cur_t, pi.get_pi()))
return 1;
*at_hook= cur_t->next;
free_item(cur_t);
break;
}
case scev_two_ends:
{
active_thread *cur_t1= cur_t->get_next();
if (cur_t->result_range &&
end_couple(cur_t, cur_t1, pi.get_pi()))
return 1;
*at_hook= cur_t1->next;
free_list(cur_t, &cur_t1->next);
break;
}
default:
DBUG_ASSERT(0);
}
return 0;
}
prev_state= 0;
prev_range= 0;
m_fn->clear_state();
for (; pi.point() != si->get_event_position(); ++pi, cur_t= cur_t->get_next())
{
if (m_fn->get_shape_kind(pi.get_shape()) == Gcalc_function::shape_polygon)
{
m_fn->invert_state(pi.get_shape());
prev_state^= cur_t->result_range;
}
at_hook= &cur_t->next;
if (cur_t->result_range)
prev_range= prev_state ? cur_t : 0;
}
switch (si->get_event())
{
case scev_thread:
{
active_thread *new_t= new_active_thread();
if (!new_t)
return 1;
m_fn->invert_state(pi.get_shape());
new_t->result_range= prev_state ^ m_fn->count();
new_t->next= *at_hook;
*at_hook= new_t;
if (new_t->result_range &&
start_range(new_t, pi.get_pi()))
return 1;
break;
}
case scev_two_threads:
{
active_thread *new_t0, *new_t1;
int fn_result;
if (!(new_t0= new_active_thread()) || !(new_t1= new_active_thread()))
return 1;
m_fn->invert_state(pi.get_shape());
fn_result= m_fn->count();
new_t0->result_range= new_t1->result_range= prev_state ^ fn_result;
new_t1->next= *at_hook;
new_t0->next= new_t1;
*at_hook= new_t0;
if (new_t0->result_range &&
start_couple(new_t0, new_t1, pi.get_pi(), prev_range))
return 1;
break;
}
case scev_intersection:
{
active_thread *cur_t1= cur_t->get_next();
const Gcalc_heap::Info *p0, *p1;
p0= pi.get_pi();
++pi;
p1= pi.get_pi();
bool line0= m_fn->get_shape_kind(p0->shape) == Gcalc_function::shape_line;
bool line1= m_fn->get_shape_kind(p1->shape) == Gcalc_function::shape_line;
if (!line0 && !line1) /* two polygons*/
{
if (handle_polygons_intersection(cur_t, cur_t1, at_hook, p0, p1,
prev_state, pi.get_x(), si->get_y(),
prev_range))
return 1;
}
else if (line0 && line1)
{
if (!prev_state &&
handle_lines_intersection(cur_t, cur_t1,
p0, p1, pi.get_x(), si->get_y()))
return 1;
switch_athreads(cur_t, cur_t1, at_hook);
}
else
{
int poly_state;
int line_state;
const Gcalc_heap::Info *line;
active_thread *line_t;
m_fn->invert_state(p0->shape);
if (line0)
{
line_state= m_fn->count();
poly_state= prev_state;
line= p0;
line_t= cur_t1;
}
else
{
poly_state= m_fn->count();
m_fn->invert_state(p1->shape);
line_state= m_fn->count();
line= p1;
line_t= cur_t;
}
if (handle_line_polygon_intersection(line_t, line,
line_state, poly_state,
pi.get_x(), si->get_y()))
return 1;
switch_athreads(cur_t, cur_t1, at_hook);
}
break;
}
case scev_single_point:
{
m_fn->invert_state(pi.get_shape());
if ((prev_state ^ m_fn->count()) &&
add_single_point(pi.get_pi()))
return 1;
break;
}
default:
DBUG_ASSERT(0);
}
return 0;
}
int Gcalc_operation_reducer::count_all(Gcalc_heap *hp)
{
Gcalc_scan_iterator si;
si.init(hp);
while (si.more_points())
{
if (si.step())
return 1;
if (count_slice(&si))
return 1;
}
return 0;
}
inline void Gcalc_operation_reducer::free_result(res_point *res)
{
if ((*res->prev_hook= res->next))
{
res->get_next()->prev_hook= res->prev_hook;
}
free_item(res);
}
inline int Gcalc_operation_reducer::get_single_result(res_point *res,
Gcalc_result_receiver *storage)
{
if (res->intersection_point)
{
if (storage->single_point(float_to_coord(res->x),
float_to_coord(res->y)))
return 1;
}
else
if (storage->single_point(res->x, res->y))
return 1;
free_result(res);
return 0;
}
int Gcalc_operation_reducer::get_result_thread(res_point *cur,
Gcalc_result_receiver *storage,
int move_upward)
{
res_point *next;
bool glue_step= false;
res_point *first_poly_node= cur;
double x, y;
while (cur)
{
if (!glue_step)
{
if (cur->intersection_point)
{
x= float_to_coord(cur->x);
y= float_to_coord(cur->y);
}
else
{
x= cur->pi->x;
y= cur->pi->y;
}
if (storage->add_point(x, y))
return 1;
}
next= move_upward ? cur->up : cur->down;
if (!next && !glue_step)
{
next= cur->glue;
move_upward^= 1;
glue_step= true;
if (next)
next->glue= NULL;
}
else
glue_step= false;
cur->first_poly_node= first_poly_node;
free_result(cur);
cur= next;
}
return 0;
}
int Gcalc_operation_reducer::get_polygon_result(res_point *cur,
Gcalc_result_receiver *storage)
{
res_point *glue= cur->glue;
glue->up->down= NULL;
free_result(glue);
return get_result_thread(cur, storage, 1) ||
storage->complete_shape();
}
int Gcalc_operation_reducer::get_line_result(res_point *cur,
Gcalc_result_receiver *storage)
{
res_point *next;
int move_upward= 1;
if (cur->glue)
{
/* Here we have to find the beginning of the line */
next= cur->up;
move_upward= 1;
while (next)
{
cur= next;
next= move_upward ? next->up : next->down;
if (!next)
{
next= cur->glue;
move_upward^= 1;
}
}
}
return get_result_thread(cur, storage, move_upward) ||
storage->complete_shape();
}
int Gcalc_operation_reducer::get_result(Gcalc_result_receiver *storage)
{
*m_res_hook= NULL;
while (m_result)
{
if (!m_result->up)
{
if (get_single_result(m_result, storage))
return 1;
continue;
}
Gcalc_function::shape_type shape= m_fn->get_shape_kind(m_result->pi->shape);
if (shape == Gcalc_function::shape_polygon)
{
if (m_result->outer_poly)
{
uint32 *insert_position, hole_position;
insert_position= &m_result->outer_poly->first_poly_node->poly_position;
DBUG_ASSERT(*insert_position);
hole_position= storage->position();
storage->start_shape(Gcalc_function::shape_hole);
if (get_polygon_result(m_result, storage) ||
storage->move_hole(*insert_position, hole_position,
insert_position))
return 1;
}
else
{
uint32 *poly_position= &m_result->poly_position;
storage->start_shape(Gcalc_function::shape_polygon);
if (get_polygon_result(m_result, storage))
return 1;
*poly_position= storage->position();
}
}
else
{
storage->start_shape(shape);
if (get_line_result(m_result, storage))
return 1;
}
}
m_res_hook= (Gcalc_dyn_list::Item **)&m_result;
storage->done();
return 0;
}
void Gcalc_operation_reducer::reset()
{
free_list(m_result, m_res_hook);
m_res_hook= (Gcalc_dyn_list::Item **)&m_result;
free_list(m_first_active_thread);
}
#endif /*HAVE_SPATIAL*/
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef GCALC_TOOLS_INCLUDED
#define GCALC_TOOLS_INCLUDED
#include "gcalc_slicescan.h"
/*
The Gcalc_function class objects are used to check for a binary relation.
The relation can be constructed with the prefix notation using predicates as
op_not (as !A)
op_union ( A || B || C... )
op_intersection ( A && B && C ... )
op_symdifference ( A+B+C+... == 1 )
op_difference ( A && !(B||C||..))
with the calls of the add_operation(operation, n_operands) method.
The relation is calculated over a set of shapes, that in turn have
to be added with the add_new_shape() method. All the 'shapes' can
be set to 0 with clear_shapes() method and single value
can be changed with the invert_state() method.
Then the value of the relation can be calculated with the count() method.
Frequently used method is find_function(Gcalc_scan_iterator it) that
iterates through the 'it' until the relation becomes TRUE.
*/
class Gcalc_function
{
private:
String shapes_buffer;
String function_buffer;
const char *cur_func;
int *i_states;
uint32 cur_object_id;
uint n_shapes;
int count_internal();
public:
enum op_type
{
op_shape= 0,
op_not= 0x80000000,
op_union= 0x10000000,
op_intersection= 0x20000000,
op_symdifference= 0x30000000,
op_difference= 0x40000000,
op_backdifference= 0x50000000,
op_any= 0x70000000
};
enum shape_type
{
shape_point= 0,
shape_line= 1,
shape_polygon= 2,
shape_hole= 3
};
Gcalc_function() : n_shapes(0) {}
gcalc_shape_info add_new_shape(uint32 shape_id, shape_type shape_kind);
/*
Adds the leaf operation that returns the shape value.
Also adds the shape to the list of operands.
*/
int single_shape_op(shape_type shape_kind, gcalc_shape_info *si);
void add_operation(op_type operation, uint32 n_operands);
void add_not_operation(op_type operation, uint32 n_operands);
uint32 get_next_operation_pos() { return function_buffer.length(); }
void add_operands_to_op(uint32 operation_pos, uint32 n_operands);
void set_cur_obj(uint32 cur_obj) { cur_object_id= cur_obj; }
int reserve_shape_buffer(uint n_shapes);
int reserve_op_buffer(uint n_ops);
uint get_nshapes() const { return n_shapes; }
shape_type get_shape_kind(gcalc_shape_info si) const
{
return (shape_type) uint4korr(shapes_buffer.ptr() + (si*4));
}
void set_states(int *shape_states) { i_states= shape_states; }
int alloc_states();
void invert_state(gcalc_shape_info shape) { i_states[shape]^= 1; }
int get_state(gcalc_shape_info shape) { return i_states[shape]; }
int count()
{
cur_func= function_buffer.ptr();
return count_internal();
}
void clear_state() { bzero(i_states, n_shapes * sizeof(int)); }
void reset();
int find_function(Gcalc_scan_iterator &scan_it);
};
/*
Gcalc_operation_transporter class extends the Gcalc_shape_transporter.
In addition to the parent's functionality, it fills the Gcalc_function
object so it has the function that determines the proper shape.
For example Multipolyline will be represented as an union of polylines.
*/
class Gcalc_operation_transporter : public Gcalc_shape_transporter
{
protected:
Gcalc_function *m_fn;
gcalc_shape_info m_si;
public:
Gcalc_operation_transporter(Gcalc_function *fn, Gcalc_heap *heap) :
Gcalc_shape_transporter(heap), m_fn(fn) {}
int single_point(double x, double y);
int start_line();
int complete_line();
int start_poly();
int complete_poly();
int start_ring();
int complete_ring();
int add_point(double x, double y);
int start_collection(int n_objects);
};
/*
When we calculate the result of an spatial operation like
Union or Intersection, we receive vertexes of the result
one-by-one, and probably need to treat them in variative ways.
So, the Gcalc_result_receiver class designed to get these
vertexes and construct shapes/objects out of them.
and to store the result in an appropriate format
*/
class Gcalc_result_receiver
{
String buffer;
uint32 n_points;
Gcalc_function::shape_type common_shapetype;
bool collection_result;
uint32 n_shapes;
uint32 n_holes;
Gcalc_function::shape_type cur_shape;
uint32 shape_pos;
double first_x, first_y, prev_x, prev_y;
double shape_area;
public:
Gcalc_result_receiver() : collection_result(FALSE), n_shapes(0), n_holes(0)
{}
int start_shape(Gcalc_function::shape_type shape);
int add_point(double x, double y);
int complete_shape();
int single_point(double x, double y);
int done();
void reset();
const char *result() { return buffer.ptr(); }
uint length() { return buffer.length(); }
int get_nshapes() { return n_shapes; }
int get_nholes() { return n_holes; }
int get_result_typeid();
uint32 position() { return buffer.length(); }
int move_hole(uint32 dest_position, uint32 source_position,
uint32 *new_dest_position);
};
/*
Gcalc_operation_reducer class incapsulates the spatial
operation functionality. It analyses the slices generated by
the slicescan and calculates the shape of the result defined
by some Gcalc_function.
*/
class Gcalc_operation_reducer : public Gcalc_dyn_list
{
public:
enum modes
{
/* Numeric values important here - careful with changing */
default_mode= 0,
prefer_big_with_holes= 1,
polygon_selfintersections_allowed= 2, /* allowed in the result */
line_selfintersections_allowed= 4 /* allowed in the result */
};
Gcalc_operation_reducer(size_t blk_size=8192);
void init(Gcalc_function *fn, modes mode= default_mode);
Gcalc_operation_reducer(Gcalc_function *fn, modes mode= default_mode,
size_t blk_size=8192);
int count_slice(Gcalc_scan_iterator *si);
int count_all(Gcalc_heap *hp);
int get_result(Gcalc_result_receiver *storage);
void reset();
class res_point : public Gcalc_dyn_list::Item
{
public:
bool intersection_point;
double x,y;
res_point *up;
res_point *down;
res_point *glue;
union
{
const Gcalc_heap::Info *pi;
res_point *first_poly_node;
};
union
{
res_point *outer_poly;
uint32 poly_position;
};
Gcalc_dyn_list::Item **prev_hook;
res_point *get_next() { return (res_point *)next; }
};
class active_thread : public Gcalc_dyn_list::Item
{
public:
res_point *rp;
int result_range;
res_point *thread_start;
active_thread *get_next() { return (active_thread *)next; }
};
protected:
Gcalc_function *m_fn;
Gcalc_dyn_list::Item **m_res_hook;
res_point *m_result;
int m_mode;
res_point *result_heap;
active_thread *m_first_active_thread;
res_point *add_res_point()
{
res_point *result= (res_point *)new_item();
*m_res_hook= result;
result->prev_hook= m_res_hook;
m_res_hook= &result->next;
return result;
}
active_thread *new_active_thread() { return (active_thread *)new_item(); }
private:
int continue_range(active_thread *t, const Gcalc_heap::Info *p);
int continue_i_range(active_thread *t, const Gcalc_heap::Info *p,
double x, double y);
int start_range(active_thread *t, const Gcalc_heap::Info *p);
int start_i_range(active_thread *t, const Gcalc_heap::Info *p,
double x, double y);
int end_range(active_thread *t, const Gcalc_heap::Info *p);
int end_i_range(active_thread *t, const Gcalc_heap::Info *p,
double x, double y);
int start_couple(active_thread *t0, active_thread *t1,const Gcalc_heap::Info *p,
const active_thread *prev_range);
int start_i_couple(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p0,
const Gcalc_heap::Info *p1,
double x, double y,
const active_thread *prev_range);
int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p);
int end_i_couple(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p0,
const Gcalc_heap::Info *p1,
double x, double y);
int add_single_point(const Gcalc_heap::Info *p);
int add_i_single_point(const Gcalc_heap::Info *p, double x, double y);
int handle_lines_intersection(active_thread *t0, active_thread *t1,
const Gcalc_heap::Info *p0,
const Gcalc_heap::Info *p1,
double x, double y);
int handle_polygons_intersection(active_thread *t0, active_thread *t1,
Gcalc_dyn_list::Item **t_hook,
const Gcalc_heap::Info *p0,
const Gcalc_heap::Info *p1,
int prev_state, double x, double y,
const active_thread *prev_range);
int handle_line_polygon_intersection(active_thread *l,
const Gcalc_heap::Info *pl,
int line_state, int poly_state,
double x, double y);
int get_single_result(res_point *res, Gcalc_result_receiver *storage);
int get_result_thread(res_point *cur, Gcalc_result_receiver *storage,
int move_upward);
int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage);
int get_line_result(res_point *cur, Gcalc_result_receiver *storage);
void free_result(res_point *res);
};
#endif /*GCALC_TOOLS_INCLUDED*/
......@@ -509,6 +509,19 @@ class Create_func_connection_id : public Create_func_arg0
#ifdef HAVE_SPATIAL
class Create_func_mbr_contains : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_mbr_contains s_singleton;
protected:
Create_func_mbr_contains() {}
virtual ~Create_func_mbr_contains() {}
};
class Create_func_contains : public Create_func_arg2
{
public:
......@@ -749,6 +762,19 @@ class Create_func_dimension : public Create_func_arg1
#ifdef HAVE_SPATIAL
class Create_func_mbr_disjoint : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_mbr_disjoint s_singleton;
protected:
Create_func_mbr_disjoint() {}
virtual ~Create_func_mbr_disjoint() {}
};
class Create_func_disjoint : public Create_func_arg2
{
public:
......@@ -760,6 +786,19 @@ class Create_func_disjoint : public Create_func_arg2
Create_func_disjoint() {}
virtual ~Create_func_disjoint() {}
};
class Create_func_distance : public Create_func_arg2
{
public:
virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_distance s_singleton;
protected:
Create_func_distance() {}
virtual ~Create_func_distance() {}
};
#endif
......@@ -833,6 +872,19 @@ class Create_func_envelope : public Create_func_arg1
#ifdef HAVE_SPATIAL
class Create_func_mbr_equals : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_mbr_equals s_singleton;
protected:
Create_func_mbr_equals() {}
virtual ~Create_func_mbr_equals() {}
};
class Create_func_equals : public Create_func_arg2
{
public:
......@@ -1161,6 +1213,19 @@ class Create_func_interiorringn : public Create_func_arg2
#ifdef HAVE_SPATIAL
class Create_func_mbr_intersects : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_mbr_intersects s_singleton;
protected:
Create_func_mbr_intersects() {}
virtual ~Create_func_mbr_intersects() {}
};
class Create_func_intersects : public Create_func_arg2
{
public:
......@@ -1172,7 +1237,72 @@ class Create_func_intersects : public Create_func_arg2
Create_func_intersects() {}
virtual ~Create_func_intersects() {}
};
#endif
class Create_func_intersection : public Create_func_arg2
{
public:
virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_intersection s_singleton;
protected:
Create_func_intersection() {}
virtual ~Create_func_intersection() {}
};
class Create_func_difference : public Create_func_arg2
{
public:
virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_difference s_singleton;
protected:
Create_func_difference() {}
virtual ~Create_func_difference() {}
};
class Create_func_union : public Create_func_arg2
{
public:
virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_union s_singleton;
protected:
Create_func_union() {}
virtual ~Create_func_union() {}
};
class Create_func_symdifference : public Create_func_arg2
{
public:
virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_symdifference s_singleton;
protected:
Create_func_symdifference() {}
virtual ~Create_func_symdifference() {}
};
class Create_func_buffer : public Create_func_arg2
{
public:
virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_buffer s_singleton;
protected:
Create_func_buffer() {}
virtual ~Create_func_buffer() {}
};
#endif /*HAVE_SPATIAL*/
class Create_func_is_free_lock : public Create_func_arg1
......@@ -1604,6 +1734,19 @@ class Create_func_ord : public Create_func_arg1
#ifdef HAVE_SPATIAL
class Create_func_mbr_overlaps : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_mbr_overlaps s_singleton;
protected:
Create_func_mbr_overlaps() {}
virtual ~Create_func_mbr_overlaps() {}
};
class Create_func_overlaps : public Create_func_arg2
{
public:
......@@ -2199,6 +2342,19 @@ class Create_func_weekofyear : public Create_func_arg1
#ifdef HAVE_SPATIAL
class Create_func_mbr_within : public Create_func_arg2
{
public:
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_mbr_within s_singleton;
protected:
Create_func_mbr_within() {}
virtual ~Create_func_mbr_within() {}
};
class Create_func_within : public Create_func_arg2
{
public:
......@@ -2890,6 +3046,16 @@ Create_func_connection_id::create_builder(THD *thd)
#ifdef HAVE_SPATIAL
Create_func_mbr_contains Create_func_mbr_contains::s_singleton;
Item*
Create_func_mbr_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2,
Item_func::SP_CONTAINS_FUNC);
}
Create_func_contains Create_func_contains::s_singleton;
Item*
......@@ -3122,6 +3288,16 @@ Create_func_dimension::create_1_arg(THD *thd, Item *arg1)
#ifdef HAVE_SPATIAL
Create_func_mbr_disjoint Create_func_mbr_disjoint::s_singleton;
Item*
Create_func_mbr_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2,
Item_func::SP_DISJOINT_FUNC);
}
Create_func_disjoint Create_func_disjoint::s_singleton;
Item*
......@@ -3130,6 +3306,15 @@ Create_func_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_DISJOINT_FUNC);
}
Create_func_distance Create_func_distance::s_singleton;
Item*
Create_func_distance::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_distance(arg1, arg2);
}
#endif
......@@ -3225,6 +3410,16 @@ Create_func_envelope::create_1_arg(THD *thd, Item *arg1)
#ifdef HAVE_SPATIAL
Create_func_mbr_equals Create_func_mbr_equals::s_singleton;
Item*
Create_func_mbr_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2,
Item_func::SP_EQUALS_FUNC);
}
Create_func_equals Create_func_equals::s_singleton;
Item*
......@@ -3620,6 +3815,16 @@ Create_func_interiorringn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
#ifdef HAVE_SPATIAL
Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton;
Item*
Create_func_mbr_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2,
Item_func::SP_INTERSECTS_FUNC);
}
Create_func_intersects Create_func_intersects::s_singleton;
Item*
......@@ -3628,7 +3833,56 @@ Create_func_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_INTERSECTS_FUNC);
}
#endif
Create_func_intersection Create_func_intersection::s_singleton;
Item*
Create_func_intersection::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2,
Gcalc_function::op_intersection);
}
Create_func_difference Create_func_difference::s_singleton;
Item*
Create_func_difference::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2,
Gcalc_function::op_difference);
}
Create_func_union Create_func_union::s_singleton;
Item*
Create_func_union::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2,
Gcalc_function::op_union);
}
Create_func_symdifference Create_func_symdifference::s_singleton;
Item*
Create_func_symdifference::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_operation(arg1, arg2,
Gcalc_function::op_symdifference);
}
Create_func_buffer Create_func_buffer::s_singleton;
Item*
Create_func_buffer::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_buffer(arg1, arg2);
}
#endif /*HAVE_SPATAI*/
Create_func_is_free_lock Create_func_is_free_lock::s_singleton;
......@@ -4088,6 +4342,16 @@ Create_func_ord::create_1_arg(THD *thd, Item *arg1)
#ifdef HAVE_SPATIAL
Create_func_mbr_overlaps Create_func_mbr_overlaps::s_singleton;
Item*
Create_func_mbr_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2,
Item_func::SP_OVERLAPS_FUNC);
}
Create_func_overlaps Create_func_overlaps::s_singleton;
Item*
......@@ -4640,6 +4904,16 @@ Create_func_weekofyear::create_1_arg(THD *thd, Item *arg1)
#ifdef HAVE_SPATIAL
Create_func_mbr_within Create_func_mbr_within::s_singleton;
Item*
Create_func_mbr_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_mbr_rel(arg1, arg2,
Item_func::SP_WITHIN_FUNC);
}
Create_func_within Create_func_within::s_singleton;
Item*
......@@ -4773,6 +5047,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("BIN") }, BUILDER(Create_func_bin)},
{ { C_STRING_WITH_LEN("BIT_COUNT") }, BUILDER(Create_func_bit_count)},
{ { C_STRING_WITH_LEN("BIT_LENGTH") }, BUILDER(Create_func_bit_length)},
{ { C_STRING_WITH_LEN("BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
{ { C_STRING_WITH_LEN("CEIL") }, BUILDER(Create_func_ceiling)},
{ { C_STRING_WITH_LEN("CEILING") }, BUILDER(Create_func_ceiling)},
{ { C_STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
......@@ -4800,13 +5075,13 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("DES_DECRYPT") }, BUILDER(Create_func_des_decrypt)},
{ { C_STRING_WITH_LEN("DES_ENCRYPT") }, BUILDER(Create_func_des_encrypt)},
{ { C_STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
{ { C_STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
{ { C_STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
{ { C_STRING_WITH_LEN("ELT") }, BUILDER(Create_func_elt)},
{ { C_STRING_WITH_LEN("ENCODE") }, BUILDER(Create_func_encode)},
{ { C_STRING_WITH_LEN("ENCRYPT") }, BUILDER(Create_func_encrypt)},
{ { C_STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
{ { C_STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
{ { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)},
{ { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
{ { C_STRING_WITH_LEN("EXP") }, BUILDER(Create_func_exp)},
{ { C_STRING_WITH_LEN("EXPORT_SET") }, BUILDER(Create_func_export_set)},
{ { C_STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
......@@ -4837,7 +5112,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("INET_NTOA") }, BUILDER(Create_func_inet_ntoa)},
{ { C_STRING_WITH_LEN("INSTR") }, BUILDER(Create_func_instr)},
{ { C_STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
{ { C_STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
{ { C_STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
{ { C_STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
{ { C_STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
{ { C_STRING_WITH_LEN("ISNULL") }, BUILDER(Create_func_isnull)},
......@@ -4866,13 +5141,13 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("MAKETIME") }, BUILDER(Create_func_maketime)},
{ { C_STRING_WITH_LEN("MAKE_SET") }, BUILDER(Create_func_make_set)},
{ { C_STRING_WITH_LEN("MASTER_POS_WAIT") }, BUILDER(Create_func_master_pos_wait)},
{ { C_STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_contains)},
{ { C_STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
{ { C_STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_equals)},
{ { C_STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
{ { C_STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
{ { C_STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_mbr_contains)},
{ { C_STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
{ { C_STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_mbr_equals)},
{ { C_STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
{ { C_STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
{ { C_STRING_WITH_LEN("MBRTOUCHES") }, GEOM_BUILDER(Create_func_touches)},
{ { C_STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_within)},
{ { C_STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_mbr_within)},
{ { C_STRING_WITH_LEN("MD5") }, BUILDER(Create_func_md5)},
{ { C_STRING_WITH_LEN("MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
......@@ -4895,7 +5170,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("OCT") }, BUILDER(Create_func_oct)},
{ { C_STRING_WITH_LEN("OCTET_LENGTH") }, BUILDER(Create_func_length)},
{ { C_STRING_WITH_LEN("ORD") }, BUILDER(Create_func_ord)},
{ { C_STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
{ { C_STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
{ { C_STRING_WITH_LEN("PERIOD_ADD") }, BUILDER(Create_func_period_add)},
{ { C_STRING_WITH_LEN("PERIOD_DIFF") }, BUILDER(Create_func_period_diff)},
{ { C_STRING_WITH_LEN("PI") }, BUILDER(Create_func_pi)},
......@@ -4930,6 +5205,64 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
{ { C_STRING_WITH_LEN("STRCMP") }, BUILDER(Create_func_strcmp)},
{ { C_STRING_WITH_LEN("STR_TO_DATE") }, BUILDER(Create_func_str_to_date)},
{ { C_STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)},
{ { C_STRING_WITH_LEN("ST_ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
{ { C_STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
{ { C_STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
{ { C_STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
{ { C_STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
{ { C_STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
{ { C_STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
{ { C_STRING_WITH_LEN("ST_CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
{ { C_STRING_WITH_LEN("ST_DIFFERENCE") }, GEOM_BUILDER(Create_func_difference)},
{ { C_STRING_WITH_LEN("ST_DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
{ { C_STRING_WITH_LEN("ST_DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
{ { C_STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)},
{ { C_STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
{ { C_STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
{ { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
{ { C_STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
{ { C_STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
{ { C_STRING_WITH_LEN("ST_GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
{ { C_STRING_WITH_LEN("ST_GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
{ { C_STRING_WITH_LEN("ST_INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
{ { C_STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
{ { C_STRING_WITH_LEN("ST_INTERSECTION") }, GEOM_BUILDER(Create_func_intersection)},
{ { C_STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
{ { C_STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
{ { C_STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
{ { C_STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)},
{ { C_STRING_WITH_LEN("ST_LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
{ { C_STRING_WITH_LEN("ST_NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
{ { C_STRING_WITH_LEN("ST_NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
{ { C_STRING_WITH_LEN("ST_OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
{ { C_STRING_WITH_LEN("ST_POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_POINTN") }, GEOM_BUILDER(Create_func_pointn)},
{ { C_STRING_WITH_LEN("ST_POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
{ { C_STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { C_STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)},
{ { C_STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
{ { C_STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)},
{ { C_STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
{ { C_STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)},
{ { C_STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_mbr_within)},
{ { C_STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
{ { C_STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
{ { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
{ { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)},
{ { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)},
......
/* Copyright (C) 2003-2006 MySQL AB
/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -10,8 +10,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/**
......@@ -26,9 +26,15 @@
#endif
#include "mysql_priv.h"
/*
It is necessary to include set_var.h instead of item.h because there
are dependencies on include order for set_var.h and item.h. This
will be resolved later.
*/
#ifdef HAVE_SPATIAL
#include <m_ctype.h>
Field *Item_geometry_func::tmp_table_field(TABLE *t_arg)
{
Field *result;
......@@ -42,7 +48,7 @@ void Item_geometry_func::fix_length_and_dec()
{
collation.set(&my_charset_bin);
decimals=0;
max_length= max_field_size;
max_length= (uint32) 4294967295U;
maybe_null= 1;
}
......@@ -134,6 +140,7 @@ String *Item_func_as_wkt::val_str(String *str)
void Item_func_as_wkt::fix_length_and_dec()
{
collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
max_length=MAX_BLOB_WIDTH;
maybe_null= 1;
}
......@@ -361,7 +368,7 @@ String *Item_func_point::val_str(String *str)
if ((null_value= (args[0]->null_value ||
args[1]->null_value ||
str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE*2))))
str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2))))
return 0;
str->set_charset(&my_charset_bin);
......@@ -508,7 +515,33 @@ String *Item_func_spatial_collection::val_str(String *str)
Functions for spatial relations
*/
longlong Item_func_spatial_rel::val_int()
const char *Item_func_spatial_mbr_rel::func_name() const
{
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
return "mbrcontains";
case SP_WITHIN_FUNC:
return "mbrwithin";
case SP_EQUALS_FUNC:
return "mbrequals";
case SP_DISJOINT_FUNC:
return "mbrdisjoint";
case SP_INTERSECTS_FUNC:
return "mbrintersects";
case SP_TOUCHES_FUNC:
return "mbrtouches";
case SP_CROSSES_FUNC:
return "mbrcrosses";
case SP_OVERLAPS_FUNC:
return "mbroverlaps";
default:
DBUG_ASSERT(0); // Should never happened
return "mbrsp_unknown";
}
}
longlong Item_func_spatial_mbr_rel::val_int()
{
DBUG_ASSERT(fixed == 1);
String *res1= args[0]->val_str(&cmp.value1);
......@@ -553,6 +586,867 @@ longlong Item_func_spatial_rel::val_int()
}
Item_func_spatial_rel::Item_func_spatial_rel(Item *a,Item *b,
enum Functype sp_rel) :
Item_bool_func2(a,b), collector()
{
spatial_rel = sp_rel;
}
Item_func_spatial_rel::~Item_func_spatial_rel()
{
}
const char *Item_func_spatial_rel::func_name() const
{
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
return "st_contains";
case SP_WITHIN_FUNC:
return "st_within";
case SP_EQUALS_FUNC:
return "st_equals";
case SP_DISJOINT_FUNC:
return "st_disjoint";
case SP_INTERSECTS_FUNC:
return "st_intersects";
case SP_TOUCHES_FUNC:
return "st_touches";
case SP_CROSSES_FUNC:
return "st_crosses";
case SP_OVERLAPS_FUNC:
return "st_overlaps";
default:
DBUG_ASSERT(0); // Should never happened
return "sp_unknown";
}
}
static double count_edge_t(const Gcalc_heap::Info *ea,
const Gcalc_heap::Info *eb,
const Gcalc_heap::Info *v,
double &ex, double &ey, double &vx, double &vy,
double &e_sqrlen)
{
ex= eb->x - ea->x;
ey= eb->y - ea->y;
vx= v->x - ea->x;
vy= v->y - ea->y;
e_sqrlen= ex * ex + ey * ey;
return (ex * vx + ey * vy) / e_sqrlen;
}
static double distance_to_line(double ex, double ey, double vx, double vy,
double e_sqrlen)
{
return fabs(vx * ey - vy * ex) / sqrt(e_sqrlen);
}
static double distance_points(const Gcalc_heap::Info *a,
const Gcalc_heap::Info *b)
{
double x= a->x - b->x;
double y= a->y - b->y;
return sqrt(x * x + y * y);
}
/*
Calculates the distance between objects.
*/
static int calc_distance(double *result, Gcalc_heap *collector, uint obj2_si,
Gcalc_function *func, Gcalc_scan_iterator *scan_it)
{
bool above_cur_point, cur_point_edge;
const Gcalc_scan_iterator::point *evpos;
const Gcalc_heap::Info *cur_point, *dist_point;
Gcalc_scan_events ev;
double t, distance, cur_distance;
double ex, ey, vx, vy, e_sqrlen;
DBUG_ENTER("calc_distance");
above_cur_point= false;
distance= DBL_MAX;
while (scan_it->more_points())
{
if (scan_it->step())
goto mem_error;
evpos= scan_it->get_event_position();
ev= scan_it->get_event();
cur_point= evpos->pi;
/*
handling intersection we only need to check if it's the intersecion
of objects 1 and 2. In this case distance is 0
*/
if (ev == scev_intersection)
{
if ((evpos->get_next()->pi->shape >= obj2_si) !=
(cur_point->shape >= obj2_si))
{
distance= 0;
goto exit;
}
continue;
}
/*
if we get 'scev_point | scev_end | scev_two_ends' we don't need
to check for intersection of objects.
Though we need to calculate distances.
*/
if (ev & (scev_point | scev_end | scev_two_ends))
goto calculate_distance;
goto calculate_distance;
/*
having these events we need to check for possible intersection
of objects
scev_thread | scev_two_threads | scev_single_point
*/
DBUG_ASSERT(ev & (scev_thread | scev_two_threads | scev_single_point));
func->clear_state();
for (Gcalc_point_iterator pit(scan_it); pit.point() != evpos; ++pit)
{
gcalc_shape_info si= pit.point()->get_shape();
if ((func->get_shape_kind(si) == Gcalc_function::shape_polygon))
func->invert_state(si);
}
func->invert_state(evpos->get_shape());
if (func->count())
{
/* Point of one object is inside the other - intersection found */
distance= 0;
goto exit;
}
calculate_distance:
if (cur_point->shape >= obj2_si)
continue;
cur_point_edge= !cur_point->is_bottom();
for (dist_point= collector->get_first(); dist_point; dist_point= dist_point->get_next())
{
/* We only check vertices of object 2 */
if (dist_point->shape < obj2_si)
continue;
/* if we have an edge to check */
if (dist_point->left)
{
t= count_edge_t(dist_point, dist_point->left, cur_point,
ex, ey, vx, vy, e_sqrlen);
if ((t > 0.0) && (t < 1.0))
{
cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
if (distance > cur_distance)
distance= cur_distance;
}
}
if (cur_point_edge)
{
t= count_edge_t(cur_point, cur_point->left, dist_point,
ex, ey, vx, vy, e_sqrlen);
if ((t > 0.0) && (t < 1.0))
{
cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
if (distance > cur_distance)
distance= cur_distance;
}
}
cur_distance= distance_points(cur_point, dist_point);
if (distance > cur_distance)
distance= cur_distance;
}
}
exit:
*result= distance;
DBUG_RETURN(0);
mem_error:
DBUG_RETURN(1);
}
#define GIS_ZERO 0.00000000001
int Item_func_spatial_rel::func_touches()
{
bool above_cur_point;
double x1, x2, y1, y2, ex, ey;
double distance, area;
int result= 0;
int cur_func= 0;
Gcalc_operation_transporter trn(&func, &collector);
String *res1= args[0]->val_str(&tmp_value1);
String *res2= args[1]->val_str(&tmp_value2);
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
int obj2_si;
DBUG_ENTER("Item_func_spatial_rel::func_touches");
DBUG_ASSERT(fixed == 1);
if ((null_value= (args[0]->null_value || args[1]->null_value ||
!(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) ||
!(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())))))
goto mem_error;
if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) &&
(g2->get_class_info()->m_type_id == Geometry::wkb_point))
{
if (((Gis_point *) g1)->get_xy(&x1, &y1) ||
((Gis_point *) g2)->get_xy(&x2, &y2))
goto mem_error;
ex= x2 - x1;
ey= y2 - y1;
DBUG_RETURN((ex * ex + ey * ey) < GIS_ZERO);
}
if (func.reserve_op_buffer(1))
goto mem_error;
func.add_operation(Gcalc_function::op_intersection, 2);
if (g1->store_shapes(&trn))
goto mem_error;
obj2_si= func.get_nshapes();
if (g2->store_shapes(&trn) || func.alloc_states())
goto mem_error;
collector.prepare_operation();
scan_it.init(&collector);
if (calc_distance(&distance, &collector, obj2_si, &func, &scan_it))
goto mem_error;
if (distance > GIS_ZERO)
goto exit;
scan_it.reset();
scan_it.init(&collector);
above_cur_point= false;
distance= DBL_MAX;
while (scan_it.more_trapezoids())
{
if (scan_it.step())
goto mem_error;
func.clear_state();
for (Gcalc_trapezoid_iterator ti(&scan_it); ti.more(); ++ti)
{
gcalc_shape_info si= ti.lb()->get_shape();
if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
{
func.invert_state(si);
cur_func= func.count();
}
if (cur_func)
{
area= scan_it.get_h() *
((ti.rb()->x - ti.lb()->x) + (ti.rt()->x - ti.lt()->x));
if (area > GIS_ZERO)
{
result= 0;
goto exit;
}
}
}
}
result= 1;
exit:
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(result);
mem_error:
null_value= 1;
DBUG_RETURN(0);
}
int Item_func_spatial_rel::func_equals()
{
Gcalc_heap::Info *pi_s1, *pi_s2;
Gcalc_heap::Info *cur_pi= collector.get_first();
double d;
if (!cur_pi)
return 1;
do {
pi_s1= cur_pi;
pi_s2= 0;
while ((cur_pi= cur_pi->get_next()))
{
d= fabs(pi_s1->x - cur_pi->x) + fabs(pi_s1->y - cur_pi->y);
if (d > GIS_ZERO)
break;
if (!pi_s2 && pi_s1->shape != cur_pi->shape)
pi_s2= cur_pi;
}
if (!pi_s2)
return 0;
} while (cur_pi);
return 1;
}
longlong Item_func_spatial_rel::val_int()
{
DBUG_ENTER("Item_func_spatial_rel::val_int");
DBUG_ASSERT(fixed == 1);
String *res1;
String *res2;
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
int result= 0;
int mask= 0;
if (spatial_rel == SP_TOUCHES_FUNC)
DBUG_RETURN(func_touches());
res1= args[0]->val_str(&tmp_value1);
res2= args[1]->val_str(&tmp_value2);
Gcalc_operation_transporter trn(&func, &collector);
if (func.reserve_op_buffer(1))
DBUG_RETURN(0);
switch (spatial_rel) {
case SP_CONTAINS_FUNC:
mask= 1;
func.add_operation(Gcalc_function::op_backdifference, 2);
break;
case SP_WITHIN_FUNC:
mask= 1;
func.add_operation(Gcalc_function::op_difference, 2);
break;
case SP_EQUALS_FUNC:
break;
case SP_DISJOINT_FUNC:
mask= 1;
func.add_operation(Gcalc_function::op_intersection, 2);
break;
case SP_INTERSECTS_FUNC:
func.add_operation(Gcalc_function::op_intersection, 2);
break;
case SP_OVERLAPS_FUNC:
func.add_operation(Gcalc_function::op_backdifference, 2);
break;
case SP_CROSSES_FUNC:
func.add_operation(Gcalc_function::op_intersection, 2);
break;
default:
DBUG_ASSERT(FALSE);
break;
}
if ((null_value=
(args[0]->null_value || args[1]->null_value ||
!(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) ||
!(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) ||
g1->store_shapes(&trn) || g2->store_shapes(&trn))))
goto exit;
collector.prepare_operation();
scan_it.init(&collector);
if (spatial_rel == SP_EQUALS_FUNC)
{
result= (g1->get_class_info()->m_type_id == g1->get_class_info()->m_type_id) &&
func_equals();
goto exit;
}
if (func.alloc_states())
goto exit;
result= func.find_function(scan_it) ^ mask;
exit:
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(result);
}
Item_func_spatial_operation::~Item_func_spatial_operation()
{
}
String *Item_func_spatial_operation::val_str(String *str_value)
{
DBUG_ENTER("Item_func_spatial_operation::val_str");
DBUG_ASSERT(fixed == 1);
String *res1= args[0]->val_str(&tmp_value1);
String *res2= args[1]->val_str(&tmp_value2);
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
uint32 srid= 0;
Gcalc_operation_transporter trn(&func, &collector);
if (func.reserve_op_buffer(1))
DBUG_RETURN(0);
func.add_operation(spatial_op, 2);
if ((null_value=
(args[0]->null_value || args[1]->null_value ||
!(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) ||
!(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) ||
g1->store_shapes(&trn) || g2->store_shapes(&trn))))
goto exit;
collector.prepare_operation();
scan_it.init(&collector);
if (func.alloc_states())
goto exit;
operation.init(&func);
if (operation.count_all(&collector) ||
operation.get_result(&res_receiver))
goto exit;
str_value->set_charset(&my_charset_bin);
if (str_value->reserve(SRID_SIZE, 512))
goto exit;
str_value->length(0);
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer1, str_value, res_receiver))
goto exit;
exit:
collector.reset();
func.reset();
scan_it.reset();
res_receiver.reset();
DBUG_RETURN(str_value);
}
const char *Item_func_spatial_operation::func_name() const
{
switch (spatial_op) {
case Gcalc_function::op_intersection:
return "st_intersection";
case Gcalc_function::op_difference:
return "st_difference";
case Gcalc_function::op_union:
return "st_union";
case Gcalc_function::op_symdifference:
return "st_symdifference";
default:
DBUG_ASSERT(0); // Should never happen
return "sp_unknown";
}
}
static const int SINUSES_CALCULATED= 32;
static double n_sinus[SINUSES_CALCULATED+1]=
{
0,
0.04906767432741802,
0.0980171403295606,
0.1467304744553618,
0.1950903220161283,
0.2429801799032639,
0.2902846772544623,
0.3368898533922201,
0.3826834323650898,
0.4275550934302821,
0.4713967368259976,
0.5141027441932217,
0.5555702330196022,
0.5956993044924334,
0.6343932841636455,
0.6715589548470183,
0.7071067811865475,
0.7409511253549591,
0.773010453362737,
0.8032075314806448,
0.8314696123025452,
0.8577286100002721,
0.8819212643483549,
0.9039892931234433,
0.9238795325112867,
0.9415440651830208,
0.9569403357322089,
0.970031253194544,
0.9807852804032304,
0.989176509964781,
0.9951847266721968,
0.9987954562051724,
1
};
static void get_n_sincos(int n, double *sinus, double *cosinus)
{
DBUG_ASSERT(n > 0 && n < SINUSES_CALCULATED*2+1);
if (n < (SINUSES_CALCULATED + 1))
{
*sinus= n_sinus[n];
*cosinus= n_sinus[SINUSES_CALCULATED - n];
}
else
{
n-= SINUSES_CALCULATED;
*sinus= n_sinus[SINUSES_CALCULATED - n];
*cosinus= -n_sinus[n];
}
}
static int fill_half_circle(Gcalc_shape_transporter *trn, double x, double y,
double ax, double ay)
{
double n_sin, n_cos;
double x_n, y_n;
for (int n = 1; n < (SINUSES_CALCULATED * 2 - 1); n++)
{
get_n_sincos(n, &n_sin, &n_cos);
x_n= ax * n_cos - ay * n_sin;
y_n= ax * n_sin + ay * n_cos;
if (trn->add_point(x_n + x, y_n + y))
return 1;
}
return 0;
}
static int fill_gap(Gcalc_shape_transporter *trn,
double x, double y,
double ax, double ay, double bx, double by, double d,
bool *empty_gap)
{
double ab= ax * bx + ay * by;
double cosab= ab / (d * d) + GIS_ZERO;
double n_sin, n_cos;
double x_n, y_n;
int n=1;
*empty_gap= true;
for (;;)
{
get_n_sincos(n++, &n_sin, &n_cos);
if (n_cos <= cosab)
break;
*empty_gap= false;
x_n= ax * n_cos - ay * n_sin;
y_n= ax * n_sin + ay * n_cos;
if (trn->add_point(x_n + x, y_n + y))
return 1;
}
return 0;
}
/*
Calculates the vector (p2,p1) and
negatively orthogonal to it with the length of d.
The result is (ex,ey) - the vector, (px,py) - the orthogonal.
*/
static void calculate_perpendicular(
double x1, double y1, double x2, double y2, double d,
double *ex, double *ey,
double *px, double *py)
{
double q;
*ex= x1 - x2;
*ey= y1 - y2;
q= d / sqrt((*ex) * (*ex) + (*ey) * (*ey));
*px= (*ey) * q;
*py= -(*ex) * q;
}
int Item_func_buffer::Transporter::single_point(double x, double y)
{
return add_point_buffer(x, y);
}
int Item_func_buffer::Transporter::add_edge_buffer(
double x3, double y3, bool round_p1, bool round_p2)
{
Gcalc_operation_transporter trn(m_fn, m_heap);
double e1_x, e1_y, e2_x, e2_y, p1_x, p1_y, p2_x, p2_y;
double e1e2;
double sin1, cos1;
double x_n, y_n;
bool empty_gap1, empty_gap2;
++m_nshapes;
if (trn.start_simple_poly())
return 1;
calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
calculate_perpendicular(x3, y3, x2, y2, m_d, &e2_x, &e2_y, &p2_x, &p2_y);
e1e2= e1_x * e2_y - e2_x * e1_y;
sin1= n_sinus[1];
cos1= n_sinus[31];
if (e1e2 < 0)
{
empty_gap2= false;
x_n= x2 + p2_x * cos1 - p2_y * sin1;
y_n= y2 + p2_y * cos1 + p2_x * sin1;
if (fill_gap(&trn, x2, y2, -p1_x,-p1_y, p2_x,p2_y, m_d, &empty_gap1) ||
trn.add_point(x2 + p2_x, y2 + p2_y) ||
trn.add_point(x_n, y_n))
return 1;
}
else
{
x_n= x2 - p2_x * cos1 - p2_y * sin1;
y_n= y2 - p2_y * cos1 + p2_x * sin1;
if (trn.add_point(x_n, y_n) ||
trn.add_point(x2 - p2_x, y2 - p2_y) ||
fill_gap(&trn, x2, y2, -p2_x, -p2_y, p1_x, p1_y, m_d, &empty_gap2))
return 1;
empty_gap1= false;
}
if ((!empty_gap2 && trn.add_point(x2 + p1_x, y2 + p1_y)) ||
trn.add_point(x1 + p1_x, y1 + p1_y))
return 1;
if (round_p1 && fill_half_circle(&trn, x1, y1, p1_x, p1_y))
return 1;
if (trn.add_point(x1 - p1_x, y1 - p1_y) ||
(!empty_gap1 && trn.add_point(x2 - p1_x, y2 - p1_y)))
return 1;
return trn.complete_simple_poly();
}
int Item_func_buffer::Transporter::add_last_edge_buffer()
{
Gcalc_operation_transporter trn(m_fn, m_heap);
double e1_x, e1_y, p1_x, p1_y;
++m_nshapes;
if (trn.start_simple_poly())
return 1;
calculate_perpendicular(x1, y1, x2, y2, m_d, &e1_x, &e1_y, &p1_x, &p1_y);
if (trn.add_point(x1 + p1_x, y1 + p1_y) ||
trn.add_point(x1 - p1_x, y1 - p1_y) ||
trn.add_point(x2 - p1_x, y2 - p1_y) ||
fill_half_circle(&trn, x2, y2, -p1_x, -p1_y) ||
trn.add_point(x2 + p1_x, y2 + p1_y))
return 1;
return trn.complete_simple_poly();
}
int Item_func_buffer::Transporter::add_point_buffer(double x, double y)
{
Gcalc_operation_transporter trn(m_fn, m_heap);
m_nshapes++;
if (trn.start_simple_poly())
return 1;
if (trn.add_point(x - m_d, y) ||
fill_half_circle(&trn, x, y, -m_d, 0.0) ||
trn.add_point(x + m_d, y) ||
fill_half_circle(&trn, x, y, m_d, 0.0))
return 1;
return trn.complete_simple_poly();
}
int Item_func_buffer::Transporter::start_line()
{
m_npoints= 0;
int_start_line();
return 0;
}
int Item_func_buffer::Transporter::start_poly()
{
++m_nshapes;
return Gcalc_operation_transporter::start_poly();
}
int Item_func_buffer::Transporter::start_ring()
{
m_npoints= 0;
return Gcalc_operation_transporter::start_ring();
}
int Item_func_buffer::Transporter::add_point(double x, double y)
{
if (m_npoints && x == x2 && y == y2)
return 0;
++m_npoints;
if (m_npoints == 1)
{
x00= x;
y00= y;
}
else if (m_npoints == 2)
{
x01= x;
y01= y;
}
else if (add_edge_buffer(x, y, (m_npoints == 3) && line_started(), false))
return 1;
x1= x2;
y1= y2;
x2= x;
y2= y;
return line_started() ? 0 : Gcalc_operation_transporter::add_point(x, y);
}
int Item_func_buffer::Transporter::complete()
{
if (m_npoints)
{
if (m_npoints == 1)
{
if (add_point_buffer(x2, y2))
return 1;
}
else if (m_npoints == 2)
{
if (add_edge_buffer(x1, y1, true, true))
return 1;
}
else if (line_started())
{
if (add_last_edge_buffer())
return 1;
}
else
{
if (x2 != x00 && y2 != y00)
{
if (add_edge_buffer(x00, y00, false, false))
return 1;
x1= x2;
y1= y2;
x2= x00;
y2= y00;
}
if (add_edge_buffer(x01, y01, false, false))
return 1;
}
}
return 0;
}
int Item_func_buffer::Transporter::complete_line()
{
if (complete())
return 1;
int_complete_line();
return 0;
}
int Item_func_buffer::Transporter::complete_ring()
{
return complete() ||
Gcalc_operation_transporter::complete_ring();
}
String *Item_func_buffer::val_str(String *str_value)
{
DBUG_ENTER("Item_func_buffer::val_str");
DBUG_ASSERT(fixed == 1);
String *obj= args[0]->val_str(&tmp_value);
double dist= args[1]->val_real();
Geometry_buffer buffer;
Geometry *g;
uint32 union_pos;
uint32 srid= 0;
String *str_result= NULL;
Transporter trn(&func, &collector, dist);
null_value= 1;
if (args[0]->null_value || args[1]->null_value ||
!(g= Geometry::construct(&buffer, obj->ptr(), obj->length())))
goto mem_error;
if (func.reserve_op_buffer(2))
goto mem_error;
/* will specify operands later */
union_pos= func.get_next_operation_pos();
func.add_operation((dist > 0.0) ? Gcalc_function::op_union :
Gcalc_function::op_difference, 0);
if (g->store_shapes(&trn))
goto mem_error;
func.add_operands_to_op(union_pos, trn.m_nshapes);
collector.prepare_operation();
if (func.alloc_states())
goto mem_error;
operation.init(&func);
if (operation.count_all(&collector) ||
operation.get_result(&res_receiver))
goto mem_error;
str_value->set_charset(&my_charset_bin);
if (str_value->reserve(SRID_SIZE, 512))
goto mem_error;
str_value->length(0);
str_value->q_append(srid);
if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver))
goto mem_error;
null_value= 0;
str_result= str_value;
mem_error:
collector.reset();
func.reset();
scan_it.reset();
res_receiver.reset();
DBUG_RETURN(str_result);
}
longlong Item_func_isempty::val_int()
{
DBUG_ASSERT(fixed == 1);
......@@ -566,20 +1460,50 @@ longlong Item_func_isempty::val_int()
}
/**
@todo
Ramil or Holyfoot, add real IsSimple calculation
*/
longlong Item_func_issimple::val_int()
{
DBUG_ASSERT(fixed == 1);
String tmp;
String *swkb= args[0]->val_str(&tmp);
Geometry_buffer buffer;
Gcalc_operation_transporter trn(&func, &collector);
Geometry *g;
int result= 1;
null_value= args[0]->null_value ||
!(Geometry::construct(&buffer, swkb->ptr(), swkb->length()));
/* TODO: Ramil or Holyfoot, add real IsSimple calculation */
DBUG_ENTER("Item_func_issimple::val_int");
DBUG_ASSERT(fixed == 1);
if ((null_value= args[0]->null_value) ||
!(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))
DBUG_RETURN(0);
if (g->get_class_info()->m_type_id == Geometry::wkb_point)
DBUG_RETURN(1);
if (g->store_shapes(&trn))
goto mem_error;
collector.prepare_operation();
scan_it.init(&collector);
while (scan_it.more_points())
{
if (scan_it.step())
goto mem_error;
if (scan_it.get_event() == scev_intersection)
{
result= 0;
break;
}
}
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(result);
mem_error:
null_value= 1;
DBUG_RETURN(0);
return 0;
}
......@@ -752,4 +1676,160 @@ longlong Item_func_srid::val_int()
return (longlong) (uint4korr(swkb->ptr()));
}
double Item_func_distance::val_real()
{
bool above_cur_point, cur_point_edge;
const Gcalc_scan_iterator::point *evpos;
const Gcalc_heap::Info *cur_point, *dist_point;
Gcalc_scan_events ev;
double t, distance, cur_distance;
double x1, x2, y1, y2;
double ex, ey, vx, vy, e_sqrlen;
uint obj2_si;
Gcalc_operation_transporter trn(&func, &collector);
DBUG_ENTER("Item_func_distance::val_real");
DBUG_ASSERT(fixed == 1);
String *res1= args[0]->val_str(&tmp_value1);
String *res2= args[1]->val_str(&tmp_value2);
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
if ((null_value= (args[0]->null_value || args[1]->null_value ||
!(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) ||
!(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())))))
goto mem_error;
if ((g1->get_class_info()->m_type_id == Geometry::wkb_point) &&
(g2->get_class_info()->m_type_id == Geometry::wkb_point))
{
if (((Gis_point *) g1)->get_xy(&x1, &y1) ||
((Gis_point *) g2)->get_xy(&x2, &y2))
goto mem_error;
ex= x2 - x1;
ey= y2 - y1;
DBUG_RETURN(sqrt(ex * ex + ey * ey));
}
if (func.reserve_op_buffer(1))
goto mem_error;
func.add_operation(Gcalc_function::op_intersection, 2);
if (g1->store_shapes(&trn))
goto mem_error;
obj2_si= func.get_nshapes();
if (g2->store_shapes(&trn) || func.alloc_states())
goto mem_error;
collector.prepare_operation();
scan_it.init(&collector);
above_cur_point= false;
distance= DBL_MAX;
while (scan_it.more_points())
{
if (scan_it.step())
goto mem_error;
evpos= scan_it.get_event_position();
ev= scan_it.get_event();
cur_point= evpos->pi;
/*
handling intersection we only need to check if it's the intersecion
of objects 1 and 2. In this case distance is 0
*/
if (ev == scev_intersection)
{
if ((evpos->get_next()->pi->shape >= obj2_si) !=
(cur_point->shape >= obj2_si))
{
distance= 0;
goto exit;
}
continue;
}
/*
if we get 'scev_point | scev_end | scev_two_ends' we don't need
to check for intersection of objects.
Though we need to calculate distances.
*/
if (ev & (scev_point | scev_end | scev_two_ends))
goto count_distance;
/*
having these events we need to check for possible intersection
of objects
scev_thread | scev_two_threads | scev_single_point
*/
DBUG_ASSERT(ev & (scev_thread | scev_two_threads | scev_single_point));
func.clear_state();
for (Gcalc_point_iterator pit(&scan_it); pit.point() != evpos; ++pit)
{
gcalc_shape_info si= pit.point()->get_shape();
if ((func.get_shape_kind(si) == Gcalc_function::shape_polygon))
func.invert_state(si);
}
func.invert_state(evpos->get_shape());
if (func.count())
{
/* Point of one object is inside the other - intersection found */
distance= 0;
goto exit;
}
count_distance:
if (cur_point->shape >= obj2_si)
continue;
cur_point_edge= !cur_point->is_bottom();
for (dist_point= collector.get_first(); dist_point; dist_point= dist_point->get_next())
{
/* We only check vertices of object 2 */
if (dist_point->shape < obj2_si)
continue;
/* if we have an edge to check */
if (dist_point->left)
{
t= count_edge_t(dist_point, dist_point->left, cur_point,
ex, ey, vx, vy, e_sqrlen);
if ((t>0.0) && (t<1.0))
{
cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
if (distance > cur_distance)
distance= cur_distance;
}
}
if (cur_point_edge)
{
t= count_edge_t(cur_point, cur_point->left, dist_point,
ex, ey, vx, vy, e_sqrlen);
if ((t>0.0) && (t<1.0))
{
cur_distance= distance_to_line(ex, ey, vx, vy, e_sqrlen);
if (distance > cur_distance)
distance= cur_distance;
}
}
cur_distance= distance_points(cur_point, dist_point);
if (distance > cur_distance)
distance= cur_distance;
}
}
exit:
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(distance);
mem_error:
null_value= 1;
DBUG_RETURN(0);
}
#endif /*HAVE_SPATIAL*/
/* Copyright (c) 2003, 2011, Oracle and/or its affiliates.
#ifndef ITEM_GEOFUNC_INCLUDED
#define ITEM_GEOFUNC_INCLUDED
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -10,8 +13,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/* This file defines all spatial functions */
......@@ -22,6 +25,8 @@
#pragma interface /* gcc class implementation */
#endif
#include "gcalc_slicescan.h"
class Item_geometry_func: public Item_str_func
{
public:
......@@ -41,7 +46,7 @@ class Item_func_geometry_from_text: public Item_geometry_func
public:
Item_func_geometry_from_text(Item *a) :Item_geometry_func(a) {}
Item_func_geometry_from_text(Item *a, Item *srid) :Item_geometry_func(a, srid) {}
const char *func_name() const { return "geometryfromtext"; }
const char *func_name() const { return "st_geometryfromtext"; }
String *val_str(String *);
};
......@@ -50,7 +55,7 @@ class Item_func_geometry_from_wkb: public Item_geometry_func
public:
Item_func_geometry_from_wkb(Item *a): Item_geometry_func(a) {}
Item_func_geometry_from_wkb(Item *a, Item *srid): Item_geometry_func(a, srid) {}
const char *func_name() const { return "geometryfromwkb"; }
const char *func_name() const { return "st_geometryfromwkb"; }
String *val_str(String *);
};
......@@ -58,7 +63,7 @@ class Item_func_as_wkt: public Item_str_func
{
public:
Item_func_as_wkt(Item *a): Item_str_func(a) {}
const char *func_name() const { return "astext"; }
const char *func_name() const { return "st_astext"; }
String *val_str(String *);
void fix_length_and_dec();
};
......@@ -67,7 +72,7 @@ class Item_func_as_wkb: public Item_geometry_func
{
public:
Item_func_as_wkb(Item *a): Item_geometry_func(a) {}
const char *func_name() const { return "aswkb"; }
const char *func_name() const { return "st_aswkb"; }
String *val_str(String *);
enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
};
......@@ -77,10 +82,11 @@ 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"; }
const char *func_name() const { return "st_geometrytype"; }
void fix_length_and_dec()
{
max_length=20; // "GeometryCollection" is the most long
// "GeometryCollection" is the longest
max_length= 20;
maybe_null= 1;
};
};
......@@ -89,7 +95,7 @@ class Item_func_centroid: public Item_geometry_func
{
public:
Item_func_centroid(Item *a): Item_geometry_func(a) {}
const char *func_name() const { return "centroid"; }
const char *func_name() const { return "st_centroid"; }
String *val_str(String *);
Field::geometry_type get_geometry_type() const;
};
......@@ -98,7 +104,7 @@ class Item_func_envelope: public Item_geometry_func
{
public:
Item_func_envelope(Item *a): Item_geometry_func(a) {}
const char *func_name() const { return "envelope"; }
const char *func_name() const { return "st_envelope"; }
String *val_str(String *);
Field::geometry_type get_geometry_type() const;
};
......@@ -108,7 +114,7 @@ class Item_func_point: public Item_geometry_func
public:
Item_func_point(Item *a, Item *b): Item_geometry_func(a, b) {}
Item_func_point(Item *a, Item *b, Item *srid): Item_geometry_func(a, b, srid) {}
const char *func_name() const { return "point"; }
const char *func_name() const { return "st_point"; }
String *val_str(String *);
Field::geometry_type get_geometry_type() const;
};
......@@ -124,11 +130,11 @@ class Item_func_spatial_decomp: public Item_geometry_func
switch (decomp_func)
{
case SP_STARTPOINT:
return "startpoint";
return "st_startpoint";
case SP_ENDPOINT:
return "endpoint";
return "st_endpoint";
case SP_EXTERIORRING:
return "exteriorring";
return "st_exteriorring";
default:
DBUG_ASSERT(0); // Should never happened
return "spatial_decomp_unknown";
......@@ -148,11 +154,11 @@ class Item_func_spatial_decomp_n: public Item_geometry_func
switch (decomp_func_n)
{
case SP_POINTN:
return "pointn";
return "st_pointn";
case SP_GEOMETRYN:
return "geometryn";
return "st_geometryn";
case SP_INTERIORRINGN:
return "interiorringn";
return "st_interiorringn";
default:
DBUG_ASSERT(0); // Should never happened
return "spatial_decomp_n_unknown";
......@@ -177,7 +183,6 @@ class Item_func_spatial_collection: public Item_geometry_func
String *val_str(String *);
void fix_length_and_dec()
{
Item_geometry_func::fix_length_and_dec();
for (unsigned int i= 0; i < arg_count; ++i)
{
if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY)
......@@ -191,57 +196,53 @@ class Item_func_spatial_collection: public Item_geometry_func
}
}
const char *func_name() const { return "multipoint"; }
const char *func_name() const { return "st_multipoint"; }
};
/*
Spatial relations
*/
class Item_func_spatial_rel: public Item_bool_func2
class Item_func_spatial_mbr_rel: public Item_bool_func2
{
enum Functype spatial_rel;
public:
Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) :
Item_func_spatial_mbr_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
const char *func_name() const;
virtual inline void print(String *str, enum_query_type query_type)
{
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:
DBUG_ASSERT(0); // Should never happened
return "sp_unknown";
}
Item_func::print(str, query_type);
}
void fix_length_and_dec() { maybe_null= 1; }
bool is_null() { (void) val_int(); return null_value; }
};
class Item_func_spatial_rel: public Item_bool_func2
{
enum Functype spatial_rel;
Gcalc_heap collector;
Gcalc_scan_iterator scan_it;
Gcalc_function func;
String tmp_value1,tmp_value2;
public:
Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel);
virtual ~Item_func_spatial_rel();
longlong val_int();
enum Functype functype() const
{
return spatial_rel;
}
enum Functype rev_functype() const { return spatial_rel; }
const char *func_name() const;
virtual inline void print(String *str, enum_query_type query_type)
{
Item_func::print(str, query_type);
......@@ -249,25 +250,104 @@ class Item_func_spatial_rel: public Item_bool_func2
void fix_length_and_dec() { maybe_null= 1; }
bool is_null() { (void) val_int(); return null_value; }
protected:
int func_touches();
int func_equals();
};
/*
Spatial operations
*/
class Item_func_spatial_operation: public Item_geometry_func
{
public:
Gcalc_function::op_type spatial_op;
Gcalc_heap collector;
Gcalc_function func;
Gcalc_scan_iterator scan_it;
Gcalc_result_receiver res_receiver;
Gcalc_operation_reducer operation;
String tmp_value1,tmp_value2;
public:
Item_func_spatial_operation(Item *a,Item *b, Gcalc_function::op_type sp_op) :
Item_geometry_func(a, b), spatial_op(sp_op)
{}
virtual ~Item_func_spatial_operation();
String *val_str(String *);
const char *func_name() const;
virtual inline void print(String *str, enum_query_type query_type)
{
Item_func::print(str, query_type);
}
};
class Item_func_buffer: public Item_geometry_func
{
protected:
class Transporter : public Gcalc_operation_transporter
{
int m_npoints;
double m_d;
double x1,y1,x2,y2;
double x00,y00,x01,y01;
int add_edge_buffer(double x3, double y3, bool round_p1, bool round_p2);
int add_last_edge_buffer();
int add_point_buffer(double x, double y);
int complete();
public:
int m_nshapes;
Transporter(Gcalc_function *fn, Gcalc_heap *heap, double d) :
Gcalc_operation_transporter(fn, heap), m_npoints(0), m_d(d), m_nshapes(0)
{}
int single_point(double x, double y);
int start_line();
int complete_line();
int start_poly();
int start_ring();
int complete_ring();
int add_point(double x, double y);
};
Gcalc_heap collector;
Gcalc_function func;
Gcalc_scan_iterator scan_it;
Gcalc_result_receiver res_receiver;
Gcalc_operation_reducer operation;
String tmp_value;
public:
Item_func_buffer(Item *obj, Item *distance):
Item_geometry_func(obj, distance) {}
const char *func_name() const { return "st_buffer"; }
String *val_str(String *);
};
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"; }
const char *func_name() const { return "st_isempty"; }
void fix_length_and_dec() { maybe_null= 1; }
};
class Item_func_issimple: public Item_bool_func
{
Gcalc_heap collector;
Gcalc_function func;
Gcalc_scan_iterator scan_it;
String tmp;
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"; }
const char *func_name() const { return "st_issimple"; }
void fix_length_and_dec() { maybe_null= 1; }
};
......@@ -277,7 +357,7 @@ class Item_func_isclosed: public Item_bool_func
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"; }
const char *func_name() const { return "st_isclosed"; }
void fix_length_and_dec() { maybe_null= 1; }
};
......@@ -287,7 +367,7 @@ class Item_func_dimension: public Item_int_func
public:
Item_func_dimension(Item *a): Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "dimension"; }
const char *func_name() const { return "st_dimension"; }
void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
......@@ -297,7 +377,7 @@ class Item_func_x: public Item_real_func
public:
Item_func_x(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "x"; }
const char *func_name() const { return "st_x"; }
void fix_length_and_dec()
{
Item_real_func::fix_length_and_dec();
......@@ -312,7 +392,7 @@ class Item_func_y: public Item_real_func
public:
Item_func_y(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "y"; }
const char *func_name() const { return "st_y"; }
void fix_length_and_dec()
{
Item_real_func::fix_length_and_dec();
......@@ -327,7 +407,7 @@ class Item_func_numgeometries: public Item_int_func
public:
Item_func_numgeometries(Item *a): Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "numgeometries"; }
const char *func_name() const { return "st_numgeometries"; }
void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
......@@ -338,7 +418,7 @@ class Item_func_numinteriorring: public Item_int_func
public:
Item_func_numinteriorring(Item *a): Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "numinteriorrings"; }
const char *func_name() const { return "st_numinteriorrings"; }
void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
......@@ -349,7 +429,7 @@ class Item_func_numpoints: public Item_int_func
public:
Item_func_numpoints(Item *a): Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "numpoints"; }
const char *func_name() const { return "st_numpoints"; }
void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
......@@ -360,7 +440,7 @@ class Item_func_area: public Item_real_func
public:
Item_func_area(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "area"; }
const char *func_name() const { return "st_area"; }
void fix_length_and_dec()
{
Item_real_func::fix_length_and_dec();
......@@ -375,7 +455,7 @@ class Item_func_glength: public Item_real_func
public:
Item_func_glength(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "glength"; }
const char *func_name() const { return "st_length"; }
void fix_length_and_dec()
{
Item_real_func::fix_length_and_dec();
......@@ -394,11 +474,26 @@ class Item_func_srid: public Item_int_func
void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
class Item_func_distance: public Item_real_func
{
String tmp_value1;
String tmp_value2;
Gcalc_heap collector;
Gcalc_function func;
Gcalc_scan_iterator scan_it;
public:
Item_func_distance(Item *a, Item *b): Item_real_func(a, b) {}
double val_real();
const char *func_name() const { return "st_distance"; }
};
#define GEOM_NEW(thd, obj_constructor) new (thd->mem_root) obj_constructor
#else /*HAVE_SPATIAL*/
#define GEOM_NEW(thd, obj_constructor) NULL
#endif
#endif /*HAVE_SPATIAL*/
#endif /*ITEM_GEOFUNC_INCLUDED*/
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
things to define before including the file:
#define LS_LIST_ITEM ListItem
#define LS_COMPARE_FUNC_DECL compare_func var_name,
#define LS_COMPARE_FUNC_CALL(list_el1, list_el2) (*var_name)(list_el1, list_el2)
#define LS_NEXT(A) (A)->next
#define LS_SET_NEXT(A,val) (A)->next= val
#define LS_P_NEXT(A) &(A)->next
#define LS_NAME plistsort
#define LS_SCOPE static
#define LS_STRUCT_NAME ls_struct_name
*/
typedef struct LS_STRUCT_NAME
{
LS_LIST_ITEM *list1;
int list_len;
int return_point;
} LS_STRUCT_NAME;
LS_SCOPE LS_LIST_ITEM* LS_NAME(LS_COMPARE_FUNC_DECL LS_LIST_ITEM *list, int list_len)
{
LS_LIST_ITEM *list_end;
LS_LIST_ITEM *sorted_list;
struct LS_STRUCT_NAME stack[63], *sp= stack;
if (list_len < 2)
return list;
sp->list_len= list_len;
sp->return_point= 2;
recursion_point:
if (sp->list_len < 4)
{
LS_LIST_ITEM *e1, *e2;
sorted_list= list;
e1= LS_NEXT(sorted_list);
list_end= LS_NEXT(e1);
if (LS_COMPARE_FUNC_CALL(sorted_list, e1))
{
sorted_list= e1;
e1= list;
}
if (sp->list_len == 2)
{
LS_SET_NEXT(sorted_list, e1);
LS_SET_NEXT(e1, NULL);
goto exit_point;
}
e2= list_end;
list_end= LS_NEXT(e2);
if (LS_COMPARE_FUNC_CALL(e1, e2))
{
{
LS_LIST_ITEM *tmp_e= e1;
e1= e2;
e2= tmp_e;
}
if (LS_COMPARE_FUNC_CALL(sorted_list, e1))
{
LS_LIST_ITEM *tmp_e= sorted_list;
sorted_list= e1;
e1= tmp_e;
}
}
LS_SET_NEXT(sorted_list, e1);
LS_SET_NEXT(e1, e2);
LS_SET_NEXT(e2, NULL);
goto exit_point;
}
{
register struct LS_STRUCT_NAME *sp0= sp++;
sp->list_len= sp0->list_len >> 1;
sp0->list_len-= sp->list_len;
sp->return_point= 0;
}
goto recursion_point;
return_point0:
sp->list1= sorted_list;
{
register struct LS_STRUCT_NAME *sp0= sp++;
list= list_end;
sp->list_len= sp0->list_len;
sp->return_point= 1;
}
goto recursion_point;
return_point1:
{
register LS_LIST_ITEM **hook= &sorted_list;
register LS_LIST_ITEM *list1= sp->list1;
register LS_LIST_ITEM *list2= sorted_list;
if (LS_COMPARE_FUNC_CALL(list1, list2))
{
LS_LIST_ITEM *tmp_e= list2;
list2= list1;
list1= tmp_e;
}
for (;;)
{
*hook= list1;
do
{
if (!(list1= *(hook= LS_P_NEXT(list1))))
{
*hook= list2;
goto exit_point;
}
} while (LS_COMPARE_FUNC_CALL(list2, list1));
*hook= list2;
do
{
if (!(list2= *(hook= LS_P_NEXT(list2))))
{
*hook= list1;
goto exit_point;
}
} while (LS_COMPARE_FUNC_CALL(list1, list2));
}
}
exit_point:
switch ((sp--)->return_point)
{
case 0: goto return_point0;
case 1: goto return_point1;
default:;
}
return sorted_list;
}
#undef LS_LIST_ITEM
#undef LS_NEXT
#undef LS_SET_NEXT
#undef LS_P_NEXT
#undef LS_NAME
#undef LS_STRUCT_NAME
#undef LS_SCOPE
#undef LS_COMPARE_FUNC_DECL
#undef LS_COMPARE_FUNC_CALL
/* Copyright (C) 2004 MySQL AB
/* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -10,8 +10,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
#include "mysql_priv.h"
......@@ -38,7 +38,7 @@
17
*/
#define MAX_DIGITS_IN_DOUBLE 22
#define MAX_DIGITS_IN_DOUBLE 30
/***************************** Gis_class_info *******************************/
......@@ -264,12 +264,28 @@ Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
}
int Geometry::create_from_opresult(Geometry_buffer *g_buf,
String *res, Gcalc_result_receiver &rr)
{
uint32 geom_type= rr.get_result_typeid();
Geometry *obj= create_by_typeid(g_buf, geom_type);
if (!obj || res->reserve(WKB_HEADER_SIZE, 512))
return 1;
res->q_append((char) wkb_ndr);
res->q_append(geom_type);
return obj->init_from_opresult(res, rr.result(), rr.get_nshapes());
}
bool Geometry::envelope(String *result) const
{
MBR mbr;
const char *end;
if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10))
if (get_mbr(&mbr, &end) ||
result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10))
return 1;
result->q_append((char) wkb_ndr);
......@@ -306,13 +322,13 @@ bool Geometry::envelope(String *result) const
bool Geometry::create_point(String *result, const char *data) const
{
if (no_data(data, SIZEOF_STORED_DOUBLE * 2) ||
result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
if (no_data(data, POINT_DATA_SIZE) ||
result->reserve(1 + 4 + POINT_DATA_SIZE))
return 1;
result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_point);
/* Copy two double in same format */
result->q_append(data, SIZEOF_STORED_DOUBLE*2);
result->q_append(data, POINT_DATA_SIZE);
return 0;
}
......@@ -332,7 +348,7 @@ bool Geometry::create_point(String *result, const char *data) const
bool Geometry::create_point(String *result, double x, double y) const
{
if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2))
if (result->reserve(1 + 4 + POINT_DATA_SIZE))
return 1;
result->q_append((char) wkb_ndr);
......@@ -364,7 +380,7 @@ const char *Geometry::append_points(String *txt, uint32 n_points,
double x,y;
data+= offset;
get_point(&x, &y, data);
data+= SIZEOF_STORED_DOUBLE * 2;
data+= POINT_DATA_SIZE;
txt->qs_append(x);
txt->qs_append(' ');
txt->qs_append(y);
......@@ -399,7 +415,7 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
points= uint4korr(data);
data+= 4;
if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points))
if (no_data(data, (POINT_DATA_SIZE + offset) * points))
return 0;
/* Calculate MBR for points */
......@@ -407,7 +423,7 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
{
data+= offset;
mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE);
data+= SIZEOF_STORED_DOUBLE * 2;
data+= POINT_DATA_SIZE;
}
return data;
}
......@@ -425,7 +441,7 @@ bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
{
double x, y;
if (trs->get_next_number(&x) || trs->get_next_number(&y) ||
wkb->reserve(SIZEOF_STORED_DOUBLE * 2))
wkb->reserve(POINT_DATA_SIZE))
return 1;
wkb->q_append(x);
wkb->q_append(y);
......@@ -472,6 +488,15 @@ bool Gis_point::get_mbr(MBR *mbr, const char **end) const
return 0;
}
int Gis_point::store_shapes(Gcalc_shape_transporter *trn) const
{
double x, y;
return get_xy(&x, &y) || trn->single_point(x, y);
}
const Geometry::Class_info *Gis_point::get_class_info() const
{
return &point_class;
......@@ -523,12 +548,12 @@ uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
const char *wkb_end;
Gis_point p;
if (len < 4)
if (len < 4 ||
(n_points= wkb_get_uint(wkb, bo))<1)
return 0;
n_points= wkb_get_uint(wkb, bo);
proper_length= 4 + n_points * POINT_DATA_SIZE;
if (!n_points || len < proper_length || res->reserve(proper_length))
if (len < proper_length || res->reserve(proper_length))
return 0;
res->q_append(n_points);
......@@ -554,7 +579,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
data += 4;
if (n_points < 1 ||
no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) ||
no_data(data, POINT_DATA_SIZE * n_points) ||
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
return 1;
......@@ -562,7 +587,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
{
double x, y;
get_point(&x, &y, data);
data+= SIZEOF_STORED_DOUBLE * 2;
data+= POINT_DATA_SIZE;
txt->qs_append(x);
txt->qs_append(' ');
txt->qs_append(y);
......@@ -591,17 +616,16 @@ int Gis_line_string::geom_length(double *len) const
return 1;
n_points= uint4korr(data);
data+= 4;
if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points))
return 1;
get_point(&prev_x, &prev_y, data);
data+= SIZEOF_STORED_DOUBLE*2;
data+= POINT_DATA_SIZE;
while (--n_points)
{
double x, y;
get_point(&x, &y, data);
data+= SIZEOF_STORED_DOUBLE * 2;
data+= POINT_DATA_SIZE;
*len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
prev_x= x;
prev_y= y;
......@@ -625,14 +649,14 @@ int Gis_line_string::is_closed(int *closed) const
return 0;
}
data+= 4;
if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
if (no_data(data, POINT_DATA_SIZE * n_points))
return 1;
/* Get first point */
get_point(&x1, &y1, data);
/* get last point */
data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE;
data+= POINT_DATA_SIZE + (n_points-2)*POINT_DATA_SIZE;
get_point(&x2, &y2, data);
*closed= (x1==x2) && (y1==y2);
......@@ -676,6 +700,34 @@ int Gis_line_string::point_n(uint32 num, String *result) const
return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE);
}
int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const
{
uint32 n_points;
double x, y;
const char *data= m_data;
if (no_data(m_data, 4))
return 1;
n_points= uint4korr(data);
data+= 4;
if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points))
return 1;
trn->start_line();
while (n_points--)
{
get_point(&x, &y, data);
data+= POINT_DATA_SIZE;
if (trn->add_point(x, y))
return 1;
}
return trn->complete_line();
}
const Geometry::Class_info *Gis_line_string::get_class_info() const
{
return &linestring_class;
......@@ -737,6 +789,53 @@ bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
uint Gis_polygon::priv_init_from_opresult(String *bin,
const char *opres, uint32 n_shapes,
uint32 *poly_shapes)
{
const char *opres_orig= opres;
uint32 position= bin->length();
*poly_shapes= 0;
if (bin->reserve(4, 512))
return 0;
bin->q_append(*poly_shapes);
while (n_shapes--)
{
uint32 n_points, proper_length;
const char *op_end, *p1_position;
Gis_point p;
Gcalc_function::shape_type st;
st= (Gcalc_function::shape_type) uint4korr(opres);
if (*poly_shapes && st != Gcalc_function::shape_hole)
break;
(*poly_shapes)++;
n_points= uint4korr(opres + 4) + 1; /* skip shape type id */
proper_length= 4 + n_points * POINT_DATA_SIZE;
if (bin->reserve(proper_length, 512))
return 0;
bin->q_append(n_points);
op_end= opres + 8 + (n_points-1) * 8 * 2;
p1_position= (opres+= 8);
for (; opres<op_end; opres+= POINT_DATA_SIZE)
{
if (!p.init_from_wkb(opres, POINT_DATA_SIZE, wkb_ndr, bin))
return 0;
}
if (!p.init_from_wkb(p1_position, POINT_DATA_SIZE, wkb_ndr, bin))
return 0;
}
bin->write_at_position(position, *poly_shapes);
return (uint) (opres - opres_orig);
}
uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
String *res)
{
......@@ -746,9 +845,7 @@ uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
if (len < 4)
return 0;
if (!(n_linear_rings= wkb_get_uint(wkb, bo)))
return 0;
n_linear_rings= wkb_get_uint(wkb, bo);
if (res->reserve(4, 512))
return 0;
wkb+= 4;
......@@ -794,7 +891,7 @@ bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
return 1;
n_points= uint4korr(data);
data+= 4;
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) ||
if (no_data(data, POINT_DATA_SIZE * n_points) ||
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
return 1;
txt->qs_append('(');
......@@ -848,16 +945,16 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const
if (no_data(data, 4))
return 1;
n_points= uint4korr(data);
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
if (no_data(data, POINT_DATA_SIZE * n_points))
return 1;
get_point(&prev_x, &prev_y, data+4);
data+= (4+SIZEOF_STORED_DOUBLE*2);
data+= (4+POINT_DATA_SIZE);
while (--n_points) // One point is already read
{
double x, y;
get_point(&x, &y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
data+= POINT_DATA_SIZE;
lr_area+= (prev_x + x)* (prev_y - y);
prev_x= x;
prev_y= y;
......@@ -884,7 +981,7 @@ int Gis_polygon::exterior_ring(String *result) const
n_points= uint4korr(data);
data+= 4;
length= n_points * POINT_DATA_SIZE;
if (no_data(data, length) || result->reserve(1+4+4+ length))
if (no_data(data, length) || result->reserve(1 + 4 + 4 + length))
return 1;
result->q_append((char) wkb_ndr);
......@@ -930,7 +1027,7 @@ int Gis_polygon::interior_ring_n(uint32 num, String *result) const
n_points= uint4korr(data);
points_size= n_points * POINT_DATA_SIZE;
data+= 4;
if (no_data(data, points_size) || result->reserve(1+4+4+ points_size))
if (no_data(data, points_size) || result->reserve(1 + 4 + 4 + points_size))
return 1;
result->q_append((char) wkb_ndr);
......@@ -969,16 +1066,16 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
return 1;
org_n_points= n_points= uint4korr(data);
data+= 4;
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
if (no_data(data, POINT_DATA_SIZE * n_points))
return 1;
get_point(&prev_x, &prev_y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
data+= POINT_DATA_SIZE;
while (--n_points) // One point is already read
{
double tmp_x, tmp_y;
get_point(&tmp_x, &tmp_y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
data+= POINT_DATA_SIZE;
cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y);
cur_cx+= tmp_x;
cur_cy+= tmp_y;
......@@ -1018,6 +1115,49 @@ int Gis_polygon::centroid(String *result) const
return create_point(result, x, y);
}
int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const
{
uint32 n_linear_rings;
const char *data= m_data;
if (trn->start_poly())
return 1;
if (no_data(data, 4))
return 1;
n_linear_rings= uint4korr(data);
data+= 4;
while (n_linear_rings--)
{
uint32 n_points;
if (no_data(data, 4))
return 1;
n_points= uint4korr(data);
data+= 4;
if (!n_points || no_data(data, POINT_DATA_SIZE * n_points))
return 1;
trn->start_ring();
while (--n_points)
{
double x, y;
get_point(&x, &y, data);
data+= POINT_DATA_SIZE;
if (trn->add_point(x, y))
return 1;
}
data+= POINT_DATA_SIZE;
trn->complete_ring();
}
trn->complete_poly();
return 0;
}
const Geometry::Class_info *Gis_polygon::get_class_info() const
{
return &polygon_class;
......@@ -1046,7 +1186,7 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
for (;;)
{
if (wkb->reserve(1+4, 512))
if (wkb->reserve(1 + 4, 512))
return 1;
wkb->q_append((char) wkb_ndr);
wkb->q_append((uint32) wkb_point);
......@@ -1061,6 +1201,32 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
uint Gis_multi_point::init_from_opresult(String *bin,
const char *opres, uint32 n_shapes)
{
uint bin_size, opres_size;
Gis_point p;
const char *opres_end;
bin_size= n_shapes * (WKB_HEADER_SIZE + POINT_DATA_SIZE) + 4;
opres_size= n_shapes * (4 + 8*2);
if (bin->reserve(bin_size, 512))
return 0;
bin->q_append(n_shapes);
opres_end= opres + opres_size;
for (; opres < opres_end; opres+= (4 + 8*2))
{
bin->q_append((char)wkb_ndr);
bin->q_append((uint32)wkb_point);
if (!p.init_from_wkb(opres + 4, POINT_DATA_SIZE, wkb_ndr, bin))
return 0;
}
return opres_size;
}
uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
String *res)
{
......@@ -1099,7 +1265,7 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
n_points= uint4korr(m_data);
if (no_data(m_data+4,
n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) ||
n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE)) ||
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
return 1;
*end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE);
......@@ -1140,6 +1306,35 @@ int Gis_multi_point::geometry_n(uint32 num, String *result) const
return 0;
}
int Gis_multi_point::store_shapes(Gcalc_shape_transporter *trn) const
{
uint32 n_points;
Gis_point pt;
const char *data= m_data;
if (no_data(data, 4))
return 1;
n_points= uint4korr(data);
data+= 4;
if (trn->start_collection(n_points))
return 1;
while (n_points--)
{
if (no_data(data, WKB_HEADER_SIZE))
return 1;
data+= WKB_HEADER_SIZE;
pt.set_data_ptr(data, (uint32) (m_data_end - data));
if (pt.store_shapes(trn))
return 1;
data+= pt.get_data_size();
}
return 0;
}
const Geometry::Class_info *Gis_multi_point::get_class_info() const
{
return &multipoint_class;
......@@ -1182,10 +1377,9 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
{
Gis_line_string ls;
if (wkb->reserve(1+4, 512))
if (wkb->reserve(1 + 4, 512))
return 1;
wkb->q_append((char) wkb_ndr);
wkb->q_append((uint32) wkb_linestring);
wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_linestring);
if (trs->check_next_symbol('(') ||
ls.init_from_wkt(trs, wkb) ||
......@@ -1200,15 +1394,44 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
uint Gis_multi_line_string::init_from_opresult(String *bin,
const char *opres,
uint32 n_shapes)
{
const char *opres_orig= opres;
if (bin->reserve(4, 512))
return 0;
bin->q_append(n_shapes);
while (n_shapes--)
{
Gis_line_string ls;
int ls_len;
if (bin->reserve(WKB_HEADER_SIZE, 512))
return 0;
bin->q_append((char) wkb_ndr);
bin->q_append((uint32) wkb_linestring);
if (!(ls_len= ls.init_from_opresult(bin, opres)))
return 0;
opres+= ls_len;
}
return (uint) (opres - opres_orig);
}
uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
wkbByteOrder bo, String *res)
{
uint32 n_line_strings;
const char *wkb_orig= wkb;
if (len < 4)
if (len < 4 ||
(n_line_strings= wkb_get_uint(wkb, bo))< 1)
return 0;
n_line_strings= wkb_get_uint(wkb, bo);
if (res->reserve(4, 512))
return 0;
......@@ -1256,7 +1479,7 @@ bool Gis_multi_line_string::get_data_as_wkt(String *txt,
return 1;
n_points= uint4korr(data + WKB_HEADER_SIZE);
data+= WKB_HEADER_SIZE + 4;
if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) ||
if (no_data(data, n_points * POINT_DATA_SIZE) ||
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
return 1;
txt->qs_append('(');
......@@ -1386,6 +1609,35 @@ int Gis_multi_line_string::is_closed(int *closed) const
return 0;
}
int Gis_multi_line_string::store_shapes(Gcalc_shape_transporter *trn) const
{
uint32 n_lines;
Gis_line_string ls;
const char *data= m_data;
if (no_data(data, 4))
return 1;
n_lines= uint4korr(data);
data+= 4;
if (trn->start_collection(n_lines))
return 1;
while (n_lines--)
{
if (no_data(data, WKB_HEADER_SIZE))
return 1;
data+= WKB_HEADER_SIZE;
ls.set_data_ptr(data, (uint32) (m_data_end - data));
if (ls.store_shapes(trn))
return 1;
data+= ls.get_data_size();
}
return 0;
}
const Geometry::Class_info *Gis_multi_line_string::get_class_info() const
{
return &multilinestring_class;
......@@ -1436,7 +1688,7 @@ bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
for (;;)
{
if (wkb->reserve(1+4, 512))
if (wkb->reserve(1 + 4, 512))
return 1;
wkb->q_append((char) wkb_ndr);
wkb->q_append((uint32) wkb_polygon);
......@@ -1491,6 +1743,37 @@ uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len,
}
uint Gis_multi_polygon::init_from_opresult(String *bin,
const char *opres, uint32 n_shapes)
{
Gis_polygon p;
const char *opres_orig= opres;
uint p_len;
uint poly_shapes;
uint n_poly= 0;
uint32 np_pos= bin->length();
if (bin->reserve(4, 512))
return 0;
bin->q_append(n_shapes);
while (n_shapes)
{
if (bin->reserve(1 + 4, 512))
return 0;
bin->q_append((char)wkb_ndr);
bin->q_append((uint32)wkb_polygon);
if (!(p_len= p.priv_init_from_opresult(bin, opres, n_shapes, &poly_shapes)))
return 0;
n_shapes-= poly_shapes;
opres+= p_len;
n_poly++;
}
bin->write_at_position(np_pos, n_poly);
return opres - opres_orig;
}
bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
{
uint32 n_polygons;
......@@ -1517,7 +1800,7 @@ bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
return 1;
uint32 n_points= uint4korr(data);
data+= 4;
if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) ||
if (no_data(data, POINT_DATA_SIZE * n_points) ||
txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points,
512))
return 1;
......@@ -1678,6 +1961,35 @@ int Gis_multi_polygon::centroid(String *result) const
return create_point(result, res_cx, res_cy);
}
int Gis_multi_polygon::store_shapes(Gcalc_shape_transporter *trn) const
{
uint32 n_polygons;
Gis_polygon p;
const char *data= m_data;
if (no_data(data, 4))
return 1;
n_polygons= uint4korr(data);
data+= 4;
if (trn->start_collection(n_polygons))
return 1;
while (n_polygons--)
{
if (no_data(data, WKB_HEADER_SIZE))
return 1;
data+= WKB_HEADER_SIZE;
p.set_data_ptr(data, (uint32) (m_data_end - data));
if (p.store_shapes(trn))
return 1;
data+= p.get_data_size();
}
return 0;
}
const Geometry::Class_info *Gis_multi_polygon::get_class_info() const
{
return &multipolygon_class;
......@@ -1749,6 +2061,45 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb)
}
uint Gis_geometry_collection::init_from_opresult(String *bin,
const char *opres,
uint32 n_shapes)
{
const char *opres_orig= opres;
Geometry_buffer buffer;
Geometry *geom;
int g_len;
uint32 wkb_type;
if (bin->reserve(4, 512))
return 0;
bin->q_append(n_shapes);
while (n_shapes--)
{
switch ((Gcalc_function::shape_type) uint4korr(opres))
{
case Gcalc_function::shape_point: wkb_type= wkb_point; break;
case Gcalc_function::shape_line: wkb_type= wkb_linestring; break;
case Gcalc_function::shape_polygon: wkb_type= wkb_polygon; break;
default: wkb_type= 0; DBUG_ASSERT(FALSE);
};
if (bin->reserve(WKB_HEADER_SIZE, 512))
return 0;
bin->q_append((char) wkb_ndr);
bin->q_append(wkb_type);
if (!(geom= create_by_typeid(&buffer, wkb_type)) ||
!(g_len= geom->init_from_opresult(bin, opres, 1)))
return 0;
opres+= g_len;
}
return (uint) (opres - opres_orig);
}
uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
wkbByteOrder bo, String *res)
{
......@@ -1898,7 +2249,7 @@ int Gis_geometry_collection::geometry_n(uint32 num, String *result) const
} while (--num);
/* Copy found object to result */
if (result->reserve(1+4+length))
if (result->reserve(1 + 4 + length))
return 1;
result->q_append((char) wkb_ndr);
result->q_append((uint32) wkb_type);
......@@ -1959,6 +2310,42 @@ bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
return 0;
}
int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const
{
uint32 n_objects;
const char *data= m_data;
Geometry_buffer buffer;
Geometry *geom;
if (no_data(data, 4))
return 1;
n_objects= uint4korr(data);
data+= 4;
if (trn->start_collection(n_objects))
return 1;
while (n_objects--)
{
uint32 wkb_type;
if (no_data(data, WKB_HEADER_SIZE))
return 1;
wkb_type= uint4korr(data + 1);
data+= WKB_HEADER_SIZE;
if (!(geom= create_by_typeid(&buffer, wkb_type)))
return 1;
geom->set_data_ptr(data, (uint32) (m_data_end - data));
if (geom->store_shapes(trn))
return 1;
data+= geom->get_data_size();
}
return 0;
}
const Geometry::Class_info *Gis_geometry_collection::get_class_info() const
{
return &geometrycollection_class;
......
/* Copyright (C) 2002-2006 MySQL AB
/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -10,14 +10,19 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
#ifndef _spatial_h
#define _spatial_h
#include "sql_string.h" /* String, LEX_STRING */
#include <my_compiler.h>
#ifdef HAVE_SPATIAL
#include "gcalc_tools.h"
const uint SRID_SIZE= 4;
const uint SIZEOF_STORED_DOUBLE= 8;
const uint POINT_DATA_SIZE= SIZEOF_STORED_DOUBLE*2;
......@@ -242,10 +247,13 @@ class Geometry
virtual const Class_info *get_class_info() const=0;
virtual uint32 get_data_size() const=0;
virtual bool init_from_wkt(Gis_read_stream *trs, String *wkb)=0;
/* returns the length of the wkb that was read */
virtual uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
String *res)=0;
virtual uint init_from_opresult(String *bin,
const char *opres, uint32 n_shapes=1)
{ return init_from_wkb(opres + 4, UINT_MAX32, wkb_ndr, bin) + 4; }
virtual bool get_data_as_wkt(String *txt, const char **end) const=0;
virtual bool get_mbr(MBR *mbr, const char **end) const=0;
virtual bool dimension(uint32 *dim, const char **end) const=0;
......@@ -264,16 +272,20 @@ class Geometry
virtual int point_n(uint32 num, String *result) const { return -1; }
virtual int interior_ring_n(uint32 num, String *result) const { return -1; }
virtual int geometry_n(uint32 num, String *result) const { return -1; }
virtual int store_shapes(Gcalc_shape_transporter *trn) const=0;
public:
static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id);
static Geometry *construct(Geometry_buffer *buffer,
const char *data, uint32 data_len);
static Geometry *create_from_wkt(Geometry_buffer *buffer,
Gis_read_stream *trs, String *wkt,
bool init_stream=1);
static Geometry *create_from_wkb(Geometry_buffer *buffer, const char *wkb,
uint32 len, String *res);
static Geometry *create_from_wkb(Geometry_buffer *buffer,
const char *wkb, uint32 len, String *res);
static int create_from_opresult(Geometry_buffer *g_buf,
String *res, Gcalc_result_receiver &rr);
int as_wkt(String *wkt, const char **end)
{
uint32 len= (uint) get_class_info()->m_name.length;
......@@ -369,6 +381,7 @@ class Gis_point: public Geometry
*end= 0; /* No default end */
return 0;
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
};
......@@ -397,6 +410,7 @@ class Gis_line_string: public Geometry
*end= 0; /* No default end */
return 0;
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
};
......@@ -411,6 +425,13 @@ class Gis_polygon: public Geometry
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
uint priv_init_from_opresult(String *bin, const char *opres,
uint32 n_shapes, uint32 *poly_shapes);
uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes)
{
uint32 foo;
return priv_init_from_opresult(bin, opres, n_shapes, &foo);
}
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int area(double *ar, const char **end) const;
......@@ -425,6 +446,7 @@ class Gis_polygon: public Geometry
*end= 0; /* No default end */
return 0;
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
};
......@@ -439,6 +461,7 @@ class Gis_multi_point: public Geometry
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
......@@ -449,6 +472,7 @@ class Gis_multi_point: public Geometry
*end= 0; /* No default end */
return 0;
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
};
......@@ -463,6 +487,7 @@ class Gis_multi_line_string: public Geometry
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
......@@ -475,6 +500,7 @@ class Gis_multi_line_string: public Geometry
*end= 0; /* No default end */
return 0;
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
};
......@@ -501,7 +527,9 @@ class Gis_multi_polygon: public Geometry
*end= 0; /* No default end */
return 0;
}
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes);
};
......@@ -515,11 +543,13 @@ class Gis_geometry_collection: public Geometry
uint32 get_data_size() const;
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
uint init_from_opresult(String *bin, const char *opres, uint32 n_shapes);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
int geometry_n(uint32 num, String *result) const;
bool dimension(uint32 *dim, const char **end) const;
int store_shapes(Gcalc_shape_transporter *trn) const;
const Class_info *get_class_info() const;
};
......
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