/****************************************************************************** * $Id: SFRS.h,v 1.21 2002/08/09 21:33:33 warmerda Exp $ * * Project: OpenGIS Simple Features Reference Implementation * Purpose: Core definitions for SF OLE DB provider. * Author: Ken Shih, kshih@home.com * ****************************************************************************** * Copyright (c) 1999, Les Technologies SoftMap Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log: SFRS.h,v $ * Revision 1.21 2002/08/09 21:33:33 warmerda * minor .net hack * * Revision 1.20 2002/08/08 22:02:51 warmerda * mark as multithreaded * * Revision 1.19 2002/04/29 20:43:18 warmerda * Ensure that ExecuteSQL() prepared layers are cleaned up * * Revision 1.18 2002/04/29 20:31:57 warmerda * allow ExecuteSQL() to handle FID * * Revision 1.17 2002/04/25 20:15:26 warmerda * upgraded to use ExecuteSQL() * * Revision 1.16 2002/04/25 17:39:31 warmerda * added ICommandPrepare, and IRowsetChange interfaces * * Revision 1.15 2002/04/17 19:53:17 warmerda * added SELECT COUNT(*) support * * Revision 1.14 2002/04/16 21:02:18 warmerda * copy columninfo to CSFCommand from rowset after executing a command * * Revision 1.13 2002/02/05 20:44:17 warmerda * added CheckRows() and feature caching to OGRVirtualArray * * Revision 1.12 2002/01/31 16:48:15 warmerda * removed need for getting feature count for a rowset * * Revision 1.11 2001/11/21 16:27:22 warmerda * added MAXOPENROWS at Bruces request * * Revision 1.10 2001/10/24 17:20:08 warmerda * added destructor debug output * * Revision 1.9 2001/10/22 21:29:50 warmerda * reworked to allow selecting a subset of fields * * Revision 1.8 2001/09/06 03:26:10 warmerda * converted to use SFAccessorImpl.h * * Revision 1.7 2001/08/17 14:25:49 warmerda * added ICommandWithParameters implmentation * * Revision 1.6 2001/06/01 18:04:17 warmerda * added mnBufferSize to CVirtualArray * * Revision 1.5 2001/05/28 19:41:58 warmerda * lots of changes * * Revision 1.4 1999/07/23 19:20:27 kshih * Modifications for errors etc... * * Revision 1.3 1999/07/20 17:11:11 kshih * Use OGR code * * Revision 1.2 1999/06/04 15:17:27 warmerda * Added copyright header. * */ // SFRS.h : Declaration of the CSFRowset #ifndef __CSFRowset_H_ #define __CSFRowset_H_ #include "resource.h" // main symbols #include "sfutil.h" #include "IColumnsRowsetImpl.h" #include "ICommandWithParametersImpl.h" #include "SFAccessorImpl.h" #include "IFRowsetImpl.h" // Select one of BLOB_NONE, BLOB_IUNKNOWN, BLOB_BYTES, or BLOB_BYTES_BY_REF // This will determine the type and handling of the geometry column. #define BLOB_IUNKNOWN /************************************************************************/ /* OGRVirtualArray */ /************************************************************************/ class CSFRowset; class OGRVirtualArray { public: OGRVirtualArray(); ~OGRVirtualArray(); void RemoveAll(); void Initialize(OGRLayer *pOGRLayer,int, CSFRowset *); BYTE *GetRow(int iIndex, HRESULT &hr ); int CheckRows( int iIndex, int nCount ); private: OGRFeature *GetFeature( int iIndex ); void ResetCache( int, int ); int FillGeometry( OGRGeometry *poGeometry, unsigned char *pabyBuffer, ATLCOLUMNINFO *pColInfo ); int FillOGRField( OGRFeature *poFeature, int iField, unsigned char *pabyBuffer, ATLCOLUMNINFO *pColInfo ); int m_nPackedRecordLength; BYTE *mBuffer; int m_nBufferSize; OGRLayer *m_pOGRLayer; int m_nLastRecordAccessed; OGRFeatureDefn *m_pFeatureDefn; CSFRowset *m_pRowset; // OGRFeature cache (filled by CheckRows()). int m_nFeatureCacheBase; int m_nFeatureCacheSize; OGRFeature **m_papoFeatureCache; }; /************************************************************************/ /* CShapeFile */ /************************************************************************/ class CShapeFile { public: template static ATLCOLUMNINFO * GetColumnInfo(T* pT, ULONG* pcCols) { USES_CONVERSION; CComQIPtr spCommand = pT->GetUnknown(); if (spCommand == NULL) { if (pcCols != NULL) *pcCols = pT->m_paColInfo.GetSize(); return pT->m_paColInfo.m_aT; } CPLDebug( "OGR_OLEDB", "CShapeFile::GetColumnInfo() - spCommand != NULL!" ); CComPtr pRowset; if (pT->m_paColInfo.m_aT == NULL) { LONG cRows; HRESULT hr = spCommand->Execute(NULL, IID_IRowset, NULL, &cRows, (IUnknown**)&pRowset); } if (pcCols != NULL) *pcCols = pT->m_paColInfo.GetSize(); return pT->m_paColInfo.m_aT; } }; /************************************************************************/ /* CSFCommandSupportsErrorInfoImpl */ /************************************************************************/ class ATL_NO_VTABLE CSFCommandSupportsErrorInfoImpl : public ISupportErrorInfo { public: STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) { if (IID_ICommand == riid) return S_OK; return S_FALSE; } }; /************************************************************************/ /* CSFCommand */ /************************************************************************/ class ATL_NO_VTABLE CSFCommand : public CComObjectRootEx, public SFAccessorImpl, public ICommandTextImpl, public ICommandPropertiesImpl, public IObjectWithSiteImpl, public IConvertTypeImpl, public IColumnsInfoImpl, public ICommandWithParametersImpl, public ICommandPrepare, //20020411 - ryan public CSFCommandSupportsErrorInfoImpl { public: BEGIN_COM_MAP(CSFCommand) COM_INTERFACE_ENTRY(ICommand) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY(IAccessor) COM_INTERFACE_ENTRY(ICommandProperties) COM_INTERFACE_ENTRY(ICommandWithParameters) COM_INTERFACE_ENTRY2(ICommandText, ICommand) COM_INTERFACE_ENTRY(IColumnsInfo) COM_INTERFACE_ENTRY(IConvertType) COM_INTERFACE_ENTRY(ISupportErrorInfo) COM_INTERFACE_ENTRY(ICommandPrepare) //20020411 - ryan END_COM_MAP() // ICommand public: HRESULT FinalConstruct() { HRESULT hr = CConvertHelper::FinalConstruct(); if (FAILED (hr)) return hr; hr = SFAccessorImpl::FinalConstruct(); if (FAILED(hr)) return hr; m_bHasParamaters = TRUE; return CUtlProps::FInit(); } void FinalRelease(); HRESULT ExtractSpatialQuery( DBPARAMS * ); HRESULT WINAPI Execute(IUnknown * pUnkOuter, REFIID riid, DBPARAMS * pParams, LONG * pcRowsAffected, IUnknown ** ppRowset); static ATLCOLUMNINFO* GetColumnInfo(CSFCommand* pv, ULONG* pcInfo) { return CShapeFile::GetColumnInfo(pv,pcInfo); } //ICommandPrepare - 20020111 - ryan STDMETHOD(Prepare)(ULONG cExpectedRuns) { return S_OK; } STDMETHOD(Unprepare)() { return S_OK; } BEGIN_PROPSET_MAP(CSFCommand) BEGIN_PROPERTY_SET(DBPROPSET_ROWSET) PROPERTY_INFO_ENTRY(IAccessor) PROPERTY_INFO_ENTRY(IColumnsInfo) PROPERTY_INFO_ENTRY_VALUE(IColumnsRowset,VARIANT_TRUE) PROPERTY_INFO_ENTRY(IConvertType) PROPERTY_INFO_ENTRY(IRowset) PROPERTY_INFO_ENTRY(IRowsetIdentity) PROPERTY_INFO_ENTRY(IRowsetInfo) PROPERTY_INFO_ENTRY(IRowsetLocate) PROPERTY_INFO_ENTRY(BOOKMARKS) PROPERTY_INFO_ENTRY(BOOKMARKSKIPPED) PROPERTY_INFO_ENTRY(BOOKMARKTYPE) PROPERTY_INFO_ENTRY_VALUE(CANFETCHBACKWARDS,VARIANT_FALSE) PROPERTY_INFO_ENTRY(CANHOLDROWS) PROPERTY_INFO_ENTRY_VALUE(CANSCROLLBACKWARDS,VARIANT_FALSE) PROPERTY_INFO_ENTRY(LITERALBOOKMARKS) PROPERTY_INFO_ENTRY(ORDEREDBOOKMARKS) PROPERTY_INFO_ENTRY_VALUE(MAXOPENROWS,1000) PROPERTY_INFO_ENTRY_VALUE(ROWTHREADMODEL,DBPROPVAL_RT_APTMTTHREAD|DBPROPVAL_RT_FREETHREAD) END_PROPERTY_SET(DBPROPSET_ROWSET) END_PROPSET_MAP() CSimpleArray m_paColInfo; }; /************************************************************************/ /* CSFRowsetImpl */ /* */ /* Template closely based on CRowsetImpl from ATLDB.H with a */ /* view variations. It is instanatiated into a real class as */ /* CSFRowset below. */ /************************************************************************/ template , class RowClass = CSimpleRow, class RowsetInterface = IFRowsetImpl < T, IRowset, RowClass> > class CSFRowsetImpl : public CComObjectRootEx, public SFAccessorImpl, public IRowsetIdentityImpl, public IRowsetCreatorImpl, public IRowsetInfoImpl, public IColumnsInfoImpl, public IConvertTypeImpl, public IColumnsRowsetImpl, public IRowsetChange, //20020411 - ryan public RowsetInterface { public: typedef CreatorClass _RowsetCreatorClass; typedef ArrayType _RowsetArrayType; typedef CSFRowsetImpl< T, Storage, CreatorClass, ArrayType, RowClass, RowsetInterface> _RowsetBaseClass; //IRowsetChange - 20020411 - ryan STDMETHOD(DeleteRows) (HCHAPTER hChapter, ULONG cRows, const HROW rghRows[], DBROWSTATUS rgRowStatus[]) { ATLTRACENOTIMPL("CSFRowsetImpl::DeleteRows"); } STDMETHOD(InsertRow) (HCHAPTER hChapter, HACCESSOR hAccessor, void* pData, HROW* phRow) { ATLTRACENOTIMPL("CSFRowsetImpl::InsertRow"); } STDMETHOD(SetData) (HROW hRow, HACCESSOR hAccessor, void* pData) { ATLTRACENOTIMPL("CSFRowsetImpl::SetData"); } BEGIN_COM_MAP(CSFRowsetImpl) COM_INTERFACE_ENTRY(IAccessor) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY(IRowsetInfo) COM_INTERFACE_ENTRY(IColumnsInfo) COM_INTERFACE_ENTRY(IColumnsRowset) COM_INTERFACE_ENTRY(IConvertType) COM_INTERFACE_ENTRY(IRowsetIdentity) COM_INTERFACE_ENTRY_IID(IID_IRowsetLocate, IRowset) //20020411 - ryan COM_INTERFACE_ENTRY(IRowset) COM_INTERFACE_ENTRY(IRowsetChange) //20020411 - ryan END_COM_MAP() virtual ~CSFRowsetImpl() { CPLDebug( "OGR_OLEDB", "~CSFRowsetImpl()" ); } HRESULT FinalConstruct() { HRESULT hr = SFAccessorImpl::FinalConstruct(); if (FAILED(hr)) return hr; return CConvertHelper::FinalConstruct(); } HRESULT NameFromDBID(DBID* pDBID, CComBSTR& bstr, bool bIndex) { if (pDBID->uName.pwszName != NULL) { bstr = pDBID->uName.pwszName; if (m_strCommandText == (BSTR)NULL) return E_OUTOFMEMORY; return S_OK; } return (bIndex) ? DB_E_NOINDEX : DB_E_NOTABLE; } HRESULT GetCommandFromID(DBID* pTableID, DBID* pIndexID) { USES_CONVERSION; HRESULT hr; if (pTableID == NULL && pIndexID == NULL) return E_INVALIDARG; if (pTableID != NULL && pTableID->eKind == DBKIND_NAME) { hr = NameFromDBID(pTableID, m_strCommandText, true); if (FAILED(hr)) return hr; if (pIndexID != NULL) { if (pIndexID->eKind == DBKIND_NAME) { hr = NameFromDBID(pIndexID, m_strIndexText, false); if (FAILED(hr)) { m_strCommandText.Empty(); return hr; } } else { m_strCommandText.Empty(); return DB_E_NOINDEX; } } return S_OK; } if (pIndexID != NULL && pIndexID->eKind == DBKIND_NAME) return NameFromDBID(pIndexID, m_strIndexText, false); return S_OK; } HRESULT ValidateCommandID(DBID* pTableID, DBID* pIndexID) { HRESULT hr = S_OK; if (pTableID != NULL) { hr = CUtlProps::IsValidDBID(pTableID); if (hr != S_OK) return hr; // Check for a NULL TABLE ID (where its a valid pointer but NULL) if ((pTableID->eKind == DBKIND_GUID_NAME || pTableID->eKind == DBKIND_NAME || pTableID->eKind == DBKIND_PGUID_NAME) && pTableID->uName.pwszName == NULL) return DB_E_NOTABLE; } if (pIndexID != NULL) hr = CUtlProps::IsValidDBID(pIndexID); return hr; } HRESULT SetCommandText(DBID* pTableID, DBID* pIndexID) { T* pT = (T*)this; HRESULT hr = pT->ValidateCommandID(pTableID, pIndexID); if (FAILED(hr)) return hr; hr = pT->GetCommandFromID(pTableID, pIndexID); return hr; } void FinalRelease() { m_rgRowData.RemoveAll(); } static ATLCOLUMNINFO* GetColumnInfo(T* pv, ULONG* pcCols) { return Storage::GetColumnInfo(pv,pcCols); } OUT_OF_LINE HRESULT GetDataHelper(HACCESSOR hAccessor, ATLCOLUMNINFO*& rpInfo, void** ppBinding, void*& rpSrcData, ULONG& rcCols, CComPtr& rspConvert, RowClass* pRow) { ATLASSERT(ppBinding != NULL); HRESULT hr; T* pT = (T*) this; *ppBinding = (void*)pT->m_rgBindings.Lookup((int)hAccessor); if (*ppBinding == NULL) return DB_E_BADACCESSORHANDLE; rpSrcData = (void*)pT->m_rgRowData.GetRow(pRow->m_iRowset, hr); if( rpSrcData == NULL ) return hr; rpInfo = T::GetColumnInfo((T*)this, &rcCols); rspConvert = pT->m_spConvert; return S_OK; } CComBSTR m_strCommandText; CComBSTR m_strIndexText; ArrayType m_rgRowData; }; /************************************************************************/ /* CSFRowset */ /************************************************************************/ class CSFRowset : public CSFRowsetImpl< CSFRowset, CShapeFile, CSFCommand, OGRVirtualArray> { char *ProcessSpecialFields( const char *, int *, int * ); public: CSFRowset(); virtual ~CSFRowset(); HRESULT Execute(DBPARAMS * pParams, LONG* pcRowsAffected); CSimpleArray m_paColInfo; CSimpleArray m_panOGRIndex; OGRDataSource *m_poDS; int m_iLayer; OGRLayer *m_poLayer; }; #endif //__CSFRowset_H_