OGRLayer * OGRDataSource::ExecuteSQL( const char *pszStatement, OGRGeometry *poSpatialFilter, const char *pszDialect ) { const char *pszError; swq_select *psSelectInfo = NULL; (void) pszDialect; /* -------------------------------------------------------------------- */ /* Handle CREATE INDEX statements specially. */ /* -------------------------------------------------------------------- */ if( EQUALN(pszStatement,"CREATE INDEX",12) ) { ProcessSQLCreateIndex( pszStatement ); return NULL; } /* -------------------------------------------------------------------- */ /* Handle DROP INDEX statements specially. */ /* -------------------------------------------------------------------- */ if( EQUALN(pszStatement,"DROP INDEX",10) ) { ProcessSQLDropIndex( pszStatement ); return NULL; } /* -------------------------------------------------------------------- */ /* Preparse the SQL statement. */ /* -------------------------------------------------------------------- */ pszError = swq_select_preparse( pszStatement, &psSelectInfo ); if( pszError != NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "SQL: %s", pszError ); return NULL; } /* -------------------------------------------------------------------- */ /* Validate that all the source tables are recognised, count */ /* fields. */ /* -------------------------------------------------------------------- */ int nFieldCount = 0, iTable; for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ ) { swq_table_def *psTableDef = psSelectInfo->table_defs + iTable; OGRLayer *poSrcLayer; OGRDataSource *poTableDS = this; if( psTableDef->data_source != NULL ) { poTableDS = (OGRDataSource *) OGROpenShared( psTableDef->data_source, FALSE, NULL ); if( poTableDS == NULL ) { if( strlen(CPLGetLastErrorMsg()) == 0 ) CPLError( CE_Failure, CPLE_AppDefined, "Unable to open secondary datasource\n" "`%s' required by JOIN.", psTableDef->data_source ); swq_select_free( psSelectInfo ); return NULL; } // This drops explicit reference, but leave it open for use by // code in ogr_gensql.cpp poTableDS->Dereference(); } poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name ); if( poSrcLayer == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "SELECT from table %s failed, no such table/featureclass.", psTableDef->table_name ); swq_select_free( psSelectInfo ); return NULL; } nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount(); } /* -------------------------------------------------------------------- */ /* Build the field list for all indicated tables. */ /* -------------------------------------------------------------------- */ swq_field_list sFieldList; int nFIDIndex = 0; memset( &sFieldList, 0, sizeof(sFieldList) ); sFieldList.table_count = psSelectInfo->table_count; sFieldList.table_defs = psSelectInfo->table_defs; sFieldList.count = 0; sFieldList.names = (char **) CPLMalloc( sizeof(char *) * (nFieldCount+1) ); sFieldList.types = (swq_field_type *) CPLMalloc( sizeof(swq_field_type) * (nFieldCount+1) ); sFieldList.table_ids = (int *) CPLMalloc( sizeof(int) * (nFieldCount+1) ); sFieldList.ids = (int *) CPLMalloc( sizeof(int) * (nFieldCount+1) ); for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ ) { swq_table_def *psTableDef = psSelectInfo->table_defs + iTable; OGRDataSource *poTableDS = this; OGRLayer *poSrcLayer; int iField; if( psTableDef->data_source != NULL ) { poTableDS = (OGRDataSource *) OGROpenShared( psTableDef->data_source, FALSE, NULL ); CPLAssert( poTableDS != NULL ); poTableDS->Dereference(); } poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name ); for( iField = 0; iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++ ) { OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField); int iOutField = sFieldList.count++; sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef(); if( poFDefn->GetType() == OFTInteger ) sFieldList.types[iOutField] = SWQ_INTEGER; else if( poFDefn->GetType() == OFTReal ) sFieldList.types[iOutField] = SWQ_FLOAT; else if( poFDefn->GetType() == OFTString ) sFieldList.types[iOutField] = SWQ_STRING; else sFieldList.types[iOutField] = SWQ_OTHER; sFieldList.table_ids[iOutField] = iTable; sFieldList.ids[iOutField] = iField; } if( iTable == 0 ) nFIDIndex = poSrcLayer->GetLayerDefn()->GetFieldCount(); } /* -------------------------------------------------------------------- */ /* Expand '*' in 'SELECT *' now before we add the pseudo field */ /* 'FID'. */ /* -------------------------------------------------------------------- */ pszError = swq_select_expand_wildcard( psSelectInfo, &sFieldList ); if( pszError != NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "SQL: %s", pszError ); return NULL; } sFieldList.names[sFieldList.count] = "FID"; sFieldList.types[sFieldList.count] = SWQ_INTEGER; sFieldList.table_ids[sFieldList.count] = 0; sFieldList.ids[sFieldList.count] = nFIDIndex; sFieldList.count++; /* -------------------------------------------------------------------- */ /* Finish the parse operation. */ /* -------------------------------------------------------------------- */ pszError = swq_select_parse( psSelectInfo, &sFieldList, 0 ); CPLFree( sFieldList.names ); CPLFree( sFieldList.types ); CPLFree( sFieldList.table_ids ); CPLFree( sFieldList.ids ); if( pszError != NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "SQL: %s", pszError ); return NULL; } /* -------------------------------------------------------------------- */ /* Everything seems OK, try to instantiate a results layer. */ /* -------------------------------------------------------------------- */ OGRGenSQLResultsLayer *poResults; poResults = new OGRGenSQLResultsLayer( this, psSelectInfo, poSpatialFilter ); // Eventually, we should keep track of layers to cleanup. return poResults; }
OGRLayer * OGRDataSource::ExecuteSQL( const char *pszStatement, OGRGeometry *poSpatialFilter, const char *pszDialect ) { const char *pszError; swq_select *psSelectInfo = NULL; (void) pszDialect; swq_field_list sFieldList; int nFIDIndex = 0; OGRGenSQLResultsLayer *poResults = NULL; memset( &sFieldList, 0, sizeof(sFieldList) ); /* -------------------------------------------------------------------- */ /* Handle CREATE INDEX statements specially. */ /* -------------------------------------------------------------------- */ if( EQUALN(pszStatement,"CREATE INDEX",12) ) { ProcessSQLCreateIndex( pszStatement ); return NULL; } /* -------------------------------------------------------------------- */ /* Handle DROP INDEX statements specially. */ /* -------------------------------------------------------------------- */ if( EQUALN(pszStatement,"DROP INDEX",10) ) { ProcessSQLDropIndex( pszStatement ); return NULL; } /* -------------------------------------------------------------------- */ /* Preparse the SQL statement. */ /* -------------------------------------------------------------------- */ pszError = swq_select_preparse( pszStatement, &psSelectInfo ); if( pszError != NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "SQL: %s", pszError ); return NULL; } /* -------------------------------------------------------------------- */ /* Validate that all the source tables are recognised, count */ /* fields. */ /* -------------------------------------------------------------------- */ int nFieldCount = 0, iTable, iField; int iEDS; int nExtraDSCount = 0; OGRDataSource** papoExtraDS = NULL; OGRSFDriverRegistrar *poReg=OGRSFDriverRegistrar::GetRegistrar(); for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ ) { swq_table_def *psTableDef = psSelectInfo->table_defs + iTable; OGRLayer *poSrcLayer; OGRDataSource *poTableDS = this; if( psTableDef->data_source != NULL ) { poTableDS = (OGRDataSource *) OGROpenShared( psTableDef->data_source, FALSE, NULL ); if( poTableDS == NULL ) { if( strlen(CPLGetLastErrorMsg()) == 0 ) CPLError( CE_Failure, CPLE_AppDefined, "Unable to open secondary datasource\n" "`%s' required by JOIN.", psTableDef->data_source ); swq_select_free( psSelectInfo ); goto end; } /* Keep in an array to release at the end of this function */ papoExtraDS = (OGRDataSource** )CPLRealloc(papoExtraDS, sizeof(OGRDataSource*) * (nExtraDSCount + 1)); papoExtraDS[nExtraDSCount++] = poTableDS; } poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name ); if( poSrcLayer == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "SELECT from table %s failed, no such table/featureclass.", psTableDef->table_name ); swq_select_free( psSelectInfo ); goto end; } nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount(); } /* -------------------------------------------------------------------- */ /* Build the field list for all indicated tables. */ /* -------------------------------------------------------------------- */ sFieldList.table_count = psSelectInfo->table_count; sFieldList.table_defs = psSelectInfo->table_defs; sFieldList.count = 0; sFieldList.names = (char **) CPLMalloc( sizeof(char *) * (nFieldCount+SPECIAL_FIELD_COUNT) ); sFieldList.types = (swq_field_type *) CPLMalloc( sizeof(swq_field_type) * (nFieldCount+SPECIAL_FIELD_COUNT) ); sFieldList.table_ids = (int *) CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) ); sFieldList.ids = (int *) CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) ); for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ ) { swq_table_def *psTableDef = psSelectInfo->table_defs + iTable; OGRDataSource *poTableDS = this; OGRLayer *poSrcLayer; if( psTableDef->data_source != NULL ) { poTableDS = (OGRDataSource *) OGROpenShared( psTableDef->data_source, FALSE, NULL ); CPLAssert( poTableDS != NULL ); poTableDS->Dereference(); } poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name ); for( iField = 0; iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++ ) { OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField); int iOutField = sFieldList.count++; sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef(); if( poFDefn->GetType() == OFTInteger ) sFieldList.types[iOutField] = SWQ_INTEGER; else if( poFDefn->GetType() == OFTReal ) sFieldList.types[iOutField] = SWQ_FLOAT; else if( poFDefn->GetType() == OFTString ) sFieldList.types[iOutField] = SWQ_STRING; else sFieldList.types[iOutField] = SWQ_OTHER; sFieldList.table_ids[iOutField] = iTable; sFieldList.ids[iOutField] = iField; } if( iTable == 0 ) nFIDIndex = poSrcLayer->GetLayerDefn()->GetFieldCount(); } /* -------------------------------------------------------------------- */ /* Expand '*' in 'SELECT *' now before we add the pseudo fields */ /* -------------------------------------------------------------------- */ pszError = swq_select_expand_wildcard( psSelectInfo, &sFieldList ); if( pszError != NULL ) { swq_select_free( psSelectInfo ); CPLError( CE_Failure, CPLE_AppDefined, "SQL: %s", pszError ); goto end; } for (iField = 0; iField < SPECIAL_FIELD_COUNT; iField++) { sFieldList.names[sFieldList.count] = (char*) SpecialFieldNames[iField]; sFieldList.types[sFieldList.count] = SpecialFieldTypes[iField]; sFieldList.table_ids[sFieldList.count] = 0; sFieldList.ids[sFieldList.count] = nFIDIndex + iField; sFieldList.count++; } /* -------------------------------------------------------------------- */ /* Finish the parse operation. */ /* -------------------------------------------------------------------- */ pszError = swq_select_parse( psSelectInfo, &sFieldList, 0 ); if( pszError != NULL ) { swq_select_free( psSelectInfo ); CPLError( CE_Failure, CPLE_AppDefined, "SQL: %s", pszError ); goto end; } /* -------------------------------------------------------------------- */ /* Everything seems OK, try to instantiate a results layer. */ /* -------------------------------------------------------------------- */ poResults = new OGRGenSQLResultsLayer( this, psSelectInfo, poSpatialFilter ); // Eventually, we should keep track of layers to cleanup. end: CPLFree( sFieldList.names ); CPLFree( sFieldList.types ); CPLFree( sFieldList.table_ids ); CPLFree( sFieldList.ids ); /* Release the datasets we have opened with OGROpenShared() */ /* It is safe to do that as the 'new OGRGenSQLResultsLayer' itself */ /* has taken a reference on them, which it will release in its */ /* destructor */ for(iEDS = 0; iEDS < nExtraDSCount; iEDS++) poReg->ReleaseDataSource( papoExtraDS[iEDS] ); CPLFree(papoExtraDS); return poResults; }