Incremental check-in: Progress toward implementing the geopoly vtab.
FossilOrigin-Name: 9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61
This commit is contained in:
parent
748b8fda90
commit
66c43599ce
@ -270,7 +270,7 @@ static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){
|
||||
const unsigned char *a = sqlite3_value_blob(pVal);
|
||||
int nVertex;
|
||||
nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
|
||||
if( (a[0]==0 && a[0]==1)
|
||||
if( (a[0]==0 || a[0]==1)
|
||||
&& (nVertex*2*sizeof(GeoCoord) + 4)==nByte
|
||||
){
|
||||
p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
|
||||
@ -407,6 +407,79 @@ static void geopolyAreaFunc(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute a bound-box on a polygon. Return a new GeoPoly object
|
||||
** that describes the bounding box. Or, if aCoord is not a NULL pointer
|
||||
** fill it in with the bounding box instead.
|
||||
*/
|
||||
static GeoPoly *geopolyBBox(
|
||||
sqlite3_context *context, /* For recording the error */
|
||||
sqlite3_value *pPoly, /* The polygon */
|
||||
double *aCoord /* Results here */
|
||||
){
|
||||
GeoPoly *p = geopolyFuncParam(context, pPoly);
|
||||
GeoPoly *pOut;
|
||||
if( p ){
|
||||
int ii;
|
||||
float mnX, mxX, mnY, mxY;
|
||||
mnX = mxX = p->a[0];
|
||||
mnY = mxY = p->a[1];
|
||||
for(ii=1; ii<p->nVertex; ii++){
|
||||
double r = p->a[ii*2];
|
||||
if( r<mnX ) mnX = r;
|
||||
else if( r>mxX ) mxX = r;
|
||||
r = p->a[ii*2+1];
|
||||
if( r<mnY ) mnY = r;
|
||||
else if( r>mxY ) mxY = r;
|
||||
}
|
||||
if( aCoord==0 ){
|
||||
pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6);
|
||||
if( pOut==0 ){
|
||||
sqlite3_free(p);
|
||||
sqlite3_result_error_nomem(context);
|
||||
return 0;
|
||||
}
|
||||
pOut->nVertex = 4;
|
||||
pOut->hdr[1] = 0;
|
||||
pOut->hdr[2] = 0;
|
||||
pOut->hdr[3] = 4;
|
||||
pOut->a[0] = mnX;
|
||||
pOut->a[1] = mnY;
|
||||
pOut->a[2] = mxX;
|
||||
pOut->a[3] = mnY;
|
||||
pOut->a[4] = mxX;
|
||||
pOut->a[5] = mxY;
|
||||
pOut->a[6] = mnX;
|
||||
pOut->a[7] = mxY;
|
||||
return pOut;
|
||||
}else{
|
||||
sqlite3_free(p);
|
||||
aCoord[0] = mnX;
|
||||
aCoord[1] = mxX;
|
||||
aCoord[2] = mnY;
|
||||
aCoord[3] = mxY;
|
||||
return (GeoPoly*)aCoord;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the geopoly_bbox(X) SQL function.
|
||||
*/
|
||||
static void geopolyBBoxFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
GeoPoly *p = geopolyBBox(context, argv[0], 0);
|
||||
if( p ){
|
||||
sqlite3_result_blob(context, p->hdr,
|
||||
4+8*p->nVertex, SQLITE_TRANSIENT);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
|
||||
** Returns:
|
||||
@ -828,6 +901,429 @@ static void geopolyDebugFunc(
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is the implementation of both the xConnect and xCreate
|
||||
** methods of the geopoly virtual table.
|
||||
**
|
||||
** argv[0] -> module name
|
||||
** argv[1] -> database name
|
||||
** argv[2] -> table name
|
||||
** argv[...] -> column names...
|
||||
*/
|
||||
static int geopolyInit(
|
||||
sqlite3 *db, /* Database connection */
|
||||
void *pAux, /* One of the RTREE_COORD_* constants */
|
||||
int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */
|
||||
sqlite3_vtab **ppVtab, /* OUT: New virtual table */
|
||||
char **pzErr, /* OUT: Error message, if any */
|
||||
int isCreate /* True for xCreate, false for xConnect */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
Rtree *pRtree;
|
||||
int nDb; /* Length of string argv[1] */
|
||||
int nName; /* Length of string argv[2] */
|
||||
sqlite3_str *pSql;
|
||||
char *zSql;
|
||||
int ii;
|
||||
char cSep;
|
||||
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
|
||||
|
||||
/* Allocate the sqlite3_vtab structure */
|
||||
nDb = (int)strlen(argv[1]);
|
||||
nName = (int)strlen(argv[2]);
|
||||
pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2);
|
||||
if( !pRtree ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
|
||||
pRtree->nBusy = 1;
|
||||
pRtree->base.pModule = &rtreeModule;
|
||||
pRtree->zDb = (char *)&pRtree[1];
|
||||
pRtree->zName = &pRtree->zDb[nDb+1];
|
||||
pRtree->eCoordType = RTREE_COORD_REAL32;
|
||||
pRtree->nDim = 2;
|
||||
pRtree->nDim2 = 4;
|
||||
memcpy(pRtree->zDb, argv[1], nDb);
|
||||
memcpy(pRtree->zName, argv[2], nName);
|
||||
|
||||
|
||||
/* Create/Connect to the underlying relational database schema. If
|
||||
** that is successful, call sqlite3_declare_vtab() to configure
|
||||
** the r-tree table schema.
|
||||
*/
|
||||
pSql = sqlite3_str_new(db);
|
||||
sqlite3_str_appendf(pSql, "CREATE TABLE x");
|
||||
cSep = '(';
|
||||
for(ii=3; ii<argc; ii++){
|
||||
pRtree->nAux++;
|
||||
sqlite3_str_appendf(pSql, "%c%s", cSep, argv[ii]+1);
|
||||
cSep = ',';
|
||||
}
|
||||
sqlite3_str_appendf(pSql, "%c _poly HIDDEN, _bbox HIDDEN);", cSep);
|
||||
zSql = sqlite3_str_finish(pSql);
|
||||
if( !zSql ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
if( rc ) goto geopolyInit_fail;
|
||||
pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
|
||||
|
||||
/* Figure out the node size to use. */
|
||||
rc = getNodeSize(db, pRtree, isCreate, pzErr);
|
||||
if( rc ) goto geopolyInit_fail;
|
||||
rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
|
||||
if( rc ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
goto geopolyInit_fail;
|
||||
}
|
||||
|
||||
*ppVtab = (sqlite3_vtab *)pRtree;
|
||||
return SQLITE_OK;
|
||||
|
||||
geopolyInit_fail:
|
||||
if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
|
||||
assert( *ppVtab==0 );
|
||||
assert( pRtree->nBusy==1 );
|
||||
rtreeRelease(pRtree);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** GEOPOLY virtual table module xCreate method.
|
||||
*/
|
||||
static int geopolyCreate(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** GEOPOLY virtual table module xConnect method.
|
||||
*/
|
||||
static int geopolyConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** GEOPOLY virtual table module xBestIndex method. There are three
|
||||
** table scan strategies to choose from (in order from most to
|
||||
** least desirable):
|
||||
**
|
||||
** idxNum idxStr Strategy
|
||||
** ------------------------------------------------
|
||||
** 1 Unused Direct lookup by rowid.
|
||||
** 2 'Fx' shape query
|
||||
** 2 '' full-table scan.
|
||||
** ------------------------------------------------
|
||||
**
|
||||
** If strategy 1 is used, then idxStr is not meaningful. If strategy
|
||||
** 2 is used, idxStr is either the two-byte string 'Fx' or an empty
|
||||
** string.
|
||||
*/
|
||||
static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
Rtree *pRtree = (Rtree*)tab;
|
||||
int rc = SQLITE_OK;
|
||||
int ii;
|
||||
int bMatch = 0; /* True if there exists a MATCH constraint */
|
||||
i64 nRow; /* Estimated rows returned by this scan */
|
||||
|
||||
int iIdx = 0;
|
||||
char zIdxStr[3];
|
||||
memset(zIdxStr, 0, sizeof(zIdxStr));
|
||||
|
||||
/* Check if there exists a MATCH constraint - even an unusable one. If there
|
||||
** is, do not consider the lookup-by-rowid plan as using such a plan would
|
||||
** require the VDBE to evaluate the MATCH constraint, which is not currently
|
||||
** possible. */
|
||||
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
|
||||
if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){
|
||||
bMatch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert( pIdxInfo->idxStr==0 );
|
||||
for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
|
||||
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
|
||||
|
||||
if( bMatch==0
|
||||
&& p->usable
|
||||
&& p->iColumn<0
|
||||
&& p->op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||
){
|
||||
/* We have an equality constraint on the rowid. Use strategy 1. */
|
||||
int jj;
|
||||
for(jj=0; jj<ii; jj++){
|
||||
pIdxInfo->aConstraintUsage[jj].argvIndex = 0;
|
||||
pIdxInfo->aConstraintUsage[jj].omit = 0;
|
||||
}
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->aConstraintUsage[ii].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[jj].omit = 1;
|
||||
|
||||
/* This strategy involves a two rowid lookups on an B-Tree structures
|
||||
** and then a linear search of an R-Tree node. This should be
|
||||
** considered almost as quick as a direct rowid lookup (for which
|
||||
** sqlite uses an internal cost of 0.0). It is expected to return
|
||||
** a single row.
|
||||
*/
|
||||
pIdxInfo->estimatedCost = 30.0;
|
||||
pIdxInfo->estimatedRows = 1;
|
||||
pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* A MATCH operator against the _shape column */
|
||||
if( p->usable
|
||||
&& p->iColumn==pRtree->nAux
|
||||
&& p->op==SQLITE_INDEX_CONSTRAINT_MATCH
|
||||
){
|
||||
zIdxStr[0] = RTREE_MATCH;
|
||||
zIdxStr[1] = 'x';
|
||||
zIdxStr[2] = 0;
|
||||
pIdxInfo->aConstraintUsage[ii].argvIndex = 0;
|
||||
pIdxInfo->aConstraintUsage[ii].omit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
pIdxInfo->idxNum = 2;
|
||||
pIdxInfo->needToFreeIdxStr = 1;
|
||||
if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
nRow = pRtree->nRowEst/100 + 5;
|
||||
pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
|
||||
pIdxInfo->estimatedRows = nRow;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** GEOPOLY virtual table module xColumn method.
|
||||
*/
|
||||
static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
||||
Rtree *pRtree = (Rtree *)cur->pVtab;
|
||||
RtreeCursor *pCsr = (RtreeCursor *)cur;
|
||||
RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
|
||||
int rc = SQLITE_OK;
|
||||
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
|
||||
|
||||
if( rc ) return rc;
|
||||
if( p==0 ) return SQLITE_OK;
|
||||
if( i<=pRtree->nAux ){
|
||||
if( !pCsr->bAuxValid ){
|
||||
if( pCsr->pReadAux==0 ){
|
||||
rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
|
||||
&pCsr->pReadAux, 0);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
sqlite3_bind_int64(pCsr->pReadAux, 1,
|
||||
nodeGetRowid(pRtree, pNode, p->iCell));
|
||||
rc = sqlite3_step(pCsr->pReadAux);
|
||||
if( rc==SQLITE_ROW ){
|
||||
pCsr->bAuxValid = 1;
|
||||
}else{
|
||||
sqlite3_reset(pCsr->pReadAux);
|
||||
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
sqlite3_result_value(ctx,
|
||||
sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1));
|
||||
}else{
|
||||
/* Must be the _bbox column */
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The xUpdate method for GEOPOLY module virtual tables.
|
||||
*/
|
||||
static int geopolyUpdate(
|
||||
sqlite3_vtab *pVtab,
|
||||
int nData,
|
||||
sqlite3_value **aData,
|
||||
sqlite_int64 *pRowid
|
||||
){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
// RtreeCell cell; /* New cell to insert if nData>1 */
|
||||
// int bHaveRowid = 0; /* Set to 1 after new rowid is determined */
|
||||
// int iShapeCol; /* Index of the _shape column */
|
||||
|
||||
if( pRtree->nNodeRef ){
|
||||
/* Unable to write to the btree while another cursor is reading from it,
|
||||
** since the write might do a rebalance which would disrupt the read
|
||||
** cursor. */
|
||||
return SQLITE_LOCKED_VTAB;
|
||||
}
|
||||
rtreeReference(pRtree);
|
||||
assert(nData>=1);
|
||||
|
||||
// cell.iRowid = 0; /* Used only to suppress a compiler warning */
|
||||
// iShapeCol = pRtree->nAux;
|
||||
|
||||
rc = SQLITE_ERROR;
|
||||
|
||||
#if 0
|
||||
|
||||
/* Constraint handling. A write operation on an r-tree table may return
|
||||
** SQLITE_CONSTRAINT for two reasons:
|
||||
**
|
||||
** 1. A duplicate rowid value, or
|
||||
** 2. The supplied data violates the "x2>=x1" constraint.
|
||||
**
|
||||
** In the first case, if the conflict-handling mode is REPLACE, then
|
||||
** the conflicting row can be removed before proceeding. In the second
|
||||
** case, SQLITE_CONSTRAINT must be returned regardless of the
|
||||
** conflict-handling mode specified by the user.
|
||||
*/
|
||||
if( nData>1
|
||||
&& (!sqlite3_value_nochange(aData[iShapeCol+2])
|
||||
){
|
||||
|
||||
#ifndef SQLITE_RTREE_INT_ONLY
|
||||
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
|
||||
for(ii=0; ii<nn; ii+=2){
|
||||
cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]);
|
||||
cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]);
|
||||
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
|
||||
rc = rtreeConstraintError(pRtree, ii+1);
|
||||
goto constraint;
|
||||
}
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
for(ii=0; ii<nn; ii+=2){
|
||||
cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]);
|
||||
cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]);
|
||||
if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
|
||||
rc = rtreeConstraintError(pRtree, ii+1);
|
||||
goto constraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If a rowid value was supplied, check if it is already present in
|
||||
** the table. If so, the constraint has failed. */
|
||||
if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){
|
||||
cell.iRowid = sqlite3_value_int64(aData[2]);
|
||||
if( sqlite3_value_type(aData[0])==SQLITE_NULL
|
||||
|| sqlite3_value_int64(aData[0])!=cell.iRowid
|
||||
){
|
||||
int steprc;
|
||||
sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
|
||||
steprc = sqlite3_step(pRtree->pReadRowid);
|
||||
rc = sqlite3_reset(pRtree->pReadRowid);
|
||||
if( SQLITE_ROW==steprc ){
|
||||
if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
|
||||
rc = rtreeDeleteRowid(pRtree, cell.iRowid);
|
||||
}else{
|
||||
rc = rtreeConstraintError(pRtree, 0);
|
||||
goto constraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
bHaveRowid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If aData[0] is not an SQL NULL value, it is the rowid of a
|
||||
** record to delete from the r-tree table. The following block does
|
||||
** just that.
|
||||
*/
|
||||
if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){
|
||||
rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0]));
|
||||
}
|
||||
|
||||
/* If the aData[] array contains more than one element, elements
|
||||
** (aData[2]..aData[argc-1]) contain a new record to insert into
|
||||
** the r-tree structure.
|
||||
*/
|
||||
if( rc==SQLITE_OK && nData>1 ){
|
||||
/* Insert the new record into the r-tree */
|
||||
RtreeNode *pLeaf = 0;
|
||||
|
||||
/* Figure out the rowid of the new row. */
|
||||
if( bHaveRowid==0 ){
|
||||
rc = newRowid(pRtree, &cell.iRowid);
|
||||
}
|
||||
*pRowid = cell.iRowid;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
int rc2;
|
||||
pRtree->iReinsertHeight = -1;
|
||||
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
|
||||
rc2 = nodeRelease(pRtree, pLeaf);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = rc2;
|
||||
}
|
||||
}
|
||||
if( pRtree->nAux ){
|
||||
sqlite3_stmt *pUp = pRtree->pWriteAux;
|
||||
int jj;
|
||||
sqlite3_bind_int64(pUp, 1, *pRowid);
|
||||
for(jj=0; jj<pRtree->nAux; jj++){
|
||||
sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]);
|
||||
}
|
||||
sqlite3_step(pUp);
|
||||
rc = sqlite3_reset(pUp);
|
||||
}
|
||||
}
|
||||
constraint:
|
||||
#endif /* 0 */
|
||||
|
||||
rtreeRelease(pRtree);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static sqlite3_module geopolyModule = {
|
||||
2, /* iVersion */
|
||||
geopolyCreate, /* xCreate - create a table */
|
||||
geopolyConnect, /* xConnect - connect to an existing table */
|
||||
geopolyBestIndex, /* xBestIndex - Determine search strategy */
|
||||
rtreeDisconnect, /* xDisconnect - Disconnect from a table */
|
||||
rtreeDestroy, /* xDestroy - Drop a table */
|
||||
rtreeOpen, /* xOpen - open a cursor */
|
||||
rtreeClose, /* xClose - close a cursor */
|
||||
rtreeFilter, /* xFilter - configure scan constraints */
|
||||
rtreeNext, /* xNext - advance a cursor */
|
||||
rtreeEof, /* xEof */
|
||||
geopolyColumn, /* xColumn - read data */
|
||||
rtreeRowid, /* xRowid - read data */
|
||||
geopolyUpdate, /* xUpdate - write data */
|
||||
rtreeBeginTransaction, /* xBegin - begin transaction */
|
||||
rtreeEndTransaction, /* xSync - sync transaction */
|
||||
rtreeEndTransaction, /* xCommit - commit transaction */
|
||||
rtreeEndTransaction, /* xRollback - rollback transaction */
|
||||
0, /* xFindFunction - function overloading */
|
||||
rtreeRename, /* xRename - rename the table */
|
||||
rtreeSavepoint, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
};
|
||||
|
||||
static int sqlite3_geopoly_init(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
static const struct {
|
||||
@ -842,6 +1338,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
||||
{ geopolyWithinFunc, 3, "geopoly_within" },
|
||||
{ geopolyOverlapFunc, 2, "geopoly_overlap" },
|
||||
{ geopolyDebugFunc, 1, "geopoly_debug" },
|
||||
{ geopolyBBoxFunc, 1, "geopoly_bbox" },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
@ -849,5 +1346,8 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
||||
SQLITE_UTF8, 0,
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
||||
C Forward\sport\sthe\sgeopoly\sextension\sfunctions\sinto\sthe\sr-tree\sextension,\nwith\sthe\sidea\sof\screating\sa\snew\sspatial\sindex\sbased\son\ssimply\spolygons.
|
||||
D 2018-05-25T19:22:47.258
|
||||
C Incremental\scheck-in:\sProgress\stoward\simplementing\sthe\sgeopoly\svtab.
|
||||
D 2018-05-25T20:53:42.012
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 51407f0e371dcb9e65d368bd4f1a08fc17ef8361ff11aac9356f0f63693b38dd
|
||||
@ -355,7 +355,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
|
||||
F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f
|
||||
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/geopoly.c bde931e25e378780f50650bab8810a868e85dbea70f29188193d717eb121c476 w ext/rtree/polygon.c
|
||||
F ext/rtree/geopoly.c bf7a5fc70df145e83b60abd3e9828ad036921a9603087f5f108e054d75f12abc
|
||||
F ext/rtree/rtree.c 2fd3c149c6fc4d3fdf602dc610b34ad9abdf75cca26d0c362f903aa02ea2ef47
|
||||
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
|
||||
F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349
|
||||
@ -1730,10 +1730,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P b816023ce07d01024d5769e16db924374a49bf909edd12dc1344a0a1ef693db5
|
||||
R c65edfd057806e76a349cce4c936be8c
|
||||
T *branch * rtree-geopoly
|
||||
T *sym-rtree-geopoly *
|
||||
T -sym-trunk *
|
||||
P 0593aac88a8c25ddafba4c29a181ee083dfc3dab44335feb6f12fdea6ce7fb27
|
||||
R 36e4ed5dc1a640520059a271545fd8c3
|
||||
U drh
|
||||
Z 27c7d298825e4848f2fc61f45fe7bda5
|
||||
Z b8c6ea17872c9a8b20afb569a3513051
|
||||
|
@ -1 +1 @@
|
||||
0593aac88a8c25ddafba4c29a181ee083dfc3dab44335feb6f12fdea6ce7fb27
|
||||
9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61
|
Loading…
x
Reference in New Issue
Block a user