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

Generated by: LCOV version 1.14