PostgreSQL Source Code  git master
geo_spgist.c File Reference
#include "postgres.h"
#include "access/spgist.h"
#include "access/spgist_private.h"
#include "access/stratnum.h"
#include "catalog/pg_type.h"
#include "utils/float.h"
#include "utils/fmgroids.h"
#include "utils/fmgrprotos.h"
#include "utils/geo_decls.h"
Include dependency graph for geo_spgist.c:

Go to the source code of this file.

Data Structures

struct  Range
 
struct  RangeBox
 
struct  RectBox
 

Functions

static int compareDoubles (const void *a, const void *b)
 
static uint8 getQuadrant (BOX *centroid, BOX *inBox)
 
static RangeBoxgetRangeBox (BOX *box)
 
static RectBoxinitRectBox (void)
 
static RectBoxnextRectBox (RectBox *rect_box, RangeBox *centroid, uint8 quadrant)
 
static bool overlap2D (RangeBox *range_box, Range *query)
 
static bool overlap4D (RectBox *rect_box, RangeBox *query)
 
static bool contain2D (RangeBox *range_box, Range *query)
 
static bool contain4D (RectBox *rect_box, RangeBox *query)
 
static bool contained2D (RangeBox *range_box, Range *query)
 
static bool contained4D (RectBox *rect_box, RangeBox *query)
 
static bool lower2D (RangeBox *range_box, Range *query)
 
static bool overLower2D (RangeBox *range_box, Range *query)
 
static bool higher2D (RangeBox *range_box, Range *query)
 
static bool overHigher2D (RangeBox *range_box, Range *query)
 
static bool left4D (RectBox *rect_box, RangeBox *query)
 
static bool overLeft4D (RectBox *rect_box, RangeBox *query)
 
static bool right4D (RectBox *rect_box, RangeBox *query)
 
static bool overRight4D (RectBox *rect_box, RangeBox *query)
 
static bool below4D (RectBox *rect_box, RangeBox *query)
 
static bool overBelow4D (RectBox *rect_box, RangeBox *query)
 
static bool above4D (RectBox *rect_box, RangeBox *query)
 
static bool overAbove4D (RectBox *rect_box, RangeBox *query)
 
static double pointToRectBoxDistance (Point *point, RectBox *rect_box)
 
Datum spg_box_quad_config (PG_FUNCTION_ARGS)
 
Datum spg_box_quad_choose (PG_FUNCTION_ARGS)
 
Datum spg_box_quad_picksplit (PG_FUNCTION_ARGS)
 
static bool is_bounding_box_test_exact (StrategyNumber strategy)
 
static BOXspg_box_quad_get_scankey_bbox (ScanKey sk, bool *recheck)
 
Datum spg_box_quad_inner_consistent (PG_FUNCTION_ARGS)
 
Datum spg_box_quad_leaf_consistent (PG_FUNCTION_ARGS)
 
Datum spg_bbox_quad_config (PG_FUNCTION_ARGS)
 
Datum spg_poly_quad_compress (PG_FUNCTION_ARGS)
 

Function Documentation

◆ above4D()

static bool above4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 360 of file geo_spgist.c.

References higher2D(), RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

361 {
362  return higher2D(&rect_box->range_box_y, &query->right);
363 }
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
static bool higher2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:302

◆ below4D()

static bool below4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 346 of file geo_spgist.c.

References lower2D(), RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

347 {
348  return lower2D(&rect_box->range_box_y, &query->right);
349 }
static bool lower2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:286
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112

◆ compareDoubles()

static int compareDoubles ( const void *  a,
const void *  b 
)
static

Definition at line 93 of file geo_spgist.c.

Referenced by spg_box_quad_picksplit().

94 {
95  float8 x = *(float8 *) a;
96  float8 y = *(float8 *) b;
97 
98  if (x == y)
99  return 0;
100  return (x > y) ? 1 : -1;
101 }
double float8
Definition: c.h:491

◆ contain2D()

static bool contain2D ( RangeBox range_box,
Range query 
)
static

Definition at line 252 of file geo_spgist.c.

References FPge, FPle, Range::high, RangeBox::left, Range::low, and RangeBox::right.

Referenced by contain4D().

253 {
254  return FPge(range_box->right.high, query->high) &&
255  FPle(range_box->left.low, query->low);
256 }
float8 low
Definition: geo_spgist.c:105
Range right
Definition: geo_spgist.c:112
float8 high
Definition: geo_spgist.c:106
#define FPge(A, B)
Definition: geo_decls.h:39
#define FPle(A, B)
Definition: geo_decls.h:37
Range left
Definition: geo_spgist.c:111

◆ contain4D()

static bool contain4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 260 of file geo_spgist.c.

References contain2D(), RangeBox::left, RectBox::range_box_x, RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

261 {
262  return contain2D(&rect_box->range_box_x, &query->left) &&
263  contain2D(&rect_box->range_box_y, &query->right);
264 }
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
RangeBox range_box_x
Definition: geo_spgist.c:117
static bool contain2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:252
Range left
Definition: geo_spgist.c:111

◆ contained2D()

static bool contained2D ( RangeBox range_box,
Range query 
)
static

Definition at line 268 of file geo_spgist.c.

References FPge, FPle, Range::high, RangeBox::left, Range::low, and RangeBox::right.

Referenced by contained4D().

269 {
270  return FPle(range_box->left.low, query->high) &&
271  FPge(range_box->left.high, query->low) &&
272  FPle(range_box->right.low, query->high) &&
273  FPge(range_box->right.high, query->low);
274 }
float8 low
Definition: geo_spgist.c:105
Range right
Definition: geo_spgist.c:112
float8 high
Definition: geo_spgist.c:106
#define FPge(A, B)
Definition: geo_decls.h:39
#define FPle(A, B)
Definition: geo_decls.h:37
Range left
Definition: geo_spgist.c:111

◆ contained4D()

static bool contained4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 278 of file geo_spgist.c.

References contained2D(), RangeBox::left, RectBox::range_box_x, RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

279 {
280  return contained2D(&rect_box->range_box_x, &query->left) &&
281  contained2D(&rect_box->range_box_y, &query->right);
282 }
static bool contained2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:268
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
RangeBox range_box_x
Definition: geo_spgist.c:117
Range left
Definition: geo_spgist.c:111

◆ getQuadrant()

static uint8 getQuadrant ( BOX centroid,
BOX inBox 
)
static

Definition at line 130 of file geo_spgist.c.

References BOX::high, BOX::low, Point::x, and Point::y.

Referenced by spg_box_quad_choose(), and spg_box_quad_picksplit().

131 {
132  uint8 quadrant = 0;
133 
134  if (inBox->low.x > centroid->low.x)
135  quadrant |= 0x8;
136 
137  if (inBox->high.x > centroid->high.x)
138  quadrant |= 0x4;
139 
140  if (inBox->low.y > centroid->low.y)
141  quadrant |= 0x2;
142 
143  if (inBox->high.y > centroid->high.y)
144  quadrant |= 0x1;
145 
146  return quadrant;
147 }
float8 x
Definition: geo_decls.h:57
unsigned char uint8
Definition: c.h:356
Point low
Definition: geo_decls.h:101
float8 y
Definition: geo_decls.h:57
Point high
Definition: geo_decls.h:101

◆ getRangeBox()

static RangeBox* getRangeBox ( BOX box)
static

Definition at line 157 of file geo_spgist.c.

References BOX::high, Range::high, RangeBox::left, BOX::low, Range::low, palloc(), RangeBox::right, Point::x, and Point::y.

Referenced by spg_box_quad_inner_consistent().

158 {
159  RangeBox *range_box = (RangeBox *) palloc(sizeof(RangeBox));
160 
161  range_box->left.low = box->low.x;
162  range_box->left.high = box->high.x;
163 
164  range_box->right.low = box->low.y;
165  range_box->right.high = box->high.y;
166 
167  return range_box;
168 }
float8 low
Definition: geo_spgist.c:105
float8 x
Definition: geo_decls.h:57
Range right
Definition: geo_spgist.c:112
float8 high
Definition: geo_spgist.c:106
Point low
Definition: geo_decls.h:101
float8 y
Definition: geo_decls.h:57
Point high
Definition: geo_decls.h:101
void * palloc(Size size)
Definition: mcxt.c:949
Range left
Definition: geo_spgist.c:111

◆ higher2D()

static bool higher2D ( RangeBox range_box,
Range query 
)
static

Definition at line 302 of file geo_spgist.c.

References FPgt, Range::high, RangeBox::left, and RangeBox::right.

Referenced by above4D(), and right4D().

303 {
304  return FPgt(range_box->left.high, query->high) &&
305  FPgt(range_box->right.high, query->high);
306 }
Range right
Definition: geo_spgist.c:112
#define FPgt(A, B)
Definition: geo_decls.h:38
float8 high
Definition: geo_spgist.c:106
Range left
Definition: geo_spgist.c:111

◆ initRectBox()

static RectBox* initRectBox ( void  )
static

Definition at line 177 of file geo_spgist.c.

References get_float8_infinity(), Range::high, RangeBox::left, Range::low, palloc(), RectBox::range_box_x, RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

178 {
179  RectBox *rect_box = (RectBox *) palloc(sizeof(RectBox));
180  float8 infinity = get_float8_infinity();
181 
182  rect_box->range_box_x.left.low = -infinity;
183  rect_box->range_box_x.left.high = infinity;
184 
185  rect_box->range_box_x.right.low = -infinity;
186  rect_box->range_box_x.right.high = infinity;
187 
188  rect_box->range_box_y.left.low = -infinity;
189  rect_box->range_box_y.left.high = infinity;
190 
191  rect_box->range_box_y.right.low = -infinity;
192  rect_box->range_box_y.right.high = infinity;
193 
194  return rect_box;
195 }
float8 low
Definition: geo_spgist.c:105
static float8 get_float8_infinity(void)
Definition: float.h:90
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
RangeBox range_box_x
Definition: geo_spgist.c:117
double float8
Definition: c.h:491
float8 high
Definition: geo_spgist.c:106
void * palloc(Size size)
Definition: mcxt.c:949
Range left
Definition: geo_spgist.c:111

◆ is_bounding_box_test_exact()

static bool is_bounding_box_test_exact ( StrategyNumber  strategy)
static

Definition at line 508 of file geo_spgist.c.

References RTAboveStrategyNumber, RTBelowStrategyNumber, RTLeftStrategyNumber, RTOverAboveStrategyNumber, RTOverBelowStrategyNumber, RTOverLeftStrategyNumber, RTOverRightStrategyNumber, and RTRightStrategyNumber.

Referenced by spg_box_quad_get_scankey_bbox().

509 {
510  switch (strategy)
511  {
520  return true;
521 
522  default:
523  return false;
524  }
525 }
#define RTLeftStrategyNumber
Definition: stratnum.h:51
#define RTOverBelowStrategyNumber
Definition: stratnum.h:59
#define RTBelowStrategyNumber
Definition: stratnum.h:60
#define RTOverAboveStrategyNumber
Definition: stratnum.h:62
#define RTOverRightStrategyNumber
Definition: stratnum.h:54
#define RTOverLeftStrategyNumber
Definition: stratnum.h:52
#define RTAboveStrategyNumber
Definition: stratnum.h:61
#define RTRightStrategyNumber
Definition: stratnum.h:55

◆ left4D()

static bool left4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 318 of file geo_spgist.c.

References RangeBox::left, lower2D(), and RectBox::range_box_x.

Referenced by spg_box_quad_inner_consistent().

319 {
320  return lower2D(&rect_box->range_box_x, &query->left);
321 }
static bool lower2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:286
RangeBox range_box_x
Definition: geo_spgist.c:117
Range left
Definition: geo_spgist.c:111

◆ lower2D()

static bool lower2D ( RangeBox range_box,
Range query 
)
static

Definition at line 286 of file geo_spgist.c.

References FPlt, RangeBox::left, Range::low, and RangeBox::right.

Referenced by below4D(), and left4D().

287 {
288  return FPlt(range_box->left.low, query->low) &&
289  FPlt(range_box->right.low, query->low);
290 }
float8 low
Definition: geo_spgist.c:105
Range right
Definition: geo_spgist.c:112
#define FPlt(A, B)
Definition: geo_decls.h:36
Range left
Definition: geo_spgist.c:111

◆ nextRectBox()

static RectBox* nextRectBox ( RectBox rect_box,
RangeBox centroid,
uint8  quadrant 
)
static

Definition at line 205 of file geo_spgist.c.

References Range::high, RangeBox::left, Range::low, palloc(), RectBox::range_box_x, RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

206 {
207  RectBox *next_rect_box = (RectBox *) palloc(sizeof(RectBox));
208 
209  memcpy(next_rect_box, rect_box, sizeof(RectBox));
210 
211  if (quadrant & 0x8)
212  next_rect_box->range_box_x.left.low = centroid->left.low;
213  else
214  next_rect_box->range_box_x.left.high = centroid->left.low;
215 
216  if (quadrant & 0x4)
217  next_rect_box->range_box_x.right.low = centroid->left.high;
218  else
219  next_rect_box->range_box_x.right.high = centroid->left.high;
220 
221  if (quadrant & 0x2)
222  next_rect_box->range_box_y.left.low = centroid->right.low;
223  else
224  next_rect_box->range_box_y.left.high = centroid->right.low;
225 
226  if (quadrant & 0x1)
227  next_rect_box->range_box_y.right.low = centroid->right.high;
228  else
229  next_rect_box->range_box_y.right.high = centroid->right.high;
230 
231  return next_rect_box;
232 }
float8 low
Definition: geo_spgist.c:105
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
RangeBox range_box_x
Definition: geo_spgist.c:117
float8 high
Definition: geo_spgist.c:106
void * palloc(Size size)
Definition: mcxt.c:949
Range left
Definition: geo_spgist.c:111

◆ overAbove4D()

static bool overAbove4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 367 of file geo_spgist.c.

References overHigher2D(), RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

368 {
369  return overHigher2D(&rect_box->range_box_y, &query->right);
370 }
static bool overHigher2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:310
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112

◆ overBelow4D()

static bool overBelow4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 353 of file geo_spgist.c.

References overLower2D(), RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

354 {
355  return overLower2D(&rect_box->range_box_y, &query->right);
356 }
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
static bool overLower2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:294

◆ overHigher2D()

static bool overHigher2D ( RangeBox range_box,
Range query 
)
static

Definition at line 310 of file geo_spgist.c.

References FPge, Range::high, RangeBox::left, Range::low, and RangeBox::right.

Referenced by overAbove4D(), and overRight4D().

311 {
312  return FPge(range_box->left.high, query->low) &&
313  FPge(range_box->right.high, query->low);
314 }
float8 low
Definition: geo_spgist.c:105
Range right
Definition: geo_spgist.c:112
float8 high
Definition: geo_spgist.c:106
#define FPge(A, B)
Definition: geo_decls.h:39
Range left
Definition: geo_spgist.c:111

◆ overlap2D()

static bool overlap2D ( RangeBox range_box,
Range query 
)
static

Definition at line 236 of file geo_spgist.c.

References FPge, FPle, Range::high, RangeBox::left, Range::low, and RangeBox::right.

Referenced by overlap4D().

237 {
238  return FPge(range_box->right.high, query->low) &&
239  FPle(range_box->left.low, query->high);
240 }
float8 low
Definition: geo_spgist.c:105
Range right
Definition: geo_spgist.c:112
float8 high
Definition: geo_spgist.c:106
#define FPge(A, B)
Definition: geo_decls.h:39
#define FPle(A, B)
Definition: geo_decls.h:37
Range left
Definition: geo_spgist.c:111

◆ overlap4D()

static bool overlap4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 244 of file geo_spgist.c.

References RangeBox::left, overlap2D(), RectBox::range_box_x, RectBox::range_box_y, and RangeBox::right.

Referenced by spg_box_quad_inner_consistent().

245 {
246  return overlap2D(&rect_box->range_box_x, &query->left) &&
247  overlap2D(&rect_box->range_box_y, &query->right);
248 }
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
RangeBox range_box_x
Definition: geo_spgist.c:117
static bool overlap2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:236
Range left
Definition: geo_spgist.c:111

◆ overLeft4D()

static bool overLeft4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 325 of file geo_spgist.c.

References RangeBox::left, overLower2D(), and RectBox::range_box_x.

Referenced by spg_box_quad_inner_consistent().

326 {
327  return overLower2D(&rect_box->range_box_x, &query->left);
328 }
static bool overLower2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:294
RangeBox range_box_x
Definition: geo_spgist.c:117
Range left
Definition: geo_spgist.c:111

◆ overLower2D()

static bool overLower2D ( RangeBox range_box,
Range query 
)
static

Definition at line 294 of file geo_spgist.c.

References FPle, Range::high, RangeBox::left, Range::low, and RangeBox::right.

Referenced by overBelow4D(), and overLeft4D().

295 {
296  return FPle(range_box->left.low, query->high) &&
297  FPle(range_box->right.low, query->high);
298 }
float8 low
Definition: geo_spgist.c:105
Range right
Definition: geo_spgist.c:112
float8 high
Definition: geo_spgist.c:106
#define FPle(A, B)
Definition: geo_decls.h:37
Range left
Definition: geo_spgist.c:111

◆ overRight4D()

static bool overRight4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 339 of file geo_spgist.c.

References RangeBox::left, overHigher2D(), and RectBox::range_box_x.

Referenced by spg_box_quad_inner_consistent().

340 {
341  return overHigher2D(&rect_box->range_box_x, &query->left);
342 }
static bool overHigher2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:310
RangeBox range_box_x
Definition: geo_spgist.c:117
Range left
Definition: geo_spgist.c:111

◆ pointToRectBoxDistance()

static double pointToRectBoxDistance ( Point point,
RectBox rect_box 
)
static

Definition at line 374 of file geo_spgist.c.

References Range::high, HYPOT, RangeBox::left, Range::low, RectBox::range_box_x, RectBox::range_box_y, RangeBox::right, Point::x, and Point::y.

Referenced by spg_box_quad_inner_consistent().

375 {
376  double dx;
377  double dy;
378 
379  if (point->x < rect_box->range_box_x.left.low)
380  dx = rect_box->range_box_x.left.low - point->x;
381  else if (point->x > rect_box->range_box_x.right.high)
382  dx = point->x - rect_box->range_box_x.right.high;
383  else
384  dx = 0;
385 
386  if (point->y < rect_box->range_box_y.left.low)
387  dy = rect_box->range_box_y.left.low - point->y;
388  else if (point->y > rect_box->range_box_y.right.high)
389  dy = point->y - rect_box->range_box_y.right.high;
390  else
391  dy = 0;
392 
393  return HYPOT(dx, dy);
394 }
float8 low
Definition: geo_spgist.c:105
float8 x
Definition: geo_decls.h:57
RangeBox range_box_y
Definition: geo_spgist.c:118
Range right
Definition: geo_spgist.c:112
RangeBox range_box_x
Definition: geo_spgist.c:117
float8 high
Definition: geo_spgist.c:106
#define HYPOT(A, B)
Definition: geo_decls.h:50
float8 y
Definition: geo_decls.h:57
Range left
Definition: geo_spgist.c:111

◆ right4D()

static bool right4D ( RectBox rect_box,
RangeBox query 
)
static

Definition at line 332 of file geo_spgist.c.

References higher2D(), RangeBox::left, and RectBox::range_box_x.

Referenced by spg_box_quad_inner_consistent().

333 {
334  return higher2D(&rect_box->range_box_x, &query->left);
335 }
RangeBox range_box_x
Definition: geo_spgist.c:117
Range left
Definition: geo_spgist.c:111
static bool higher2D(RangeBox *range_box, Range *query)
Definition: geo_spgist.c:302

◆ spg_bbox_quad_config()

Datum spg_bbox_quad_config ( PG_FUNCTION_ARGS  )

Definition at line 854 of file geo_spgist.c.

References spgConfigOut::canReturnData, spgConfigOut::labelType, spgConfigOut::leafType, spgConfigOut::longValuesOK, PG_GETARG_POINTER, PG_RETURN_VOID, and spgConfigOut::prefixType.

855 {
857 
858  cfg->prefixType = BOXOID; /* A type represented by its bounding box */
859  cfg->labelType = VOIDOID; /* We don't need node labels. */
860  cfg->leafType = BOXOID;
861  cfg->canReturnData = false;
862  cfg->longValuesOK = false;
863 
864  PG_RETURN_VOID();
865 }
bool canReturnData
Definition: spgist.h:49
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
bool longValuesOK
Definition: spgist.h:50
Oid prefixType
Definition: spgist.h:46
#define PG_RETURN_VOID()
Definition: fmgr.h:339
Oid labelType
Definition: spgist.h:47
Oid leafType
Definition: spgist.h:48

◆ spg_box_quad_choose()

Datum spg_box_quad_choose ( PG_FUNCTION_ARGS  )

Definition at line 417 of file geo_spgist.c.

References spgChooseIn::allTheSame, BoxPGetDatum, DatumGetBoxP, getQuadrant(), spgChooseIn::leafDatum, spgChooseOut::matchNode, PG_GETARG_POINTER, PG_RETURN_VOID, spgChooseIn::prefixDatum, spgChooseOut::result, spgChooseOut::resultType, and spgMatchNode.

418 {
421  BOX *centroid = DatumGetBoxP(in->prefixDatum),
422  *box = DatumGetBoxP(in->leafDatum);
423 
424  out->resultType = spgMatchNode;
425  out->result.matchNode.restDatum = BoxPGetDatum(box);
426 
427  /* nodeN will be set by core, when allTheSame. */
428  if (!in->allTheSame)
429  out->result.matchNode.nodeN = getQuadrant(centroid, box);
430 
431  PG_RETURN_VOID();
432 }
Definition: geo_decls.h:99
struct spgChooseOut::@48::@49 matchNode
Datum prefixDatum
Definition: spgist.h:65
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
spgChooseResultType resultType
Definition: spgist.h:79
#define BoxPGetDatum(X)
Definition: geo_decls.h:157
#define PG_RETURN_VOID()
Definition: fmgr.h:339
Datum leafDatum
Definition: spgist.h:59
union spgChooseOut::@48 result
#define DatumGetBoxP(X)
Definition: geo_decls.h:156
static uint8 getQuadrant(BOX *centroid, BOX *inBox)
Definition: geo_spgist.c:130
bool allTheSame
Definition: spgist.h:63

◆ spg_box_quad_config()

Datum spg_box_quad_config ( PG_FUNCTION_ARGS  )

Definition at line 401 of file geo_spgist.c.

References spgConfigOut::canReturnData, spgConfigOut::labelType, spgConfigOut::longValuesOK, PG_GETARG_POINTER, PG_RETURN_VOID, and spgConfigOut::prefixType.

402 {
404 
405  cfg->prefixType = BOXOID;
406  cfg->labelType = VOIDOID; /* We don't need node labels. */
407  cfg->canReturnData = true;
408  cfg->longValuesOK = false;
409 
410  PG_RETURN_VOID();
411 }
bool canReturnData
Definition: spgist.h:49
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
bool longValuesOK
Definition: spgist.h:50
Oid prefixType
Definition: spgist.h:46
#define PG_RETURN_VOID()
Definition: fmgr.h:339
Oid labelType
Definition: spgist.h:47

◆ spg_box_quad_get_scankey_bbox()

static BOX* spg_box_quad_get_scankey_bbox ( ScanKey  sk,
bool recheck 
)
static

Definition at line 531 of file geo_spgist.c.

References DatumGetBoxP, DatumGetPolygonP, elog, ERROR, is_bounding_box_test_exact(), ScanKeyData::sk_argument, ScanKeyData::sk_strategy, and ScanKeyData::sk_subtype.

Referenced by spg_box_quad_inner_consistent(), and spg_box_quad_leaf_consistent().

532 {
533  switch (sk->sk_subtype)
534  {
535  case BOXOID:
536  return DatumGetBoxP(sk->sk_argument);
537 
538  case POLYGONOID:
539  if (recheck && !is_bounding_box_test_exact(sk->sk_strategy))
540  *recheck = true;
541  return &DatumGetPolygonP(sk->sk_argument)->boundbox;
542 
543  default:
544  elog(ERROR, "unrecognized scankey subtype: %d", sk->sk_subtype);
545  return NULL;
546  }
547 }
Oid sk_subtype
Definition: skey.h:69
static bool is_bounding_box_test_exact(StrategyNumber strategy)
Definition: geo_spgist.c:508
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
#define DatumGetBoxP(X)
Definition: geo_decls.h:156
#define DatumGetPolygonP(X)
Definition: geo_decls.h:161
#define elog(elevel,...)
Definition: elog.h:226
Datum sk_argument
Definition: skey.h:72

◆ spg_box_quad_inner_consistent()

Datum spg_box_quad_inner_consistent ( PG_FUNCTION_ARGS  )

Definition at line 553 of file geo_spgist.c.

References above4D(), spgInnerConsistentIn::allTheSame, below4D(), contain4D(), contained4D(), DatumGetBoxP, DatumGetPointP, spgInnerConsistentOut::distances, elog, ERROR, flag(), getRangeBox(), i, initRectBox(), left4D(), MemoryContextSwitchTo(), nextRectBox(), spgInnerConsistentIn::nkeys, spgInnerConsistentIn::nNodes, spgInnerConsistentOut::nNodes, spgInnerConsistentOut::nodeNumbers, spgInnerConsistentIn::norderbys, spgInnerConsistentIn::orderbys, overAbove4D(), overBelow4D(), overlap4D(), overLeft4D(), overRight4D(), palloc(), pfree(), PG_GETARG_POINTER, PG_RETURN_VOID, pointToRectBoxDistance(), spgInnerConsistentIn::prefixDatum, right4D(), RTAboveStrategyNumber, RTBelowStrategyNumber, RTContainedByStrategyNumber, RTContainsStrategyNumber, RTLeftStrategyNumber, RTOverAboveStrategyNumber, RTOverBelowStrategyNumber, RTOverlapStrategyNumber, RTOverLeftStrategyNumber, RTOverRightStrategyNumber, RTRightStrategyNumber, RTSameStrategyNumber, spgInnerConsistentIn::scankeys, ScanKeyData::sk_argument, ScanKeyData::sk_strategy, spg_box_quad_get_scankey_bbox(), spgInnerConsistentIn::traversalMemoryContext, spgInnerConsistentIn::traversalValue, and spgInnerConsistentOut::traversalValues.

554 {
557  int i;
558  MemoryContext old_ctx;
559  RectBox *rect_box;
560  uint8 quadrant;
561  RangeBox *centroid,
562  **queries;
563 
564  /*
565  * We are saving the traversal value or initialize it an unbounded one, if
566  * we have just begun to walk the tree.
567  */
568  if (in->traversalValue)
569  rect_box = in->traversalValue;
570  else
571  rect_box = initRectBox();
572 
573  if (in->allTheSame)
574  {
575  /* Report that all nodes should be visited */
576  out->nNodes = in->nNodes;
577  out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
578  for (i = 0; i < in->nNodes; i++)
579  out->nodeNumbers[i] = i;
580 
581  if (in->norderbys > 0 && in->nNodes > 0)
582  {
583  double *distances = palloc(sizeof(double) * in->norderbys);
584  int j;
585 
586  for (j = 0; j < in->norderbys; j++)
587  {
589 
590  distances[j] = pointToRectBoxDistance(pt, rect_box);
591  }
592 
593  out->distances = (double **) palloc(sizeof(double *) * in->nNodes);
594  out->distances[0] = distances;
595 
596  for (i = 1; i < in->nNodes; i++)
597  {
598  out->distances[i] = palloc(sizeof(double) * in->norderbys);
599  memcpy(out->distances[i], distances,
600  sizeof(double) * in->norderbys);
601  }
602  }
603 
604  PG_RETURN_VOID();
605  }
606 
607  /*
608  * We are casting the prefix and queries to RangeBoxes for ease of the
609  * following operations.
610  */
611  centroid = getRangeBox(DatumGetBoxP(in->prefixDatum));
612  queries = (RangeBox **) palloc(in->nkeys * sizeof(RangeBox *));
613  for (i = 0; i < in->nkeys; i++)
614  {
615  BOX *box = spg_box_quad_get_scankey_bbox(&in->scankeys[i], NULL);
616 
617  queries[i] = getRangeBox(box);
618  }
619 
620  /* Allocate enough memory for nodes */
621  out->nNodes = 0;
622  out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
623  out->traversalValues = (void **) palloc(sizeof(void *) * in->nNodes);
624  if (in->norderbys > 0)
625  out->distances = (double **) palloc(sizeof(double *) * in->nNodes);
626 
627  /*
628  * We switch memory context, because we want to allocate memory for new
629  * traversal values (next_rect_box) and pass these pieces of memory to
630  * further call of this function.
631  */
633 
634  for (quadrant = 0; quadrant < in->nNodes; quadrant++)
635  {
636  RectBox *next_rect_box = nextRectBox(rect_box, centroid, quadrant);
637  bool flag = true;
638 
639  for (i = 0; i < in->nkeys; i++)
640  {
641  StrategyNumber strategy = in->scankeys[i].sk_strategy;
642 
643  switch (strategy)
644  {
646  flag = overlap4D(next_rect_box, queries[i]);
647  break;
648 
650  flag = contain4D(next_rect_box, queries[i]);
651  break;
652 
655  flag = contained4D(next_rect_box, queries[i]);
656  break;
657 
659  flag = left4D(next_rect_box, queries[i]);
660  break;
661 
663  flag = overLeft4D(next_rect_box, queries[i]);
664  break;
665 
667  flag = right4D(next_rect_box, queries[i]);
668  break;
669 
671  flag = overRight4D(next_rect_box, queries[i]);
672  break;
673 
675  flag = above4D(next_rect_box, queries[i]);
676  break;
677 
679  flag = overAbove4D(next_rect_box, queries[i]);
680  break;
681 
683  flag = below4D(next_rect_box, queries[i]);
684  break;
685 
687  flag = overBelow4D(next_rect_box, queries[i]);
688  break;
689 
690  default:
691  elog(ERROR, "unrecognized strategy: %d", strategy);
692  }
693 
694  /* If any check is failed, we have found our answer. */
695  if (!flag)
696  break;
697  }
698 
699  if (flag)
700  {
701  out->traversalValues[out->nNodes] = next_rect_box;
702  out->nodeNumbers[out->nNodes] = quadrant;
703 
704  if (in->norderbys > 0)
705  {
706  double *distances = palloc(sizeof(double) * in->norderbys);
707  int j;
708 
709  out->distances[out->nNodes] = distances;
710 
711  for (j = 0; j < in->norderbys; j++)
712  {
714 
715  distances[j] = pointToRectBoxDistance(pt, next_rect_box);
716  }
717  }
718 
719  out->nNodes++;
720  }
721  else
722  {
723  /*
724  * If this node is not selected, we don't need to keep the next
725  * traversal value in the memory context.
726  */
727  pfree(next_rect_box);
728  }
729  }
730 
731  /* Switch back */
732  MemoryContextSwitchTo(old_ctx);
733 
734  PG_RETURN_VOID();
735 }
static bool overAbove4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:367
Definition: geo_decls.h:99
static bool overBelow4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:353
static bool contain4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:260
#define RTLeftStrategyNumber
Definition: stratnum.h:51
ScanKey orderbys
Definition: spgist.h:138
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned char uint8
Definition: c.h:356
void * traversalValue
Definition: spgist.h:144
#define RTOverBelowStrategyNumber
Definition: stratnum.h:59
static bool overRight4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:339
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTContainedByStrategyNumber
Definition: stratnum.h:58
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
static bool left4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:318
#define RTBelowStrategyNumber
Definition: stratnum.h:60
#define RTOverAboveStrategyNumber
Definition: stratnum.h:62
static bool below4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:346
void pfree(void *pointer)
Definition: mcxt.c:1056
static bool overlap4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:244
MemoryContext traversalMemoryContext
Definition: spgist.h:145
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
char * flag(int b)
Definition: test-ctype.c:33
#define RTSameStrategyNumber
Definition: stratnum.h:56
#define RTOverRightStrategyNumber
Definition: stratnum.h:54
void ** traversalValues
Definition: spgist.h:163
static bool above4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:360
#define RTOverLeftStrategyNumber
Definition: stratnum.h:52
static RectBox * initRectBox(void)
Definition: geo_spgist.c:177
double ** distances
Definition: spgist.h:164
static double pointToRectBoxDistance(Point *point, RectBox *rect_box)
Definition: geo_spgist.c:374
#define PG_RETURN_VOID()
Definition: fmgr.h:339
#define RTAboveStrategyNumber
Definition: stratnum.h:61
#define RTRightStrategyNumber
Definition: stratnum.h:55
#define DatumGetPointP(X)
Definition: geo_decls.h:134
static bool contained4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:278
#define RTContainsStrategyNumber
Definition: stratnum.h:57
ScanKey scankeys
Definition: spgist.h:137
#define DatumGetBoxP(X)
Definition: geo_decls.h:156
void * palloc(Size size)
Definition: mcxt.c:949
static BOX * spg_box_quad_get_scankey_bbox(ScanKey sk, bool *recheck)
Definition: geo_spgist.c:531
#define elog(elevel,...)
Definition: elog.h:226
static bool overLeft4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:325
int i
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
static bool right4D(RectBox *rect_box, RangeBox *query)
Definition: geo_spgist.c:332
static RangeBox * getRangeBox(BOX *box)
Definition: geo_spgist.c:157
Datum sk_argument
Definition: skey.h:72
static RectBox * nextRectBox(RectBox *rect_box, RangeBox *centroid, uint8 quadrant)
Definition: geo_spgist.c:205

◆ spg_box_quad_leaf_consistent()

Datum spg_box_quad_leaf_consistent ( PG_FUNCTION_ARGS  )

Definition at line 741 of file geo_spgist.c.

References box_above(), box_below(), box_contain(), box_contained(), box_left(), box_overabove(), box_overbelow(), box_overlap(), box_overleft(), box_overright(), box_right(), box_same(), BoxPGetDatum, DatumGetBool, DirectFunctionCall2, spgLeafConsistentOut::distances, elog, ERROR, flag(), FmgrInfo::fn_oid, i, spgLeafConsistentIn::leafDatum, spgLeafConsistentOut::leafValue, spgLeafConsistentIn::nkeys, spgLeafConsistentIn::norderbys, spgLeafConsistentIn::orderbys, PG_GETARG_POINTER, PG_RETURN_BOOL, spgLeafConsistentOut::recheck, spgLeafConsistentOut::recheckDistances, RTAboveStrategyNumber, RTBelowStrategyNumber, RTContainedByStrategyNumber, RTContainsStrategyNumber, RTLeftStrategyNumber, RTOverAboveStrategyNumber, RTOverBelowStrategyNumber, RTOverlapStrategyNumber, RTOverLeftStrategyNumber, RTOverRightStrategyNumber, RTRightStrategyNumber, RTSameStrategyNumber, spgLeafConsistentIn::scankeys, ScanKeyData::sk_func, ScanKeyData::sk_strategy, spg_box_quad_get_scankey_bbox(), and spg_key_orderbys_distances().

742 {
745  Datum leaf = in->leafDatum;
746  bool flag = true;
747  int i;
748 
749  /* All tests are exact. */
750  out->recheck = false;
751 
752  /* leafDatum is what it is... */
753  out->leafValue = in->leafDatum;
754 
755  /* Perform the required comparison(s) */
756  for (i = 0; i < in->nkeys; i++)
757  {
758  StrategyNumber strategy = in->scankeys[i].sk_strategy;
760  &out->recheck);
761  Datum query = BoxPGetDatum(box);
762 
763  switch (strategy)
764  {
767  query));
768  break;
769 
772  query));
773  break;
774 
777  query));
778  break;
779 
782  query));
783  break;
784 
787  query));
788  break;
789 
792  query));
793  break;
794 
797  query));
798  break;
799 
802  query));
803  break;
804 
807  query));
808  break;
809 
812  query));
813  break;
814 
817  query));
818  break;
819 
822  query));
823  break;
824 
825  default:
826  elog(ERROR, "unrecognized strategy: %d", strategy);
827  }
828 
829  /* If any check is failed, we have found our answer. */
830  if (!flag)
831  break;
832  }
833 
834  if (flag && in->norderbys > 0)
835  {
836  Oid distfnoid = in->orderbys[0].sk_func.fn_oid;
837 
838  out->distances = spg_key_orderbys_distances(leaf, false,
839  in->orderbys, in->norderbys);
840 
841  /* Recheck is necessary when computing distance to polygon */
842  out->recheckDistances = distfnoid == F_DIST_POLYP;
843  }
844 
845  PG_RETURN_BOOL(flag);
846 }
Datum box_right(PG_FUNCTION_ARGS)
Definition: geo_ops.c:597
Datum box_contained(PG_FUNCTION_ARGS)
Definition: geo_ops.c:669
Datum box_same(PG_FUNCTION_ARGS)
Definition: geo_ops.c:539
Definition: geo_decls.h:99
Datum box_left(PG_FUNCTION_ARGS)
Definition: geo_ops.c:571
#define RTLeftStrategyNumber
Definition: stratnum.h:51
Datum box_overright(PG_FUNCTION_ARGS)
Definition: geo_ops.c:612
Datum box_overlap(PG_FUNCTION_ARGS)
Definition: geo_ops.c:551
#define RTOverBelowStrategyNumber
Definition: stratnum.h:59
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTContainedByStrategyNumber
Definition: stratnum.h:58
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
unsigned int Oid
Definition: postgres_ext.h:31
#define RTBelowStrategyNumber
Definition: stratnum.h:60
#define RTOverAboveStrategyNumber
Definition: stratnum.h:62
#define ERROR
Definition: elog.h:43
ScanKey orderbys
Definition: spgist.h:173
StrategyNumber sk_strategy
Definition: skey.h:68
ScanKey scankeys
Definition: spgist.h:172
Datum box_contain(PG_FUNCTION_ARGS)
Definition: geo_ops.c:680
Datum box_above(PG_FUNCTION_ARGS)
Definition: geo_ops.c:646
char * flag(int b)
Definition: test-ctype.c:33
double * distances
Definition: spgist.h:191
FmgrInfo sk_func
Definition: skey.h:71
#define DatumGetBool(X)
Definition: postgres.h:393
#define RTSameStrategyNumber
Definition: stratnum.h:56
#define RTOverRightStrategyNumber
Definition: stratnum.h:54
#define RTOverLeftStrategyNumber
Definition: stratnum.h:52
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
uintptr_t Datum
Definition: postgres.h:367
Datum box_overbelow(PG_FUNCTION_ARGS)
Definition: geo_ops.c:635
Oid fn_oid
Definition: fmgr.h:59
#define BoxPGetDatum(X)
Definition: geo_decls.h:157
Datum box_below(PG_FUNCTION_ARGS)
Definition: geo_ops.c:623
#define RTAboveStrategyNumber
Definition: stratnum.h:61
#define RTRightStrategyNumber
Definition: stratnum.h:55
Datum box_overleft(PG_FUNCTION_ARGS)
Definition: geo_ops.c:586
#define RTContainsStrategyNumber
Definition: stratnum.h:57
double * spg_key_orderbys_distances(Datum key, bool isLeaf, ScanKey orderbys, int norderbys)
Definition: spgproc.c:63
static BOX * spg_box_quad_get_scankey_bbox(ScanKey sk, bool *recheck)
Definition: geo_spgist.c:531
#define elog(elevel,...)
Definition: elog.h:226
int i
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
Datum box_overabove(PG_FUNCTION_ARGS)
Definition: geo_ops.c:658
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:619

◆ spg_box_quad_picksplit()

Datum spg_box_quad_picksplit ( PG_FUNCTION_ARGS  )

Definition at line 441 of file geo_spgist.c.

References BoxPGetDatum, compareDoubles(), DatumGetBoxP, spgPickSplitIn::datums, getQuadrant(), spgPickSplitOut::hasPrefix, BOX::high, i, spgPickSplitOut::leafTupleDatums, BOX::low, spgPickSplitOut::mapTuplesToNodes, spgPickSplitOut::nNodes, spgPickSplitOut::nodeLabels, spgPickSplitIn::nTuples, palloc(), PG_GETARG_POINTER, PG_RETURN_VOID, spgPickSplitOut::prefixDatum, qsort, Point::x, and Point::y.

442 {
445  BOX *centroid;
446  int median,
447  i;
448  float8 *lowXs = palloc(sizeof(float8) * in->nTuples);
449  float8 *highXs = palloc(sizeof(float8) * in->nTuples);
450  float8 *lowYs = palloc(sizeof(float8) * in->nTuples);
451  float8 *highYs = palloc(sizeof(float8) * in->nTuples);
452 
453  /* Calculate median of all 4D coordinates */
454  for (i = 0; i < in->nTuples; i++)
455  {
456  BOX *box = DatumGetBoxP(in->datums[i]);
457 
458  lowXs[i] = box->low.x;
459  highXs[i] = box->high.x;
460  lowYs[i] = box->low.y;
461  highYs[i] = box->high.y;
462  }
463 
464  qsort(lowXs, in->nTuples, sizeof(float8), compareDoubles);
465  qsort(highXs, in->nTuples, sizeof(float8), compareDoubles);
466  qsort(lowYs, in->nTuples, sizeof(float8), compareDoubles);
467  qsort(highYs, in->nTuples, sizeof(float8), compareDoubles);
468 
469  median = in->nTuples / 2;
470 
471  centroid = palloc(sizeof(BOX));
472 
473  centroid->low.x = lowXs[median];
474  centroid->high.x = highXs[median];
475  centroid->low.y = lowYs[median];
476  centroid->high.y = highYs[median];
477 
478  /* Fill the output */
479  out->hasPrefix = true;
480  out->prefixDatum = BoxPGetDatum(centroid);
481 
482  out->nNodes = 16;
483  out->nodeLabels = NULL; /* We don't need node labels. */
484 
485  out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
486  out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
487 
488  /*
489  * Assign ranges to corresponding nodes according to quadrants relative to
490  * the "centroid" range
491  */
492  for (i = 0; i < in->nTuples; i++)
493  {
494  BOX *box = DatumGetBoxP(in->datums[i]);
495  uint8 quadrant = getQuadrant(centroid, box);
496 
497  out->leafTupleDatums[i] = BoxPGetDatum(box);
498  out->mapTuplesToNodes[i] = quadrant;
499  }
500 
501  PG_RETURN_VOID();
502 }
Definition: geo_decls.h:99
float8 x
Definition: geo_decls.h:57
Datum * leafTupleDatums
Definition: spgist.h:129
Datum * datums
Definition: spgist.h:116
unsigned char uint8
Definition: c.h:356
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
double float8
Definition: c.h:491
Datum * nodeLabels
Definition: spgist.h:126
Point low
Definition: geo_decls.h:101
uintptr_t Datum
Definition: postgres.h:367
#define BoxPGetDatum(X)
Definition: geo_decls.h:157
#define PG_RETURN_VOID()
Definition: fmgr.h:339
float8 y
Definition: geo_decls.h:57
bool hasPrefix
Definition: spgist.h:122
#define DatumGetBoxP(X)
Definition: geo_decls.h:156
Point high
Definition: geo_decls.h:101
static uint8 getQuadrant(BOX *centroid, BOX *inBox)
Definition: geo_spgist.c:130
void * palloc(Size size)
Definition: mcxt.c:949
int i
int * mapTuplesToNodes
Definition: spgist.h:128
static int compareDoubles(const void *a, const void *b)
Definition: geo_spgist.c:93
Datum prefixDatum
Definition: spgist.h:123
#define qsort(a, b, c, d)
Definition: port.h:492

◆ spg_poly_quad_compress()

Datum spg_poly_quad_compress ( PG_FUNCTION_ARGS  )

Definition at line 871 of file geo_spgist.c.

References POLYGON::boundbox, palloc(), PG_GETARG_POLYGON_P, and PG_RETURN_BOX_P.

872 {
873  POLYGON *polygon = PG_GETARG_POLYGON_P(0);
874  BOX *box;
875 
876  box = (BOX *) palloc(sizeof(BOX));
877  *box = polygon->boundbox;
878 
879  PG_RETURN_BOX_P(box);
880 }
Definition: geo_decls.h:99
#define PG_GETARG_POLYGON_P(n)
Definition: geo_decls.h:164
#define PG_RETURN_BOX_P(x)
Definition: geo_decls.h:159
BOX boundbox
Definition: geo_decls.h:114
void * palloc(Size size)
Definition: mcxt.c:949