Changeset 23944


Ignore:
Timestamp:
Feb 11, 2012, 6:07:49 AM (13 years ago)
Author:
Even Rouault
Message:

Spatialite: make use of spatial filter on result layers when the SQL expression is simple enough (no join, etc...) (#4508)

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/autotest/ogr/ogr_sqlite.py

    r23613 r23944  
    12031203        return 'fail'
    12041204
     1205    lyr = ds.GetLayerByName('polygon')
     1206    if lyr is None:
     1207        gdaltest.post_reason('failed')
     1208        return 'fail'
     1209
     1210    if lyr.GetLayerDefn().GetFieldCount() == 0:
     1211        gdaltest.post_reason('failed')
     1212        return 'fail'
     1213
    12051214    return 'success'
    12061215
     
    12881297    srs.SetFromUserInput('EPSG:4326')
    12891298    lyr = ds.CreateLayer( 'test_spatialfilter', srs = srs)
    1290    
     1299    lyr.CreateField(ogr.FieldDefn('intcol', ogr.OFTInteger))
     1300
    12911301    lyr.StartTransaction()
    12921302
     
    13161326        'POLYGON((2 2,2 8,8 8,8 2,2 2))' )
    13171327    lyr.SetSpatialFilter( geom )
    1318     geom.Destroy()
    13191328
    13201329    if lyr.TestCapability(ogr.OLCFastFeatureCount) != True:
     1330        gdaltest.post_reason('OLCFastFeatureCount failed')
    13211331        return 'fail'
    13221332    if lyr.TestCapability(ogr.OLCFastSpatialFilter) != True:
     1333        gdaltest.post_reason('OLCFastSpatialFilter failed')
    13231334        return 'fail'
    13241335
    13251336    if lyr.GetFeatureCount() != 50:
    1326         gdaltest.post_reason('did not get expected feature count(1)')
     1337        gdaltest.post_reason('did not get expected feature count')
    13271338        print(lyr.GetFeatureCount())
    13281339        return 'fail'
     1340
     1341    # Test spatial filter with a SQL result layer without WHERE clause
     1342    sql_lyr = ds.ExecuteSQL("SELECT * FROM 'test_spatialfilter'")
     1343    if sql_lyr.TestCapability(ogr.OLCFastSpatialFilter) != True:
     1344        gdaltest.post_reason('OLCFastSpatialFilter failed')
     1345        return 'fail'
     1346    sql_lyr.SetSpatialFilter( geom )
     1347    if sql_lyr.TestCapability(ogr.OLCFastSpatialFilter) != True:
     1348        gdaltest.post_reason('OLCFastSpatialFilter failed')
     1349        return 'fail'
     1350    if sql_lyr.GetFeatureCount() != 50:
     1351        gdaltest.post_reason('did not get expected feature count')
     1352        print(sql_lyr.GetFeatureCount())
     1353        return 'fail'
     1354    ds.ReleaseResultSet(sql_lyr)
     1355
     1356    # Test spatial filter with a SQL result layer with WHERE clause
     1357    sql_lyr = ds.ExecuteSQL('SELECT * FROM test_spatialfilter WHERE 1=1')
     1358    if sql_lyr.TestCapability(ogr.OLCFastSpatialFilter) != True:
     1359        gdaltest.post_reason('OLCFastSpatialFilter failed')
     1360        return 'fail'
     1361    sql_lyr.SetSpatialFilter( geom )
     1362    if sql_lyr.TestCapability(ogr.OLCFastSpatialFilter) != True:
     1363        gdaltest.post_reason('OLCFastSpatialFilter failed')
     1364        return 'fail'
     1365    if sql_lyr.GetFeatureCount() != 50:
     1366        gdaltest.post_reason('did not get expected feature count')
     1367        print(sql_lyr.GetFeatureCount())
     1368        return 'fail'
     1369    ds.ReleaseResultSet(sql_lyr)
     1370
     1371    # Test spatial filter with a SQL result layer with ORDER BY clause
     1372    sql_lyr = ds.ExecuteSQL('SELECT * FROM test_spatialfilter ORDER BY intcol')
     1373    if sql_lyr.TestCapability(ogr.OLCFastSpatialFilter) != True:
     1374        gdaltest.post_reason('OLCFastSpatialFilter failed')
     1375        return 'fail'
     1376    sql_lyr.SetSpatialFilter( geom )
     1377    if sql_lyr.TestCapability(ogr.OLCFastSpatialFilter) != True:
     1378        gdaltest.post_reason('OLCFastSpatialFilter failed')
     1379        return 'fail'
     1380    if sql_lyr.GetFeatureCount() != 50:
     1381        gdaltest.post_reason('did not get expected feature count')
     1382        print(sql_lyr.GetFeatureCount())
     1383        return 'fail'
     1384    ds.ReleaseResultSet(sql_lyr)
    13291385
    13301386    # Remove spatial index
  • trunk/gdal/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h

    r23736 r23944  
    244244
    245245    int                  HasSpatialIndex() const { return bHasSpatialIndex; }
     246
     247    virtual CPLString     GetSpatialWhere(OGRGeometry* poFilterGeom) { return ""; }
    246248};
    247249
     
    342344
    343345    virtual int          IsTableLayer() { return TRUE; }
     346
     347    virtual CPLString    GetSpatialWhere(OGRGeometry* poFilterGeom);
    344348};
    345349
     
    383387
    384388    virtual int         TestCapability( const char * );
     389
     390    virtual CPLString    GetSpatialWhere(OGRGeometry* poFilterGeom);
    385391};
    386392
     
    391397class OGRSQLiteSelectLayer : public OGRSQLiteLayer
    392398{
    393     CPLString           osSQL;
     399    CPLString           osSQLBase;
     400    CPLString           osSQLCurrent;
    394401
    395402    OGRErr              ResetStatement();
     403
     404    OGRSQLiteLayer     *GetBaseLayer(size_t& i);
     405    void                RebuildSQL();
    396406
    397407  public:
     
    400410                                              sqlite3_stmt * );
    401411                        ~OGRSQLiteSelectLayer();
     412
     413    virtual void        SetSpatialFilter( OGRGeometry * );
     414
     415    virtual int         TestCapability( const char * );
    402416};
    403417
  • trunk/gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteselectlayer.cpp

    r19800 r23944  
    3838
    3939OGRSQLiteSelectLayer::OGRSQLiteSelectLayer( OGRSQLiteDataSource *poDSIn,
    40                                             CPLString osSQL,
     40                                            CPLString osSQLIn,
    4141                                            sqlite3_stmt *hStmtIn )
    4242
     
    5252    sqlite3_finalize( hStmtIn );
    5353
    54     this->osSQL = osSQL;
     54    osSQLBase = osSQLIn;
     55    osSQLCurrent = osSQLIn;
    5556}
    5657
     
    7778    iNextShapeId = 0;
    7879
    79     rc = sqlite3_prepare( poDS->GetDB(), osSQL, osSQL.size(),
     80#ifdef DEBUG
     81    CPLDebug( "OGR_SQLITE", "prepare(%s)", osSQLCurrent.c_str() );
     82#endif
     83
     84    rc = sqlite3_prepare( poDS->GetDB(), osSQLCurrent, osSQLCurrent.size(),
    8085                          &hStmt, NULL );
    8186
     
    8893        CPLError( CE_Failure, CPLE_AppDefined,
    8994                  "In ResetStatement(): sqlite3_prepare(%s):\n  %s",
    90                   osSQL.c_str(), sqlite3_errmsg(poDS->GetDB()) );
     95                  osSQLCurrent.c_str(), sqlite3_errmsg(poDS->GetDB()) );
    9196        hStmt = NULL;
    9297        return OGRERR_FAILURE;
    9398    }
    9499}
     100
     101/************************************************************************/
     102/*                          SetSpatialFilter()                          */
     103/************************************************************************/
     104
     105void OGRSQLiteSelectLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     106
     107{
     108    if( InstallFilter( poGeomIn ) )
     109    {
     110        RebuildSQL();
     111
     112        ResetReading();
     113    }
     114}
     115
     116/************************************************************************/
     117/*                            GetBaseLayer()                            */
     118/************************************************************************/
     119
     120OGRSQLiteLayer* OGRSQLiteSelectLayer::GetBaseLayer(size_t& i)
     121{
     122    char** papszTokens = CSLTokenizeString(osSQLBase.c_str());
     123    int bCanInsertSpatialFilter = TRUE;
     124    int nCountSelect = 0, nCountFrom = 0, nCountWhere = 0;
     125
     126    for(int iToken = 0; papszTokens[iToken] != NULL; iToken++)
     127    {
     128        if (EQUAL(papszTokens[iToken], "SELECT"))
     129            nCountSelect ++;
     130        else if (EQUAL(papszTokens[iToken], "FROM"))
     131            nCountFrom ++;
     132        else if (EQUAL(papszTokens[iToken], "WHERE"))
     133            nCountWhere ++;
     134        else if (EQUAL(papszTokens[iToken], "UNION") ||
     135                 EQUAL(papszTokens[iToken], "JOIN") ||
     136                 EQUAL(papszTokens[iToken], "INTERSECT") ||
     137                 EQUAL(papszTokens[iToken], "EXCEPT"))
     138        {
     139            bCanInsertSpatialFilter = FALSE;
     140        }
     141    }
     142    CSLDestroy(papszTokens);
     143
     144    if (!(bCanInsertSpatialFilter && nCountSelect == 1 && nCountFrom == 1 && nCountWhere <= 1))
     145    {
     146        CPLDebug("SQLITE", "SQL expression too complex to analyse");
     147        return NULL;
     148    }
     149
     150    size_t nFromPos = osSQLBase.ifind(" from ");
     151    if (nFromPos == std::string::npos)
     152    {
     153        return NULL;
     154    }
     155
     156    int bInSingleQuotes = (osSQLBase[nFromPos + 6] == '\'');
     157    CPLString osBaseLayerName;
     158    for( i = nFromPos + 6 + (bInSingleQuotes ? 1 : 0);
     159         i < osSQLBase.size(); i++ )
     160    {
     161        if (osSQLBase[i] == '\'' && i + 1 < osSQLBase.size() &&
     162            osSQLBase[i + 1] == '\'' )
     163        {
     164            osBaseLayerName += osSQLBase[i];
     165            i++;
     166        }
     167        else if (osSQLBase[i] == '\'' && bInSingleQuotes)
     168        {
     169            i++;
     170            break;
     171        }
     172        else if (osSQLBase[i] == ' ' && !bInSingleQuotes)
     173            break;
     174        else
     175            osBaseLayerName += osSQLBase[i];
     176    }
     177
     178    return (OGRSQLiteLayer*) poDS->GetLayerByName(osBaseLayerName);
     179}
     180
     181/************************************************************************/
     182/*                            RebuildSQL()                              */
     183/************************************************************************/
     184
     185void OGRSQLiteSelectLayer::RebuildSQL()
     186
     187{
     188    osSQLCurrent = osSQLBase;
     189
     190    if (m_poFilterGeom == NULL)
     191    {
     192        return;
     193    }
     194
     195    size_t i = 0;
     196    OGRSQLiteLayer* poBaseLayer = GetBaseLayer(i);
     197    if (poBaseLayer == NULL)
     198    {
     199        CPLDebug("SQLITE", "Cannot find base layer");
     200        return;
     201    }
     202
     203    CPLString    osSpatialWhere = poBaseLayer->GetSpatialWhere(m_poFilterGeom);
     204    if (osSpatialWhere.size() == 0)
     205    {
     206        CPLDebug("SQLITE", "Cannot get spatial where clause");
     207        return;
     208    }
     209
     210    while (i < osSQLBase.size() && osSQLBase[i] == ' ')
     211        i ++;
     212
     213    if (i < osSQLBase.size() && EQUALN(osSQLBase.c_str() + i, "WHERE ", 6))
     214    {
     215        osSQLCurrent = osSQLBase.substr(0, i + 6);
     216        osSQLCurrent += osSpatialWhere;
     217        osSQLCurrent += " AND ";
     218        osSQLCurrent += osSQLBase.substr(i + 6);
     219    }
     220    else if (i < osSQLBase.size() &&
     221             (EQUALN(osSQLBase.c_str() + i, "GROUP ", 6) ||
     222              EQUALN(osSQLBase.c_str() + i, "ORDER ", 6) ||
     223              EQUALN(osSQLBase.c_str() + i, "LIMIT ", 6)))
     224    {
     225        osSQLCurrent = osSQLBase.substr(0, i);
     226        osSQLCurrent += " WHERE ";
     227        osSQLCurrent += osSpatialWhere;
     228        osSQLCurrent += " ";
     229        osSQLCurrent += osSQLBase.substr(i);
     230    }
     231    else if (i == osSQLBase.size())
     232    {
     233        osSQLCurrent = osSQLBase.substr(0, i);
     234        osSQLCurrent += " WHERE ";
     235        osSQLCurrent += osSpatialWhere;
     236    }
     237    else
     238    {
     239        CPLDebug("SQLITE", "SQL expression too complex for the driver to insert spatial filter in it");
     240    }
     241}
     242
     243/************************************************************************/
     244/*                           TestCapability()                           */
     245/************************************************************************/
     246
     247int OGRSQLiteSelectLayer::TestCapability( const char * pszCap )
     248
     249{
     250    if (EQUAL(pszCap,OLCFastSpatialFilter))
     251    {
     252        if (osSQLCurrent != osSQLBase)
     253            return TRUE;
     254
     255        size_t i = 0;
     256        OGRSQLiteLayer* poBaseLayer = GetBaseLayer(i);
     257        if (poBaseLayer == NULL)
     258        {
     259            CPLDebug("SQLITE", "Cannot find base layer");
     260            return FALSE;
     261        }
     262
     263        OGRPolygon oFakePoly;
     264        const char* pszWKT = "POLYGON((0 0,0 1,1 1,1 0,0 0))";
     265        oFakePoly.importFromWkt((char**) &pszWKT);
     266        CPLString    osSpatialWhere = poBaseLayer->GetSpatialWhere(&oFakePoly);
     267
     268        return osSpatialWhere.size() != 0;
     269    }
     270    else
     271        return OGRSQLiteLayer::TestCapability( pszCap );
     272}
  • trunk/gdal/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp

    r23942 r23944  
    456456
    457457/************************************************************************/
     458/*                           GetSpatialWhere()                          */
     459/************************************************************************/
     460
     461CPLString OGRSQLiteTableLayer::GetSpatialWhere(OGRGeometry* poFilterGeom)
     462{
     463    CPLString osSpatialWHERE;
     464
     465    if( poFilterGeom != NULL && CheckSpatialIndexTable() )
     466    {
     467        OGREnvelope  sEnvelope;
     468
     469        poFilterGeom->getEnvelope( &sEnvelope );
     470
     471        osSpatialWHERE.Printf("ROWID IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
     472                        "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f AND ymin <= %.12f)",
     473                        pszEscapedTableName, osGeomColumn.c_str(),
     474                        sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
     475                        sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
     476    }
     477
     478    if( poFilterGeom != NULL && bSpatialiteLoaded && !bHasSpatialIndex)
     479    {
     480        OGREnvelope  sEnvelope;
     481
     482        poFilterGeom->getEnvelope( &sEnvelope );
     483
     484        /* A bit inefficient but still faster than OGR filtering */
     485        osSpatialWHERE.Printf("MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f, %d))",
     486                       osGeomColumn.c_str(),
     487                       sEnvelope.MinX - 1e-11, sEnvelope.MinY - 1e-11,
     488                       sEnvelope.MaxX + 1e-11, sEnvelope.MaxY + 1e-11,
     489                       nSRSId);
     490    }
     491
     492    return osSpatialWHERE;
     493}
     494
     495/************************************************************************/
    458496/*                             BuildWhere()                             */
    459497/*                                                                      */
     
    467505    osWHERE = "";
    468506
    469     if( m_poFilterGeom != NULL && CheckSpatialIndexTable() )
    470     {
    471         OGREnvelope  sEnvelope;
    472 
    473         m_poFilterGeom->getEnvelope( &sEnvelope );
    474 
    475         osWHERE.Printf("WHERE ROWID IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
    476                         "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f AND ymin <= %.12f) ",
    477                         pszEscapedTableName, osGeomColumn.c_str(),
    478                         sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
    479                         sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
    480     }
    481 
    482     if( m_poFilterGeom != NULL && bSpatialiteLoaded && !bHasSpatialIndex)
    483     {
    484         OGREnvelope  sEnvelope;
    485 
    486         m_poFilterGeom->getEnvelope( &sEnvelope );
    487 
    488         /* A bit inefficient but still faster than OGR filtering */
    489         osWHERE.Printf("WHERE MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f, %d)) ",
    490                        osGeomColumn.c_str(),
    491                        sEnvelope.MinX - 1e-11, sEnvelope.MinY - 1e-11,
    492                        sEnvelope.MaxX + 1e-11, sEnvelope.MaxY + 1e-11,
    493                        nSRSId);
    494     }
    495 
    496     if( strlen(osQuery) > 0 )
    497     {
    498         if( strlen(osWHERE) == 0 )
    499         {
    500             osWHERE.Printf( "WHERE %s ", osQuery.c_str()  );
     507    CPLString osSpatialWHERE = GetSpatialWhere(m_poFilterGeom);
     508    if (osSpatialWHERE.size() != 0)
     509    {
     510        osWHERE = "WHERE ";
     511        osWHERE += osSpatialWHERE;
     512    }
     513
     514    if( osQuery.size() > 0 )
     515    {
     516        if( osWHERE.size() == 0 )
     517        {
     518            osWHERE = "WHERE ";
     519            osWHERE += osQuery;
    501520        }
    502521        else   
    503522        {
    504             osWHERE += "AND (";
     523            osWHERE += " AND (";
    505524            osWHERE += osQuery;
    506525            osWHERE += ")";
  • trunk/gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp

    r23942 r23944  
    299299
    300300/************************************************************************/
    301 /*                             BuildWhere()                             */
    302 /*                                                                      */
    303 /*      Build the WHERE statement appropriate to the current set of     */
    304 /*      criteria (spatial and attribute queries).                       */
    305 /************************************************************************/
    306 
    307 void OGRSQLiteViewLayer::BuildWhere()
    308 
    309 {
    310     osWHERE = "";
    311 
    312     if( m_poFilterGeom != NULL && bHasSpatialIndex )
     301/*                           GetSpatialWhere()                          */
     302/************************************************************************/
     303
     304CPLString OGRSQLiteViewLayer::GetSpatialWhere(OGRGeometry* poFilterGeom)
     305{
     306    CPLString osSpatialWHERE;
     307
     308    if( poFilterGeom != NULL && bHasSpatialIndex )
    313309    {
    314310        OGREnvelope  sEnvelope;
    315311
    316         m_poFilterGeom->getEnvelope( &sEnvelope );
     312        poFilterGeom->getEnvelope( &sEnvelope );
    317313
    318314        /* We first check that the spatial index table exists */
     
    353349        if (bHasSpatialIndex)
    354350        {
    355             osWHERE.Printf("WHERE %s IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
    356                            "xmax > %.12f AND xmin < %.12f AND ymax > %.12f AND ymin < %.12f) ",
     351            osSpatialWHERE.Printf("%s IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
     352                           "xmax > %.12f AND xmin < %.12f AND ymax > %.12f AND ymin < %.12f)",
    357353                            pszFIDColumn,
    358354                            pszEscapedUnderlyingTableName, osUnderlyingGeometryColumn.c_str(),
     
    368364    }
    369365
    370     if( m_poFilterGeom != NULL && bSpatialiteLoaded && !bHasSpatialIndex )
     366    if( poFilterGeom != NULL && bSpatialiteLoaded && !bHasSpatialIndex )
    371367    {
    372368        OGREnvelope  sEnvelope;
    373369
    374         m_poFilterGeom->getEnvelope( &sEnvelope );
     370        poFilterGeom->getEnvelope( &sEnvelope );
    375371
    376372        /* A bit inefficient but still faster than OGR filtering */
    377         osWHERE.Printf("WHERE MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f)) ",
     373        osSpatialWHERE.Printf("MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f))",
    378374                       osGeomColumn.c_str(),
    379375                       sEnvelope.MinX - 1e-11, sEnvelope.MinY - 1e-11,
     
    381377    }
    382378
    383     if( strlen(osQuery) > 0 )
    384     {
    385         if( strlen(osWHERE) == 0 )
     379    return osSpatialWHERE;
     380}
     381
     382/************************************************************************/
     383/*                             BuildWhere()                             */
     384/*                                                                      */
     385/*      Build the WHERE statement appropriate to the current set of     */
     386/*      criteria (spatial and attribute queries).                       */
     387/************************************************************************/
     388
     389void OGRSQLiteViewLayer::BuildWhere()
     390
     391{
     392    osWHERE = "";
     393
     394    CPLString osSpatialWHERE = GetSpatialWhere(m_poFilterGeom);
     395    if (osSpatialWHERE.size() != 0)
     396    {
     397        osWHERE = "WHERE ";
     398        osWHERE += osSpatialWHERE;
     399    }
     400
     401    if( osQuery.size() > 0 )
     402    {
     403        if( osWHERE.size() == 0 )
    386404        {
    387             osWHERE.Printf( "WHERE %s ", osQuery.c_str()  );
     405            osWHERE = "WHERE ";
     406            osWHERE += osQuery;
    388407        }
    389         else   
     408        else
    390409        {
    391             osWHERE += "AND (";
     410            osWHERE += " AND (";
    392411            osWHERE += osQuery;
    393412            osWHERE += ")";
Note: See TracChangeset for help on using the changeset viewer.