Skip to content

Commit

Permalink
OGR GenSQL: optimize (memory-wise) ORDER BY ... LIMIT 1 [OFFSET 0] case.
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.osgeo.org/gdal/trunk@37568 f0d54148-0727-0410-94bb-9a71ac55c965
  • Loading branch information
rouault committed Mar 3, 2017
1 parent 610a9f3 commit c259adb
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 65 deletions.
8 changes: 7 additions & 1 deletion autotest/ogr/ogr_sql_rfc28.py
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ def ogr_rfc28_46():
return 'success'

###############################################################################
# Test
# Test LIMIT and OFFSET

def ogr_rfc28_47():

Expand All @@ -1334,6 +1334,12 @@ def ogr_rfc28_47():
gdaltest.post_reason('fail')
return 'fail'

lyr = gdaltest.ds.ExecuteSQL( "SELECT * FROM POLY WHERE 0 LIMIT 1" )
if lyr.GetNextFeature() is not None:
gdaltest.post_reason('fail')
return 'fail'
gdaltest.ds.ReleaseResultSet( lyr )

lyr = gdaltest.ds.ExecuteSQL( "SELECT * FROM POLY WHERE EAS_ID = 168 LIMIT 11" )
if lyr.GetFeatureCount() != 1:
gdaltest.post_reason('fail')
Expand Down
184 changes: 121 additions & 63 deletions gdal/ogr/ogrsf_frmts/generic/ogr_gensql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1747,7 +1747,8 @@ OGRFeatureDefn *OGRGenSQLResultsLayer::GetLayerDefn()
/************************************************************************/

void OGRGenSQLResultsLayer::FreeIndexFields(OGRField *pasIndexFields,
size_t l_nIndexSize)
size_t l_nIndexSize,
bool bFreeArray)
{
swq_select *psSelectInfo = (swq_select *) pSelectInfo;
const int nOrderItems = psSelectInfo->order_specs;
Expand Down Expand Up @@ -1790,9 +1791,76 @@ void OGRGenSQLResultsLayer::FreeIndexFields(OGRField *pasIndexFields,
}
}

VSIFree(pasIndexFields);
if( bFreeArray )
VSIFree(pasIndexFields);
}

/************************************************************************/
/* ReadIndexFields() */
/************************************************************************/

void OGRGenSQLResultsLayer::ReadIndexFields( OGRFeature* poSrcFeat,
int nOrderItems,
OGRField *pasIndexFields )
{
swq_select *psSelectInfo = (swq_select *) pSelectInfo;
for( int iKey = 0; iKey < nOrderItems; iKey++ )
{
const swq_order_def *psKeyDef = psSelectInfo->order_defs + iKey;
OGRField *psDstField = pasIndexFields + iKey;

if ( psKeyDef->field_index >= iFIDFieldIndex)
{
if ( psKeyDef->field_index <
iFIDFieldIndex + SPECIAL_FIELD_COUNT )
{
switch (SpecialFieldTypes[
psKeyDef->field_index - iFIDFieldIndex])
{
case SWQ_INTEGER:
case SWQ_INTEGER64:
psDstField->Integer64 =
poSrcFeat->GetFieldAsInteger64(
psKeyDef->field_index);
break;

case SWQ_FLOAT:
psDstField->Real =
poSrcFeat->GetFieldAsDouble(psKeyDef->field_index);
break;

default:
psDstField->String = CPLStrdup(
poSrcFeat->GetFieldAsString(
psKeyDef->field_index) );
break;
}
}
continue;
}

OGRFieldDefn *poFDefn = poSrcLayer->GetLayerDefn()->GetFieldDefn(
psKeyDef->field_index );

OGRField *psSrcField =
poSrcFeat->GetRawFieldRef( psKeyDef->field_index );

if( poFDefn->GetType() == OFTInteger
|| poFDefn->GetType() == OFTInteger64
|| poFDefn->GetType() == OFTReal
|| poFDefn->GetType() == OFTDate
|| poFDefn->GetType() == OFTTime
|| poFDefn->GetType() == OFTDateTime)
memcpy( psDstField, psSrcField, sizeof(OGRField) );
else if( poFDefn->GetType() == OFTString )
{
if( poSrcFeat->IsFieldSetAndNotNull( psKeyDef->field_index ) )
psDstField->String = CPLStrdup( psSrcField->String );
else
memcpy( psDstField, psSrcField, sizeof(OGRField) );
}
}
}

/************************************************************************/
/* CreateOrderByIndex() */
Expand Down Expand Up @@ -1829,6 +1897,51 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()

ResetReading();

/* -------------------------------------------------------------------- */
/* Optimize (memory-wise) ORDER BY ... LIMIT 1 [OFFSET 0] case. */
/* -------------------------------------------------------------------- */
if( psSelectInfo->offset == 0 && psSelectInfo->limit == 1 )
{
OGRFeature* poSrcFeat = poSrcLayer->GetNextFeature();
if( poSrcFeat == NULL )
{
panFIDIndex = NULL;
nIndexSize = 0;
return;
}

OGRField *pasCurrentFields = static_cast<OGRField *>(
CPLCalloc(sizeof(OGRField), nOrderItems));
OGRField *pasBestFields = static_cast<OGRField *>(
CPLCalloc(sizeof(OGRField), nOrderItems));
GIntBig nBestFID = poSrcFeat->GetFID();
ReadIndexFields( poSrcFeat, nOrderItems, pasBestFields);
delete poSrcFeat;
while( (poSrcFeat = poSrcLayer->GetNextFeature()) != NULL )
{
ReadIndexFields( poSrcFeat, nOrderItems, pasCurrentFields);
if( Compare( pasCurrentFields, pasBestFields ) < 0 )
{
nBestFID = poSrcFeat->GetFID();
FreeIndexFields( pasBestFields, 1, false);
memcpy( pasBestFields, pasCurrentFields,
sizeof(OGRField) * nOrderItems );
}
else
{
FreeIndexFields( pasCurrentFields, 1, false);
}
memset( pasCurrentFields, 0, sizeof(OGRField) * nOrderItems );
delete poSrcFeat;
}
VSIFree( pasCurrentFields );
FreeIndexFields( pasBestFields, 1 );
panFIDIndex = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
panFIDIndex[0] = nBestFID;
nIndexSize = 1;
return;
}

/* -------------------------------------------------------------------- */
/* Allocate set of key values, and the output index. */
/* -------------------------------------------------------------------- */
Expand Down Expand Up @@ -1902,63 +2015,8 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
nFeaturesAlloc = static_cast<size_t>(nNewFeaturesAlloc);
}

for( int iKey = 0; iKey < nOrderItems; iKey++ )
{
const swq_order_def *psKeyDef = psSelectInfo->order_defs + iKey;
OGRField *psDstField =
pasIndexFields + nIndexSize * nOrderItems + iKey;

if ( psKeyDef->field_index >= iFIDFieldIndex)
{
if ( psKeyDef->field_index <
iFIDFieldIndex + SPECIAL_FIELD_COUNT )
{
switch (SpecialFieldTypes[
psKeyDef->field_index - iFIDFieldIndex])
{
case SWQ_INTEGER:
case SWQ_INTEGER64:
psDstField->Integer64 =
poSrcFeat->GetFieldAsInteger64(
psKeyDef->field_index);
break;

case SWQ_FLOAT:
psDstField->Real =
poSrcFeat->GetFieldAsDouble(psKeyDef->field_index);
break;

default:
psDstField->String = CPLStrdup(
poSrcFeat->GetFieldAsString(
psKeyDef->field_index) );
break;
}
}
continue;
}

OGRFieldDefn *poFDefn = poSrcLayer->GetLayerDefn()->GetFieldDefn(
psKeyDef->field_index );

OGRField *psSrcField =
poSrcFeat->GetRawFieldRef( psKeyDef->field_index );

if( poFDefn->GetType() == OFTInteger
|| poFDefn->GetType() == OFTInteger64
|| poFDefn->GetType() == OFTReal
|| poFDefn->GetType() == OFTDate
|| poFDefn->GetType() == OFTTime
|| poFDefn->GetType() == OFTDateTime)
memcpy( psDstField, psSrcField, sizeof(OGRField) );
else if( poFDefn->GetType() == OFTString )
{
if( poSrcFeat->IsFieldSetAndNotNull( psKeyDef->field_index ) )
psDstField->String = CPLStrdup( psSrcField->String );
else
memcpy( psDstField, psSrcField, sizeof(OGRField) );
}
}
ReadIndexFields( poSrcFeat, nOrderItems,
pasIndexFields + nIndexSize * nOrderItems );

panFIDList[nIndexSize] = poSrcFeat->GetFID();
delete poSrcFeat;
Expand Down Expand Up @@ -2063,16 +2121,16 @@ void OGRGenSQLResultsLayer::SortIndexSection( const OGRField *pasIndexFields,
int nResult = 0;

if( nFirstGroup == 0 )
nResult = -1;
else if( nSecondGroup == 0 )
nResult = 1;
else if( nSecondGroup == 0 )
nResult = -1;
else
nResult = Compare( pasIndexFields
+ panFIDIndex[nFirstStart] * nOrderItems,
pasIndexFields
+ panFIDIndex[nSecondStart] * nOrderItems );

if( nResult < 0 )
if( nResult > 0 )
{
panMerged[iMerge] = panFIDIndex[nSecondStart];
nSecondStart++;
Expand Down Expand Up @@ -2194,7 +2252,7 @@ int OGRGenSQLResultsLayer::Compare( const OGRField *pasFirstTuple,
&pasSecondTuple[iKey]);
}

if( psKeyDef->ascending_flag )
if( !(psKeyDef->ascending_flag) )
nResult *= -1;
}

Expand Down
7 changes: 6 additions & 1 deletion gdal/ogr/ogrsf_frmts/generic/ogr_gensql.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,15 @@ class CPL_DLL OGRGenSQLResultsLayer : public OGRLayer

OGRFeature *TranslateFeature( OGRFeature * );
void CreateOrderByIndex();
void ReadIndexFields( OGRFeature* poSrcFeat,
int nOrderItems,
OGRField *pasIndexFields );
void SortIndexSection( const OGRField *pasIndexFields,
GIntBig *panMerged,
size_t nStart, size_t nEntries );
void FreeIndexFields(OGRField *pasIndexFields, size_t l_nIndexSize);
void FreeIndexFields(OGRField *pasIndexFields,
size_t l_nIndexSize,
bool bFreeArray = true);
int Compare( const OGRField *pasFirst, const OGRField *pasSecond );

void ClearFilters();
Expand Down

0 comments on commit c259adb

Please sign in to comment.