LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sqlite/sqlite_rtree_bulk_load - sqlite_rtree_bulk_load.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 454 521 87.1 %
Date: 2024-11-21 22:18:42 Functions: 32 33 97.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Purpose:  Bulk loading of SQLite R*Tree tables
       4             :  * Author:   Even Rouault <even dot rouault at spatialys dot com>
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2020- 2023 Joshua J Baker
       8             :  * Copyright (c) 2023, Even Rouault <even dot rouault at spatialys dot com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef __STDC_FORMAT_MACROS
      14             : #define __STDC_FORMAT_MACROS
      15             : #endif
      16             : 
      17             : #include "sqlite_rtree_bulk_load.h"
      18             : 
      19             : #include <assert.h>
      20             : #include <inttypes.h>
      21             : #include <math.h>
      22             : #include <stdbool.h>
      23             : #include <stdio.h>
      24             : #include <string.h>
      25             : 
      26             : #if defined(__cplusplus) && !defined(DISABLE_CPLUSPLUS)
      27             : #define USE_CPLUSPLUS
      28             : #endif
      29             : 
      30             : #ifdef USE_CPLUSPLUS
      31             : #include <algorithm>
      32             : #else
      33             : #include <stdlib.h>
      34             : #endif
      35             : 
      36             : #ifdef __cplusplus
      37             : #define STATIC_CAST(type, value) static_cast<type>(value)
      38             : #ifdef NULL
      39             : #undef NULL
      40             : #endif
      41             : #define NULL nullptr
      42             : #undef SQLITE_STATIC
      43             : #define SQLITE_STATIC STATIC_CAST(sqlite3_destructor_type, nullptr)
      44             : #else
      45             : #define STATIC_CAST(type, value) (type)(value)
      46             : #endif
      47             : 
      48             : ////////////////////////////////
      49             : 
      50             : #define DATATYPE int64_t
      51             : #define DIMS 2
      52             : #define NUMTYPE float
      53             : 
      54             : // Cf https://github.com/sqlite/sqlite/blob/90e4a3b7fcdf63035d6f35eb44d11ff58ff4b068/ext/rtree/rtree.c#L262
      55             : #define MAXITEMS 51
      56             : 
      57             : #define BYTES_PER_CELL STATIC_CAST(int, sizeof(int64_t) + 4 * sizeof(float))
      58             : 
      59             : //#ifndef RTREE_NOPATHHINT
      60             : //#define USE_PATHHINT
      61             : //#endif
      62             : 
      63             : enum kind {
      64             :     LEAF = 1,
      65             :     BRANCH = 2,
      66             : };
      67             : 
      68             : struct rect {
      69             :     NUMTYPE min[DIMS];
      70             :     NUMTYPE max[DIMS];
      71             : };
      72             : 
      73             : struct item {
      74             :     DATATYPE data;
      75             : };
      76             : 
      77             : struct node {
      78             :     enum kind kind;     // LEAF or BRANCH
      79             :     int count;          // number of rects
      80             :     struct rect rects[MAXITEMS];
      81             :     union {
      82             :         struct node *nodes[MAXITEMS];
      83             :         struct item datas[MAXITEMS];
      84             :     };
      85             : };
      86             : 
      87             : struct node_MAXITEMS_plus_ONE {
      88             :     enum kind kind;     // LEAF or BRANCH
      89             :     int count;          // number of rects
      90             :     struct rect rects[MAXITEMS+1];
      91             :     union {
      92             :         struct node *nodes[MAXITEMS+1];
      93             :         struct item datas[MAXITEMS+1];
      94             :     };
      95             : };
      96             : 
      97             : struct sqlite_rtree_bl {
      98             :     struct rect rect;
      99             :     struct node *root;
     100             :     size_t count;
     101             :     size_t mem_usage;
     102             :     int height;
     103             :     int node_size;
     104             :     int node_capacity;
     105             : #ifdef USE_PATHHINT
     106             :     int path_hint[16];
     107             : #endif
     108             :     void *(*malloc)(size_t);
     109             :     void (*free)(void *);
     110             : };
     111             : 
     112             : #if defined(__GNUC__) && __GNUC__ >= 4
     113             : #define CPL_UNUSED __attribute((__unused__))
     114             : #else
     115             : #define CPL_UNUSED
     116             : #endif
     117             : 
     118        2197 : static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int v) {
     119             :     (void)v;
     120        2197 : }
     121             : 
     122    67064300 : static inline NUMTYPE min0(NUMTYPE x, NUMTYPE y) {
     123    67064300 :     return x < y ? x : y;
     124             : }
     125             : 
     126    67064300 : static inline NUMTYPE max0(NUMTYPE x, NUMTYPE y) {
     127    67064300 :     return x > y ? x : y;
     128             : }
     129             : 
     130        9744 : static struct node *node_new(struct sqlite_rtree_bl *tr, enum kind kind) {
     131        9744 :     struct node *node = STATIC_CAST(struct node *, tr->malloc(sizeof(struct node)));
     132        9744 :     if (!node) {
     133           0 :         return NULL;
     134             :     }
     135        9744 :     memset(node, 0, sizeof(struct node));
     136        9744 :     node->kind = kind;
     137        9744 :     tr->mem_usage += sizeof(struct node);
     138        9744 :     return node;
     139             : }
     140             : 
     141        9744 : static void node_free(struct sqlite_rtree_bl *tr, struct node *node) {
     142        9744 :     if (node->kind == BRANCH) {
     143        9667 :         for (int i = 0; i < node->count; i++) {
     144        9307 :             node_free(tr, node->nodes[i]);
     145             :         }
     146             :     }
     147        9744 :     tr->mem_usage -= sizeof(struct node);
     148        9744 :     tr->free(node);
     149        9744 : }
     150             : 
     151    18796400 : static void rect_expand(struct rect *rect, const struct rect *other) {
     152    56389100 :     for (int i = 0; i < DIMS; i++) {
     153    37592800 :         rect->min[i] = min0(rect->min[i], other->min[i]);
     154    37592800 :         rect->max[i] = max0(rect->max[i], other->max[i]);
     155             :     }
     156    18796400 : }
     157             : 
     158    15263700 : static double rect_area(const struct rect *rect) {
     159    15263700 :     double result = 1;
     160    45791200 :     for (int i = 0; i < DIMS; i++) {
     161    30527500 :         result *= STATIC_CAST(double, rect->max[i]) - rect->min[i];
     162             :     }
     163    15263700 :     return result;
     164             : }
     165             : 
     166             : // return the area of two rects expanded
     167    14559100 : static double rect_unioned_area(const struct rect *rect,
     168             :                                 const struct rect *other) {
     169    14559100 :     double result = 1;
     170    43677400 :     for (int i = 0; i < DIMS; i++) {
     171    29118300 :         result *= STATIC_CAST(double, max0(rect->max[i], other->max[i])) -
     172    29118300 :                   min0(rect->min[i], other->min[i]);
     173             :     }
     174    14559100 :     return result;
     175             : }
     176             : 
     177    14561200 : static bool rect_contains(const struct rect *rect, const struct rect *other) {
     178    14562700 :     for (int i = 0; i < DIMS; i++) {
     179    14562300 :         if (other->min[i] < rect->min[i])
     180       61747 :             return false;
     181    14500500 :         if (other->max[i] > rect->max[i])
     182    14499000 :             return false;
     183             :     }
     184         460 :     return true;
     185             : }
     186             : 
     187      704140 : static double rect_margin(const struct rect *rect) {
     188      704140 :     return (STATIC_CAST(double, rect->max[0]) - rect->min[0]) +
     189      704140 :            (STATIC_CAST(double, rect->max[1]) - rect->min[1]);
     190             : }
     191             : 
     192      352070 : static double rect_overlap(const struct rect *rect1, const struct rect *rect2) {
     193      352070 :    double overlap = 1;
     194      354406 :    for (int idim = 0; idim < DIMS; ++idim)
     195             :    {
     196      353240 :        double minv = max0(rect1->min[idim], rect2->min[idim]);
     197      353240 :        double maxv = min0(rect1->max[idim], rect2->max[idim]);
     198      353240 :        if( maxv < minv ) {
     199      350904 :            return 0;
     200             :        }
     201        2336 :        overlap *= (maxv - minv);
     202             :    }
     203        1166 :    return overlap;
     204             : }
     205             : 
     206             : typedef struct SortType
     207             : {
     208             :     int i;
     209             : #ifndef USE_CPLUSPLUS
     210             :     struct rect* rects;
     211             : #endif
     212             : } SortType;
     213             : 
     214             : #ifndef USE_CPLUSPLUS
     215             : static int CompareAxis0(const void *a, const void *b)
     216             : {
     217             :     const SortType* sa = STATIC_CAST(const SortType*, a);
     218             :     const SortType* sb = STATIC_CAST(const SortType*, b);
     219             :     if (sa->rects[sa->i].min[0] < sb->rects[sb->i].min[0])
     220             :         return -1;
     221             :     if (sa->rects[sa->i].min[0] == sb->rects[sb->i].min[0])
     222             :     {
     223             :         if (sa->rects[sa->i].max[0] < sb->rects[sb->i].max[0])
     224             :             return -1;
     225             :         if (sa->rects[sa->i].max[0] == sb->rects[sb->i].max[0])
     226             :             return 0;
     227             :         return 1;
     228             :     }
     229             :     return 1;
     230             : }
     231             : 
     232             : static int CompareAxis1(const void *a, const void *b)
     233             : {
     234             :     const SortType* sa = STATIC_CAST(const SortType*, a);
     235             :     const SortType* sb = STATIC_CAST(const SortType*, b);
     236             :     if (sa->rects[sa->i].min[1] < sb->rects[sb->i].min[1])
     237             :         return -1;
     238             :     if (sa->rects[sa->i].min[1] == sb->rects[sb->i].min[1])
     239             :     {
     240             :         if (sa->rects[sa->i].max[1] < sb->rects[sb->i].max[1])
     241             :             return -1;
     242             :         if (sa->rects[sa->i].max[1] == sb->rects[sb->i].max[1])
     243             :             return 0;
     244             :         return 1;
     245             :     }
     246             :     return 1;
     247             : }
     248             : #endif
     249             : 
     250             : // Implementation of the R*-tree variant of SplitNode from Beckman[1990].
     251             : // Cf https://github.com/sqlite/sqlite/blob/5f53f85e22df1c5e1e36106b5e4d1db5089519aa/ext/rtree/rtree.c#L2418
     252        9265 : static bool node_split_rstartree(struct sqlite_rtree_bl *tr,
     253             :                                  struct node *node,
     254             :                                  const struct rect *extraRect,
     255             :                                  struct item extraData,
     256             :                                  struct node *extraNode,
     257             :                                  struct node **right_out) {
     258             :     struct node_MAXITEMS_plus_ONE nodeOri;
     259        9265 :     nodeOri.kind = node->kind;
     260        9265 :     nodeOri.count = node->count;
     261        9265 :     memcpy(nodeOri.rects, node->rects, node->count * sizeof(struct rect));
     262        9265 :     nodeOri.rects[node->count] = *extraRect;
     263        9265 :     if (nodeOri.kind == LEAF) {
     264        8947 :         memcpy(nodeOri.datas, node->datas, node->count * sizeof(struct item));
     265        8947 :         nodeOri.datas[nodeOri.count] = extraData;
     266             :     } else {
     267         318 :         memcpy(nodeOri.nodes, node->nodes, node->count * sizeof(struct node*));
     268         318 :         nodeOri.nodes[nodeOri.count] = extraNode;
     269             :     }
     270        9265 :     nodeOri.count ++;
     271        9265 :     assert(nodeOri.count == tr->node_capacity + 1);
     272             : 
     273             :     SortType aSorted[DIMS][MAXITEMS+1];
     274       27795 :     for (int idim = 0; idim < DIMS; ++idim) {
     275      982090 :         for (int i = 0; i < tr->node_capacity + 1; ++i) {
     276      963560 :             aSorted[idim][i].i = i;
     277             : #ifndef USE_CPLUSPLUS
     278             :             aSorted[idim][i].rects = nodeOri.rects;
     279             : #endif
     280             :         }
     281             :     }
     282             : 
     283             : #ifndef USE_CPLUSPLUS
     284             :     qsort(aSorted[0], nodeOri.count, sizeof(SortType), CompareAxis0);
     285             :     qsort(aSorted[1], nodeOri.count, sizeof(SortType), CompareAxis1);
     286             : #else
     287        9265 :     std::sort(aSorted[0], aSorted[0] + nodeOri.count, [&nodeOri](const SortType& a, const SortType& b) {
     288     3057300 :         return nodeOri.rects[a.i].min[0] < nodeOri.rects[b.i].min[0] ||
     289      715259 :                (nodeOri.rects[a.i].min[0] == nodeOri.rects[b.i].min[0] &&
     290     2343640 :                 nodeOri.rects[a.i].max[0] < nodeOri.rects[b.i].max[0]);
     291             :     });
     292        9265 :     std::sort(aSorted[1], aSorted[1] + nodeOri.count, [&nodeOri](const SortType& a, const SortType& b) {
     293     3056840 :         return nodeOri.rects[a.i].min[1] < nodeOri.rects[b.i].min[1] ||
     294      716511 :                (nodeOri.rects[a.i].min[1] == nodeOri.rects[b.i].min[1] &&
     295     2343880 :                 nodeOri.rects[a.i].max[1] < nodeOri.rects[b.i].max[1]);
     296             :     });
     297             : #endif
     298             : 
     299        9265 :     int iBestDim = 0;
     300        9265 :     int iBestSplit = tr->node_capacity / 2;
     301        9265 :     double fBestMargin = INFINITY;
     302       27795 :     for (int idim = 0; idim < DIMS; ++idim) {
     303       18530 :         double margin = 0;
     304       18530 :         double fBestOverlap = INFINITY;
     305       18530 :         double fBestArea = INFINITY;
     306       18530 :         int iBestLeft = 0;
     307       18530 :         const int minItems = tr->node_capacity / 3;
     308      370600 :         for (int nLeft = minItems; nLeft <= nodeOri.count - minItems; ++nLeft) {
     309      352070 :             struct rect rectLeft = nodeOri.rects[aSorted[idim][0].i];
     310      352070 :             struct rect rectRight = nodeOri.rects[aSorted[idim][nodeOri.count-1].i];
     311    17955600 :             for(int kk=1; kk<(nodeOri.count-1); kk++) {
     312    17603500 :                 if( kk<nLeft ){
     313     8801750 :                   rect_expand(&rectLeft, &nodeOri.rects[aSorted[idim][kk].i]);
     314             :                 }else{
     315     8801750 :                   rect_expand(&rectRight, &nodeOri.rects[aSorted[idim][kk].i]);
     316             :                 }
     317             :             }
     318      352070 :             margin += rect_margin(&rectLeft);
     319      352070 :             margin += rect_margin(&rectRight);
     320      352070 :             double overlap = rect_overlap(&rectLeft, &rectRight);
     321      352070 :             double area = rect_area(&rectLeft) + rect_area(&rectRight);
     322      352070 :             if( overlap<fBestOverlap || (overlap==fBestOverlap && area<fBestArea)) {
     323      184815 :                 iBestLeft = nLeft;
     324      184815 :                 fBestOverlap = overlap;
     325      184815 :                 fBestArea = area;
     326             :             }
     327             :         }
     328             : 
     329       18530 :         if (margin<fBestMargin) {
     330        9273 :           iBestDim = idim;
     331        9273 :           fBestMargin = margin;
     332        9273 :           iBestSplit = iBestLeft;
     333             :         }
     334             :     }
     335             : 
     336        9265 :     struct node *right = node_new(tr, node->kind);
     337        9265 :     if (!right) {
     338           0 :         return false;
     339             :     }
     340        9265 :     node->count = 0;
     341        9265 :     int i = 0;
     342      250003 :     for (; i < iBestSplit; ++i) {
     343      240738 :         struct node* target = node;
     344      240738 :         target->rects[target->count] = nodeOri.rects[aSorted[iBestDim][i].i];
     345      240738 :         if (nodeOri.kind == LEAF) {
     346      232470 :             target->datas[target->count] = nodeOri.datas[aSorted[iBestDim][i].i];
     347             :         } else {
     348        8268 :             target->nodes[target->count] = nodeOri.nodes[aSorted[iBestDim][i].i];
     349             :         }
     350      240738 :         ++target->count;
     351             :     }
     352      250307 :     for (; i < nodeOri.count; ++i) {
     353      241042 :         struct node* target = right;
     354      241042 :         target->rects[target->count] = nodeOri.rects[aSorted[iBestDim][i].i];
     355      241042 :         if (nodeOri.kind == LEAF) {
     356      232774 :             target->datas[target->count] = nodeOri.datas[aSorted[iBestDim][i].i];
     357             :         } else {
     358        8268 :             target->nodes[target->count] = nodeOri.nodes[aSorted[iBestDim][i].i];
     359             :         }
     360      241042 :         ++target->count;
     361             :     }
     362        9265 :     *right_out = right;
     363        9265 :     return true;
     364             : }
     365             : 
     366      503023 : static int node_choose_least_enlargement(const struct node *node,
     367             :                                          const struct rect *ir) {
     368      503023 :     int j = 0;
     369      503023 :     double jenlarge = INFINITY;
     370      503023 :     double minarea = 0;
     371    15062200 :     for (int i = 0; i < node->count; i++) {
     372             :         // calculate the enlarged area
     373    14559100 :         double uarea = rect_unioned_area(&node->rects[i], ir);
     374    14559100 :         double area = rect_area(&node->rects[i]);
     375    14559100 :         double enlarge = uarea - area;
     376    14559100 :         if (enlarge < jenlarge || (enlarge == jenlarge && area < minarea)) {
     377    14501600 :             j = i;
     378    14501600 :             jenlarge = enlarge;
     379    14501600 :             minarea = area;
     380             :         }
     381             :     }
     382      503023 :     return j;
     383             : }
     384             : 
     385      503461 : static int node_choose(struct sqlite_rtree_bl * tr,
     386             :                        const struct node *node,
     387             :                        const struct rect *rect,
     388             :                        int depth)
     389             : {
     390             : #ifndef USE_PATHHINT
     391             :     (void)tr;
     392             :     (void)depth;
     393             : #endif
     394             : 
     395             : #ifdef USE_PATHHINT
     396             :     int h = tr->path_hint[depth];
     397             :     if (h < node->count) {
     398             :         if (rect_contains(&node->rects[h], rect)) {
     399             :             return h;
     400             :         }
     401             :     }
     402             : #endif
     403             : 
     404             :     // Take a quick look for the first node that contain the rect.
     405      503461 :     int iBestIndex = -1;
     406      503461 :     double minArea = INFINITY;
     407    15064600 :     for (int i = 0; i < node->count; i++) {
     408    14561200 :         if (rect_contains(&node->rects[i], rect)) {
     409         460 :             double area = rect_area(&node->rects[i]);
     410         460 :             if( area < minArea )
     411             :             {
     412         456 :                 iBestIndex = i;
     413         456 :                 minArea = area;
     414             :             }
     415             :         }
     416             :     }
     417      503461 :     if (iBestIndex >= 0) {
     418             : #ifdef USE_PATHHINT
     419             :         tr->path_hint[depth] = iBestIndex;
     420             : #endif
     421         438 :         return iBestIndex;
     422             :     }
     423             : 
     424             :     // Fallback to using che "choose least enlargement" algorithm.
     425      503023 :     int i = node_choose_least_enlargement(node, rect);
     426             : #ifdef USE_PATHHINT
     427             :     tr->path_hint[depth] = i;
     428             : #endif
     429      503023 :     return i;
     430             : }
     431             : 
     432       18530 : static struct rect node_rect_calc(const struct node *node) {
     433       18530 :     struct rect rect = node->rects[0];
     434      481780 :     for (int i = 1; i < node->count; i++) {
     435      463250 :         rect_expand(&rect, &node->rects[i]);
     436             :     }
     437       18530 :     return rect;
     438             : }
     439             : 
     440             : // node_insert returns false if out of memory
     441      738894 : static bool node_insert(struct sqlite_rtree_bl *tr,
     442             :                         struct node *node,
     443             :                         const struct rect *ir,
     444             :                         struct item item,
     445             :                         int depth,
     446             :                         bool *split,
     447             :                         struct rect *rectToInsert,
     448             :                         struct item *itemToInsert,
     449             :                         struct node** nodeToInsert)
     450             : {
     451      738894 :     if (node->kind == LEAF) {
     452      235433 :         if (node->count == tr->node_capacity) {
     453        8947 :             *split = true;
     454        8947 :             *rectToInsert = *ir;
     455        8947 :             *itemToInsert = item;
     456        8947 :             *nodeToInsert = NULL;
     457        8947 :             return true;
     458             :         }
     459      226486 :         int index = node->count;
     460      226486 :         node->rects[index] = *ir;
     461      226486 :         node->datas[index] = item;
     462      226486 :         node->count++;
     463      226486 :         *split = false;
     464      226486 :         return true;
     465             :     }
     466             :     // Choose a subtree for inserting the rectangle.
     467      503461 :     const int i = node_choose(tr, node, ir, depth);
     468      503461 :     if (!node_insert(tr, node->nodes[i], ir, item, depth+1,
     469             :                      split, rectToInsert, itemToInsert, nodeToInsert))
     470             :     {
     471           0 :         return false;
     472             :     }
     473      503461 :     if (!*split) {
     474      494238 :         rect_expand(&node->rects[i], ir);
     475      494238 :         *split = false;
     476      494238 :         return true;
     477             :     }
     478             : 
     479             :     struct node *right;
     480        9223 :     if (!node_split_rstartree(tr, node->nodes[i], rectToInsert,
     481             :                               *itemToInsert, *nodeToInsert, &right)) {
     482           0 :         return false;
     483             :     }
     484        9223 :     node->rects[i] = node_rect_calc(node->nodes[i]);
     485             : 
     486             :     // split the child node
     487        9223 :     if (node->count == tr->node_capacity) {
     488         318 :         *split = true;
     489         318 :         *rectToInsert = node_rect_calc(right);
     490         318 :         *nodeToInsert = right;
     491         318 :         itemToInsert->data = -1;
     492         318 :         return true;
     493             :     }
     494             : 
     495        8905 :     *split = false;
     496        8905 :     node->rects[node->count] = node_rect_calc(right);
     497        8905 :     node->nodes[node->count] = right;
     498        8905 :     node->count++;
     499        8905 :     return true;
     500             : }
     501             : 
     502             : static
     503         625 : struct sqlite_rtree_bl *sqlite_rtree_bl_new_with_allocator(int sqlite_page_size,
     504             :                                               void *(*pfnMalloc)(size_t),
     505             :                                               void (*pfnFree)(void*)) {
     506         625 :     if (!pfnMalloc)
     507         625 :         pfnMalloc = malloc;
     508         625 :     if (!pfnFree)
     509         625 :         pfnFree = free;
     510         625 :     struct sqlite_rtree_bl *tr = STATIC_CAST(struct sqlite_rtree_bl *, pfnMalloc(sizeof(struct sqlite_rtree_bl)));
     511         625 :     if (!tr) return NULL;
     512         625 :     memset(tr, 0, sizeof(struct sqlite_rtree_bl));
     513         625 :     tr->malloc = pfnMalloc;
     514         625 :     tr->free = pfnFree;
     515             : 
     516             :     // Cf https://github.com/sqlite/sqlite/blob/90e4a3b7fcdf63035d6f35eb44d11ff58ff4b068/ext/rtree/rtree.c#L3541
     517         625 :     tr->node_size = sqlite_page_size-64;
     518         625 :     if( tr->node_size > 4+BYTES_PER_CELL*MAXITEMS ){
     519         625 :         tr->node_size = 4+BYTES_PER_CELL*MAXITEMS;
     520             :     }
     521         625 :     tr->node_capacity = (tr->node_size-4)/BYTES_PER_CELL;
     522         625 :     tr->mem_usage = sizeof(struct sqlite_rtree_bl);
     523             : 
     524         625 :     return tr;
     525             : }
     526             : 
     527         625 : struct sqlite_rtree_bl *SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_new)(int sqlite_page_size) {
     528         625 :     return sqlite_rtree_bl_new_with_allocator(sqlite_page_size, NULL, NULL);
     529             : }
     530             : 
     531             : // Cf https://github.com/sqlite/sqlite/blob/90e4a3b7fcdf63035d6f35eb44d11ff58ff4b068/ext/rtree/rtree.c#L2993C1-L2995C3
     532             : /*
     533             : ** Rounding constants for float->double conversion.
     534             : */
     535             : #define RNDTOWARDS  (1.0 - 1.0/8388608.0)  /* Round towards zero */
     536             : #define RNDAWAY     (1.0 + 1.0/8388608.0)  /* Round away from zero */
     537             : 
     538             : /*
     539             : ** Convert an sqlite3_value into an RtreeValue (presumably a float)
     540             : ** while taking care to round toward negative or positive, respectively.
     541             : */
     542      470866 : static float rtreeValueDown(double d){
     543      470866 :   float f = STATIC_CAST(float, d);
     544      470866 :   if( f>d ){
     545       10065 :     f = STATIC_CAST(float, d*(d<0 ? RNDAWAY : RNDTOWARDS));
     546             :   }
     547      470866 :   return f;
     548             : }
     549      470866 : static float rtreeValueUp(double d){
     550      470866 :   float f = STATIC_CAST(float, d);
     551      470866 :   if( f<d ){
     552       10061 :     f = STATIC_CAST(float, d*(d<0 ? RNDTOWARDS : RNDAWAY));
     553             :   }
     554      470866 :   return f;
     555             : }
     556             : 
     557      235433 : bool SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_insert)(struct sqlite_rtree_bl *tr,
     558             :                          int64_t fid,
     559             :                          double minx, double miny,
     560             :                          double maxx, double maxy)
     561             : {
     562      235433 :     if( !(minx <= maxx) || !(miny <= maxy) )
     563           0 :         return false;
     564             : 
     565             :     // copy input rect
     566             :     struct rect rect;
     567      235433 :     rect.min[0] = rtreeValueDown(minx);
     568      235433 :     rect.min[1] = rtreeValueDown(miny);
     569      235433 :     rect.max[0] = rtreeValueUp(maxx);
     570      235433 :     rect.max[1] = rtreeValueUp(maxy);
     571             : 
     572             :     // copy input data
     573             :     struct item item;
     574      235433 :     item.data = fid;
     575             : 
     576             :     struct rect rectToInsert;
     577             :     struct item itemToInsert;
     578             :     struct node* nodeToInsert;
     579             : 
     580      235433 :     if (!tr->root) {
     581         437 :         struct node *new_root = node_new(tr, LEAF);
     582         437 :         if (!new_root) {
     583           0 :             return false;
     584             :         }
     585         437 :         tr->root = new_root;
     586         437 :         tr->rect = rect;
     587         437 :         tr->height = 1;
     588             :     }
     589      235433 :     bool split = false;
     590      235433 :     if (!node_insert(tr, tr->root, &rect, item, 0,
     591             :                      &split, &rectToInsert, &itemToInsert, &nodeToInsert)) {
     592           0 :         return false;
     593             :     }
     594      235433 :     if (!split) {
     595      235391 :         rect_expand(&tr->rect, &rect);
     596      235391 :         tr->count++;
     597      235391 :         return true;
     598             :     }
     599          42 :     struct node *new_root = node_new(tr, BRANCH);
     600          42 :     if (!new_root) {
     601           0 :         return false;
     602             :     }
     603             :     struct node *right;
     604          42 :     if (!node_split_rstartree(tr, tr->root, &rectToInsert, itemToInsert, nodeToInsert, &right)) {
     605           0 :         tr->free(new_root);
     606           0 :         return false;
     607             :     }
     608          42 :     new_root->rects[0] = node_rect_calc(tr->root);
     609          42 :     new_root->rects[1] = node_rect_calc(right);
     610          42 :     new_root->nodes[0] = tr->root;
     611          42 :     new_root->nodes[1] = right;
     612          42 :     tr->root = new_root;
     613          42 :     tr->root->count = 2;
     614          42 :     tr->height++;
     615             : 
     616          42 :     return true;
     617             : }
     618             : 
     619      235441 : size_t SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_ram_usage)(const sqlite_rtree_bl* tr) {
     620      235441 :     return tr->mem_usage;
     621             : }
     622             : 
     623         625 : void SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_free)(struct sqlite_rtree_bl *tr) {
     624         625 :     if (tr) {
     625         625 :         if (tr->root) {
     626         437 :             node_free(tr, tr->root);
     627             :         }
     628         625 :         tr->free(tr);
     629             :     }
     630         625 : }
     631             : 
     632       19416 : static void write_be_uint16(uint8_t* dest, uint16_t n) {
     633       19416 :     dest[0] = STATIC_CAST(uint8_t, n >> 8);
     634       19416 :     dest[1] = STATIC_CAST(uint8_t, n);
     635       19416 : }
     636             : 
     637      244380 : static void write_be_int64(uint8_t* dest, int64_t i) {
     638      244380 :     const uint64_t n = i;
     639      244380 :     dest[0] = STATIC_CAST(uint8_t, n >> 56);
     640      244380 :     dest[1] = STATIC_CAST(uint8_t, n >> 48);
     641      244380 :     dest[2] = STATIC_CAST(uint8_t, n >> 40);
     642      244380 :     dest[3] = STATIC_CAST(uint8_t, n >> 32);
     643      244380 :     dest[4] = STATIC_CAST(uint8_t, n >> 24);
     644      244380 :     dest[5] = STATIC_CAST(uint8_t, n >> 16);
     645      244380 :     dest[6] = STATIC_CAST(uint8_t, n >> 8);
     646      244380 :     dest[7] = STATIC_CAST(uint8_t, n);
     647      244380 : }
     648             : 
     649      977520 : static void write_be_float(uint8_t* dest, float f) {
     650             :     uint32_t n;
     651      977520 :     memcpy(&n, &f, sizeof(float));
     652      977520 :     dest[0] = STATIC_CAST(uint8_t, n >> 24);
     653      977520 :     dest[1] = STATIC_CAST(uint8_t, n >> 16);
     654      977520 :     dest[2] = STATIC_CAST(uint8_t, n >> 8);
     655      977520 :     dest[3] = STATIC_CAST(uint8_t, n);
     656      977520 : }
     657             : 
     658           0 : static char* my_sqlite3_strdup(const char* s) {
     659           0 :     if( !s )
     660           0 :         return NULL;
     661           0 :     const int n = STATIC_CAST(int, strlen(s));
     662           0 :     char* new_s = STATIC_CAST(char*, sqlite3_malloc(n+1));
     663           0 :     memcpy(new_s, s, n+1);
     664           0 :     return new_s;
     665             : }
     666             : 
     667             : typedef struct rtree_insert_context
     668             : {
     669             :     sqlite3* hDB;
     670             :     sqlite3_stmt* hStmtNode;
     671             :     sqlite3_stmt* hStmtParent;
     672             :     sqlite3_stmt* hStmtRowid;
     673             :     int node_capacity;
     674             :     int tree_height;
     675             :     char** p_error_msg;
     676             : } rtree_insert_context;
     677             : 
     678             : typedef enum
     679             : {
     680             :     PASS_ALL,
     681             :     PASS_NODE,
     682             :     PASS_PARENT,
     683             :     PASS_ROWID,
     684             : } PassType;
     685             : 
     686       29124 : static bool insert_into_db(const struct rtree_insert_context* ctxt,
     687             :                            const struct node* node,
     688             :                            int64_t* p_cur_nodeno,
     689             :                            int64_t parent_nodeno,
     690             :                            PassType pass) {
     691       29124 :     const int64_t this_cur_nodeno = (*p_cur_nodeno);
     692       29124 :     uint8_t blob[4 + MAXITEMS * BYTES_PER_CELL] = {0};
     693       29124 :     size_t offset = 4;
     694             : 
     695       29124 :     if (node->kind == BRANCH) {
     696       29001 :         for (int i = 0; i < node->count; ++i) {
     697       27921 :             ++(*p_cur_nodeno);
     698             : 
     699       27921 :             if (pass == PASS_ALL || pass == PASS_NODE) {
     700        9307 :                 write_be_int64(blob + offset, (*p_cur_nodeno));
     701        9307 :                 offset += sizeof(int64_t);
     702             : 
     703        9307 :                 const float minx = node->rects[i].min[0];
     704        9307 :                 write_be_float(blob + offset, minx);
     705        9307 :                 offset += sizeof(float);
     706             : 
     707        9307 :                 const float maxx = node->rects[i].max[0];
     708        9307 :                 write_be_float(blob + offset, maxx);
     709        9307 :                 offset += sizeof(float);
     710             : 
     711        9307 :                 const float miny = node->rects[i].min[1];
     712        9307 :                 write_be_float(blob + offset, miny);
     713        9307 :                 offset += sizeof(float);
     714             : 
     715        9307 :                 const float maxy = node->rects[i].max[1];
     716        9307 :                 write_be_float(blob + offset, maxy);
     717        9307 :                 offset += sizeof(float);
     718             :             }
     719             : 
     720       27921 :             if (!insert_into_db(ctxt, node->nodes[i], p_cur_nodeno,
     721             :                                 this_cur_nodeno, pass)) {
     722           0 :                 return false;
     723             :             }
     724             :         }
     725             :     }
     726       28044 :     else if (pass == PASS_ALL || pass == PASS_NODE || pass == PASS_ROWID) {
     727      488842 :         for (int i = 0; i < node->count; ++i ) {
     728      470146 :             const int64_t fid = node->datas[i].data;
     729      470146 :             if( pass == PASS_ALL || pass == PASS_NODE )
     730             :             {
     731      235073 :                 write_be_int64(blob + offset, fid);
     732      235073 :                 offset += sizeof(int64_t);
     733             : 
     734      235073 :                 const float minx = node->rects[i].min[0];
     735      235073 :                 write_be_float(blob + offset, minx);
     736      235073 :                 offset += sizeof(float);
     737             : 
     738      235073 :                 const float maxx = node->rects[i].max[0];
     739      235073 :                 write_be_float(blob + offset, maxx);
     740      235073 :                 offset += sizeof(float);
     741             : 
     742      235073 :                 const float miny = node->rects[i].min[1];
     743      235073 :                 write_be_float(blob + offset, miny);
     744      235073 :                 offset += sizeof(float);
     745             : 
     746      235073 :                 const float maxy = node->rects[i].max[1];
     747      235073 :                 write_be_float(blob + offset, maxy);
     748      235073 :                 offset += sizeof(float);
     749             :             }
     750             : 
     751      470146 :             if (pass == PASS_ALL || pass == PASS_ROWID) {
     752      235073 :                 sqlite3_reset(ctxt->hStmtRowid);
     753      235073 :                 sqlite3_bind_int64(ctxt->hStmtRowid, 1, fid);
     754      235073 :                 sqlite3_bind_int64(ctxt->hStmtRowid, 2, this_cur_nodeno);
     755      235073 :                 int ret = sqlite3_step(ctxt->hStmtRowid);
     756      235073 :                 if (ret != SQLITE_OK && ret != SQLITE_DONE) {
     757           0 :                     if (ctxt->p_error_msg) {
     758           0 :                         *ctxt->p_error_msg = my_sqlite3_strdup(sqlite3_errmsg(ctxt->hDB));
     759             :                     }
     760           0 :                     return false;
     761             :                 }
     762             :             }
     763             :         }
     764             :     }
     765             : 
     766       29124 :     if (pass == PASS_ALL || pass == PASS_NODE) {
     767        9708 :         write_be_uint16(blob, STATIC_CAST(uint16_t, parent_nodeno == 0 ? ctxt->tree_height - 1 : 0));
     768        9708 :         write_be_uint16(blob + 2, STATIC_CAST(uint16_t, node->count));
     769             : 
     770        9708 :         sqlite3_reset(ctxt->hStmtNode);
     771        9708 :         sqlite3_bind_int64(ctxt->hStmtNode, 1, this_cur_nodeno);
     772        9708 :         sqlite3_bind_blob(ctxt->hStmtNode, 2, blob,
     773        9708 :                           4 + ctxt->node_capacity * BYTES_PER_CELL,
     774             :                           SQLITE_STATIC);
     775        9708 :         int ret = sqlite3_step(ctxt->hStmtNode);
     776        9708 :         if (ret != SQLITE_OK && ret != SQLITE_DONE) {
     777           0 :             if (ctxt->p_error_msg) {
     778           0 :                 *ctxt->p_error_msg = my_sqlite3_strdup(sqlite3_errmsg(ctxt->hDB));
     779             :             }
     780           0 :             return false;
     781             :         }
     782             :     }
     783             : 
     784       29124 :     if ((pass == PASS_ALL || pass == PASS_PARENT) && parent_nodeno > 0) {
     785        9307 :         sqlite3_reset(ctxt->hStmtParent);
     786        9307 :         sqlite3_bind_int64(ctxt->hStmtParent, 1, this_cur_nodeno);
     787        9307 :         sqlite3_bind_int64(ctxt->hStmtParent, 2, parent_nodeno);
     788        9307 :         int ret = sqlite3_step(ctxt->hStmtParent);
     789        9307 :         if (ret != SQLITE_OK && ret != SQLITE_DONE) {
     790           0 :             if (ctxt->p_error_msg) {
     791           0 :                 *ctxt->p_error_msg = my_sqlite3_strdup(sqlite3_errmsg(ctxt->hDB));
     792             :             }
     793           0 :             return false;
     794             :         }
     795             :     }
     796             : 
     797       29124 :     return true;
     798             : }
     799             : 
     800       13547 : static bool IsLowercaseAlpha(const char* s)
     801             : {
     802       13547 :     for (; *s != 0; ++s) {
     803       10602 :         if (!(*s >= 'a' && *s <= 'z')) {
     804           0 :             return false;
     805             :         }
     806             :     }
     807        2945 :     return true;
     808             : }
     809             : 
     810         589 : bool SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_serialize)(
     811             :                                const struct sqlite_rtree_bl *tr,
     812             :                                sqlite3* hDB,
     813             :                                const char* rtree_name,
     814             :                                const char* rowid_colname,
     815             :                                const char* minx_colname,
     816             :                                const char* miny_colname,
     817             :                                const char* maxx_colname,
     818             :                                const char* maxy_colname,
     819             :                                char** p_error_msg) {
     820         589 :     if (p_error_msg) {
     821         589 :         *p_error_msg = NULL;
     822             :     }
     823             : 
     824             :     char* sql;
     825        1178 :     if (IsLowercaseAlpha(rowid_colname) &&
     826        1178 :         IsLowercaseAlpha(minx_colname) &&
     827        1178 :         IsLowercaseAlpha(maxx_colname) &&
     828        1767 :         IsLowercaseAlpha(miny_colname) &&
     829         589 :         IsLowercaseAlpha(maxy_colname)) {
     830             :         /* To make OGC GeoPackage compliance test happy... */
     831         589 :         sql = sqlite3_mprintf(
     832             :             "CREATE VIRTUAL TABLE \"%w\" USING rtree(%s, %s, %s, %s, %s)",
     833             :             rtree_name, rowid_colname, minx_colname, maxx_colname, miny_colname,
     834             :             maxy_colname);
     835             :     }
     836             :     else {
     837           0 :         sql = sqlite3_mprintf(
     838             :             "CREATE VIRTUAL TABLE \"%w\" USING rtree(\"%w\", \"%w\", \"%w\", \"%w\", \"%w\")",
     839             :             rtree_name, rowid_colname, minx_colname, maxx_colname, miny_colname,
     840             :             maxy_colname);
     841             :     }
     842         589 :     int ret = sqlite3_exec(hDB, sql, NULL, NULL, p_error_msg);
     843         589 :     sqlite3_free(sql);
     844         589 :     if (ret != SQLITE_OK) {
     845           0 :         return false;
     846             :     }
     847             : 
     848         589 :     if (tr->count == 0) {
     849         188 :         return true;
     850             :     }
     851             : 
     852             :     // Suppress default root node
     853         401 :     sql = sqlite3_mprintf("DELETE FROM \"%w_node\"", rtree_name);
     854         401 :     ret = sqlite3_exec(hDB, sql, NULL, NULL, p_error_msg);
     855         401 :     sqlite3_free(sql);
     856         401 :     if (ret != SQLITE_OK) {
     857           0 :         return false;
     858             :     }
     859             : 
     860         401 :     sqlite3_stmt *hStmtNode = NULL;
     861         401 :     sql = sqlite3_mprintf("INSERT INTO \"%w_node\" VALUES (?, ?)", rtree_name);
     862         401 :     CPL_IGNORE_RET_VAL_INT(sqlite3_prepare_v2(hDB, sql, -1, &hStmtNode, NULL));
     863         401 :     sqlite3_free(sql);
     864         401 :     if (!hStmtNode) {
     865           0 :         return false;
     866             :     }
     867             : 
     868         401 :     sqlite3_stmt *hStmtParent = NULL;
     869         401 :     sql = sqlite3_mprintf("INSERT INTO \"%w_parent\" VALUES (?, ?)", rtree_name);
     870         401 :     CPL_IGNORE_RET_VAL_INT(sqlite3_prepare_v2(hDB, sql, -1, &hStmtParent, NULL));
     871         401 :     sqlite3_free(sql);
     872         401 :     if (!hStmtParent) {
     873           0 :         sqlite3_finalize(hStmtNode);
     874           0 :         return false;
     875             :     }
     876             : 
     877         401 :     sqlite3_stmt *hStmtRowid = NULL;
     878         401 :     sql = sqlite3_mprintf("INSERT INTO \"%w_rowid\" VALUES (?, ?)", rtree_name);
     879         401 :     CPL_IGNORE_RET_VAL_INT(sqlite3_prepare_v2(hDB, sql, -1, &hStmtRowid, NULL));
     880         401 :     sqlite3_free(sql);
     881         401 :     if (!hStmtRowid) {
     882           0 :         sqlite3_finalize(hStmtNode);
     883           0 :         sqlite3_finalize(hStmtParent);
     884           0 :         return false;
     885             :     }
     886             : 
     887             :     rtree_insert_context ctxt;
     888         401 :     ctxt.hDB = hDB;
     889         401 :     ctxt.hStmtNode = hStmtNode;
     890         401 :     ctxt.hStmtParent = hStmtParent;
     891         401 :     ctxt.hStmtRowid = hStmtRowid;
     892         401 :     ctxt.node_capacity = tr->node_capacity;
     893         401 :     ctxt.tree_height = tr->height;
     894         401 :     ctxt.p_error_msg = p_error_msg;
     895             : 
     896         401 :     int64_t cur_nodeno = 1;
     897         401 :     bool ok = insert_into_db(&ctxt, tr->root, &cur_nodeno, 0, PASS_NODE);
     898         401 :     if (ok) {
     899         401 :         cur_nodeno = 1;
     900         401 :         ok = insert_into_db(&ctxt, tr->root, &cur_nodeno, 0, PASS_PARENT);
     901             :     }
     902         401 :     if (ok) {
     903         401 :         cur_nodeno = 1;
     904         401 :         ok = insert_into_db(&ctxt, tr->root, &cur_nodeno, 0, PASS_ROWID);
     905             :     }
     906             : 
     907         401 :     sqlite3_finalize(hStmtNode);
     908         401 :     sqlite3_finalize(hStmtParent);
     909         401 :     sqlite3_finalize(hStmtRowid);
     910         401 :     return ok;
     911             : }
     912             : 
     913             : #define NOTIFICATION_INTERVAL (500 * 1000)
     914             : 
     915         577 : bool SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_from_feature_table)(
     916             :                                sqlite3* hDB,
     917             :                                const char* feature_table_name,
     918             :                                const char* feature_table_fid_colname,
     919             :                                const char* feature_table_geom_colname,
     920             :                                const char* rtree_name,
     921             :                                const char* rowid_colname,
     922             :                                const char* minx_colname,
     923             :                                const char* miny_colname,
     924             :                                const char* maxx_colname,
     925             :                                const char* maxy_colname,
     926             :                                size_t max_ram_usage,
     927             :                                char** p_error_msg,
     928             :                                sqlite_rtree_progress_callback progress_cbk,
     929             :                                void* progress_cbk_user_data)
     930             : {
     931         577 :     char** papszResult = NULL;
     932         577 :     sqlite3_get_table(hDB, "PRAGMA page_size", &papszResult, NULL, NULL, NULL);
     933         577 :     const int page_size = atoi(papszResult[1]);
     934         577 :     sqlite3_free_table(papszResult);
     935             : 
     936         577 :     struct sqlite_rtree_bl* t = SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_new)(page_size);
     937         577 :     if (!t) {
     938           0 :         if (p_error_msg)
     939           0 :             *p_error_msg = my_sqlite3_strdup("not enough memory");
     940           0 :         return false;
     941             :     }
     942             : 
     943         577 :     sqlite3_stmt *hStmt = NULL;
     944             :     char *pszSQL =
     945         577 :             sqlite3_mprintf("SELECT \"%w\", ST_MinX(\"%w\"), ST_MaxX(\"%w\"), "
     946             :                             "ST_MinY(\"%w\"), ST_MaxY(\"%w\") FROM \"%w\" "
     947             :                             "WHERE \"%w\" NOT NULL AND NOT ST_IsEmpty(\"%w\")",
     948             :                             feature_table_fid_colname,
     949             :                             feature_table_geom_colname,
     950             :                             feature_table_geom_colname,
     951             :                             feature_table_geom_colname,
     952             :                             feature_table_geom_colname,
     953             :                             feature_table_name,
     954             :                             feature_table_geom_colname,
     955             :                             feature_table_geom_colname);
     956         577 :     CPL_IGNORE_RET_VAL_INT(sqlite3_prepare_v2(hDB, pszSQL, -1, &hStmt, NULL));
     957         577 :     sqlite3_free(pszSQL);
     958         577 :     if (!hStmt) {
     959           0 :         if (p_error_msg)
     960           0 :             *p_error_msg = my_sqlite3_strdup(sqlite3_errmsg(hDB));
     961           0 :         SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_free)(t);
     962           0 :         return false;
     963             :     }
     964             : 
     965         577 :     bool bMaxMemReached = false;
     966         577 :     uint64_t nRows = 0;
     967      231634 :     while (sqlite3_step(hStmt) == SQLITE_ROW) {
     968      231069 :         int64_t id = sqlite3_column_int64(hStmt, 0);
     969      231069 :         const double minx = sqlite3_column_double(hStmt, 1);
     970      231069 :         const double maxx = sqlite3_column_double(hStmt, 2);
     971      231069 :         const double miny = sqlite3_column_double(hStmt, 3);
     972      231069 :         const double maxy = sqlite3_column_double(hStmt, 4);
     973      231069 :         if (!SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_insert)(t, id, minx, miny, maxx, maxy)) {
     974           0 :             bMaxMemReached = true;
     975           0 :             break;
     976             :         }
     977      462138 :         if (max_ram_usage != 0 &&
     978      231069 :             SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_ram_usage)(t) > max_ram_usage) {
     979          12 :             bMaxMemReached = true;
     980          12 :             break;
     981             :         }
     982      231057 :         if (progress_cbk && ((++nRows) % NOTIFICATION_INTERVAL) == 0) {
     983             :             char szMsg[256];
     984           0 :             snprintf(szMsg, sizeof(szMsg),
     985             :                      "%" PRIu64 " rows inserted in %s (in RAM)",
     986             :                      nRows, rtree_name);
     987           0 :             if (!progress_cbk(szMsg, progress_cbk_user_data)) {
     988           0 :                 SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_free)(t);
     989           0 :                 sqlite3_finalize(hStmt);
     990           0 :                 if (p_error_msg)
     991           0 :                     *p_error_msg = my_sqlite3_strdup("Processing interrupted");
     992           0 :                 return false;
     993             :             }
     994             :         }
     995             :     }
     996             : 
     997         577 :     bool bOK = SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_serialize)(
     998             :                                t, hDB,
     999             :                                rtree_name,
    1000             :                                rowid_colname,
    1001             :                                minx_colname,
    1002             :                                miny_colname,
    1003             :                                maxx_colname,
    1004             :                                maxy_colname,
    1005             :                                p_error_msg);
    1006             : 
    1007         577 :     SQLITE_RTREE_BL_SYMBOL(sqlite_rtree_bl_free)(t);
    1008             : 
    1009         577 :     if (bOK && bMaxMemReached) {
    1010          12 :         if (progress_cbk) {
    1011          12 :             CPL_IGNORE_RET_VAL_INT(progress_cbk(
    1012             :                 "Max RAM reached. Falling back to slower "
    1013             :                 "insertion method", progress_cbk_user_data));
    1014             :         }
    1015             : 
    1016          12 :         sqlite3_stmt *hStmtInsert = NULL;
    1017             :         pszSQL =
    1018          12 :                 sqlite3_mprintf("INSERT INTO \"%w\" VALUES (?,?,?,?,?)",
    1019             :                                 rtree_name);
    1020          12 :         CPL_IGNORE_RET_VAL_INT(sqlite3_prepare_v2(hDB, pszSQL, -1, &hStmtInsert, NULL));
    1021          12 :         sqlite3_free(pszSQL);
    1022          12 :         if (!hStmtInsert) {
    1023           0 :             if (p_error_msg)
    1024           0 :                 *p_error_msg = my_sqlite3_strdup(sqlite3_errmsg(hDB));
    1025           0 :             sqlite3_finalize(hStmt);
    1026           0 :             return false;
    1027             :         }
    1028       11200 :         while (sqlite3_step(hStmt) == SQLITE_ROW) {
    1029       11188 :             int64_t id = sqlite3_column_int64(hStmt, 0);
    1030       11188 :             const double minx = sqlite3_column_double(hStmt, 1);
    1031       11188 :             const double maxx = sqlite3_column_double(hStmt, 2);
    1032       11188 :             const double miny = sqlite3_column_double(hStmt, 3);
    1033       11188 :             const double maxy = sqlite3_column_double(hStmt, 4);
    1034             : 
    1035       11188 :             sqlite3_reset(hStmtInsert);
    1036       11188 :             sqlite3_bind_int64(hStmtInsert, 1, id);
    1037       11188 :             sqlite3_bind_double(hStmtInsert, 2, minx);
    1038       11188 :             sqlite3_bind_double(hStmtInsert, 3, maxx);
    1039       11188 :             sqlite3_bind_double(hStmtInsert, 4, miny);
    1040       11188 :             sqlite3_bind_double(hStmtInsert, 5, maxy);
    1041       11188 :             int ret = sqlite3_step(hStmtInsert);
    1042       11188 :             if (ret != SQLITE_OK && ret != SQLITE_DONE) {
    1043           0 :                 if (p_error_msg)
    1044           0 :                     *p_error_msg = my_sqlite3_strdup(sqlite3_errmsg(hDB));
    1045           0 :                 bOK = false;
    1046           0 :                 break;
    1047             :             }
    1048       11188 :             if (progress_cbk && ((++nRows) % NOTIFICATION_INTERVAL) == 0) {
    1049             :                 char szMsg[256];
    1050           0 :                 snprintf(szMsg, sizeof(szMsg),
    1051             :                          "%" PRIu64 " rows inserted in %s", nRows, rtree_name);
    1052           0 :                 if (!progress_cbk(szMsg, progress_cbk_user_data)) {
    1053           0 :                     bOK = false;
    1054           0 :                     if (p_error_msg)
    1055           0 :                         *p_error_msg = my_sqlite3_strdup("Processing interrupted");
    1056           0 :                     break;
    1057             :                 }
    1058             :             }
    1059             :         }
    1060          12 :         sqlite3_finalize(hStmtInsert);
    1061             :     }
    1062             : 
    1063         577 :     if (bOK && progress_cbk && (nRows % NOTIFICATION_INTERVAL) != 0)
    1064             :     {
    1065             :         char szMsg[256];
    1066         393 :         snprintf(szMsg, sizeof(szMsg), "%" PRIu64 " rows inserted in %s",
    1067             :                  nRows, rtree_name);
    1068         393 :         CPL_IGNORE_RET_VAL_INT(progress_cbk(szMsg, progress_cbk_user_data));
    1069             :     }
    1070             : 
    1071         577 :     sqlite3_finalize(hStmt);
    1072         577 :     return bOK;
    1073             : }

Generated by: LCOV version 1.14