/*++ Copyright (c) 1995 Microsoft Corporation Module Name: odbcreq.hxx Abstract: ODBC Request class used for ODBC requests from a query file Author: John Ludeman (johnl) 22-Feb-1995 Revision History: Phillich 24-Jan-1996 Added ODBC_REQ::SkipConditionalBlock() --*/ #ifndef _ODBCREQ_HXX_ #define _ODBCREQ_HXX_ // // ODBC DLL Module Name // #define HTTP_ODBC_DLL "httpodbc.dll" // // Contains the maximum number of queries (i.e.,SQLStatement // statements) IDC supports // #define MAX_QUERIES 100 // // ODBC_REQ callback function for doing output // typedef DWORD ( * ODBC_REQ_CALLBACK )( PVOID pvContext, const CHAR * pchOutput, DWORD cbOutput ); // // ODBC_REQ callback function for sending header // typedef BOOL ( * ODBC_REQ_HEADER )( PVOID pvContext, const CHAR * pchStatus, const CHAR * pchHeaders ); // // ODBC_REQ callback function for searching client supplied // symbol tables // typedef BOOL ( * ODBC_REQ_FIND_SYMBOL )( VOID * pContext, const CHAR * pszSymbolName, STRA * pstrSymbolValue ); // // These are the types of tags that we recognize in the template // file // enum TAG_TYPE { // // i.e., a column name with data // TAG_TYPE_VALUE = 0, TAG_TYPE_BEGIN_DETAIL, TAG_TYPE_END_DETAIL, TAG_TYPE_IF, TAG_TYPE_ELSE, TAG_TYPE_END_IF, TAG_TYPE_INTEGER, TAG_TYPE_STRING, TAG_TYPE_OP_LT, TAG_TYPE_OP_GT, TAG_TYPE_OP_EQ, TAG_TYPE_OP_CONTAINS, TAG_TYPE_UNKNOWN, TAG_TYPE_VALUE_TO_ESCAPE }; // // This class handles all of the work related to processing a // ODBC query file // #define ODBC_REQ_SIGNATURE 'ERDO' #define ODBC_REQ_FREE_SIGNATURE 'fRDO' class ODBC_REQ { public: ODBC_REQ( EXTENSION_CONTROL_BLOCK * pECB, DWORD csecConnPool, int nCharset = 0 ); ~ODBC_REQ(); BOOL CheckSignature( VOID ) const { return _dwSignature == ODBC_REQ_SIGNATURE; } HRESULT Create( CONST CHAR * pszQueryFile, CONST CHAR * pszParameters ); BOOL IsValid( VOID ) const { return _fValid; } HRESULT OpenQueryFile( BOOL * pfAccessDenied ); HRESULT ParseAndQuery( CHAR * pszLoggedOnUser ); HRESULT OutputResults( ODBC_REQ_CALLBACK pfnCallback, PVOID pvContext, STRA * pstrHeaders, ODBC_REQ_HEADER pfnHeader, BOOL fIsAuth, BOOL * pfAccessDenied ); HRESULT AppendHeaders( STRA * pstr ); __inline VOID Close( VOID ); HRESULT LookupSymbol( const CHAR * pchSymbolName, enum TAG_TYPE * pTagType, const CHAR * * ppchValue, DWORD * pcbValue ); HRESULT SetErrorText( const CHAR * lpszError ) { return _strErrorText.Copy( lpszError ); } BOOL GetLastErrorText( STRA * pstrError ); BOOL IsEqual( ODBC_REQ * pOdbcReq ); CHAR * QueryContentType( VOID ) { return (_strContentType.IsEmpty() ? "text/html" : _strContentType.QueryStr()); } DWORD QueryMaxRecords( VOID ) const { return _cMaxRecords; } DWORD QueryCurrentRecordNum( VOID ) const { return _cCurrentRecordNum; } const CHAR * QueryQueryFile( VOID ) const { return _strQueryFile.QueryStr(); } const CHAR * QueryTemplateFile( VOID ) const { return _strTemplateFile.QueryStr(); } DWORD QueryClientParamCount( VOID ) const { return _cClientParams; } DWORD QueryAllocatedBytes( VOID ) const { return _buffchain.CalcTotalSize(); } BOOL IsExpired( DWORD csecSysStartup ) { return csecSysStartup >= _csecExpiresAt; } ODBC_CONNECTION * QueryOdbcConnection( VOID ) { return ( _podbcconnPool ? _podbcconnPool : &_odbcconn ); } DWORD QueryConnPoolTimeout( VOID ) const { return _csecConnPool; } HANDLE QueryUserToken( VOID ) { return _hToken; } PSECURITY_DESCRIPTOR GetSecDesc( VOID ) { return _pSecDesc; } VOID InvalidateSecDesc( VOID ) { _pSecDesc = NULL; } BOOL IsAnonymous() { return _fAnonymous; } VOID * operator new( size_t size ) { DBG_ASSERT( size == sizeof( ODBC_REQ ) ); DBG_ASSERT( sm_pachOdbcRequests != NULL ); return sm_pachOdbcRequests->Alloc(); } VOID operator delete( VOID * pOdbcRequest ) { DBG_ASSERT( pOdbcRequest != NULL ); DBG_ASSERT( sm_pachOdbcRequests != NULL ); DBG_REQUIRE( sm_pachOdbcRequests->Free( pOdbcRequest ) ); } static HRESULT Initialize( VOID ); static VOID Terminate( VOID ); protected: VOID LookupTag( CHAR * pchBeginTag, const CHAR * * ppchAfterTag, const CHAR * * ppchDBValue, DWORD * cbValue, enum TAG_TYPE * pTagType ); HRESULT SendData( ODBC_REQ_CALLBACK pfnCallback, PVOID pvContext, const CHAR * pbData, DWORD cbData, BUFFER_CHAIN_ITEM * * ppbufOut, DWORD * pcbOut ); HRESULT SendEscapedData( ODBC_REQ_CALLBACK pfnCallback, PVOID pvContext, PCSTR pch, DWORD cbIn, LPDWORD pcbOut ); HRESULT NextRow( BOOL * pfLast ); HRESULT ReplaceParams( BUFFER * pbufFile, PARAM_LIST * pParamList ); HRESULT EvaluateExpression( const CHAR * * ppchExpression, BOOL * pfExprValue ); HRESULT EvaluateOperator( const CHAR * * ppchExpression, TAG_TYPE * pOpType ); VOID SkipToTag( const CHAR * * pchIn, const CHAR * pchTag ); BOOL SkipConditionalBlock( const CHAR * * ppchIn, const CHAR * ppchEOF, const CHAR * pchSearchTag ); private: // // Signature of the class // DWORD _dwSignature; ODBC_CONNECTION _odbcconn; ODBC_CONNECTION * _podbcconnPool; ODBC_STATEMENT * _podbcstmt; // // Contains query file and cache info for template merge file // BUFFER _bufQueryFile; DWORD _cbQueryFile; // // Buffer chain if this query is going to be cached and the current // buffer before it has been added to the chain // BUFFER_CHAIN _buffchain; BUFFER_CHAIN_ITEM * _pbufOut; // // Maximum buffer size of data field // DWORD _cchMaxFieldSize; // // Current nesting level of if/endif pairs // DWORD _cNestedIfs; // // The number of seconds to consider the query valid // DWORD _csecExpires; // Relative from time of query DWORD _csecExpiresAt; // Absolute from system start // // The maximum number of records to return in a query // DWORD _cMaxRecords; // // The current record number we are enumerating // DWORD _cCurrentRecordNum; // // Full path to the web database gateway query file // STRA _strQueryFile; // // Full path to template file to merge the results with // STRA _strTemplateFile; // // Data content type, we default to text/html if none is specified // STRA _strContentType; // // Contains the expires time if we are caching this query // STRA _strExpiresTime; // // List of odbc options to set on this connection // STRA _strOdbcOptions; // // TRUE if the first column of retrieved data should be sent directly // to the client w/o going through an htx merge // BOOL _fDirect; // // TRUE if we constructed w/o errors // BOOL _fValid; // // The merged parameter list from the web browser and the default // parameter list from the query file // PARAM_LIST _plParams; // // This is the number of parameters passed by the client // DWORD _cClientParams; // // Required parameters specified in the query file // PARAM_LIST _plReqParams; // // String translation list and file // PARAM_LIST _plTransList; STRA _strTranslationFile; // // The impersonation token file opens are performed with // HANDLE _hToken; // // Holds the Column names and memory for the database values // STRA * _pstrCols; STRA * _pstrValues; DWORD * _pcbValues; DWORD _cCols; // // If an error that requires an explanation occurs it's stored here // STRA _strErrorText; // // Contains a client supplied callback for looking up symbols (such as // HTTP_USER_AGENT). _strSymbolValue is just a storage variable used // by LookupTag. // EXTENSION_CONTROL_BLOCK * _pECB; STRA _strSymbolValue; // // Contains an array of queries // STRA _strQueries[MAX_QUERIES]; DWORD _cQueries; // // Are we the anonymous user? // BOOL _fAnonymous; PSECURITY_DESCRIPTOR _pSecDesc; // // Contains the number of seconds to allow this ODBC connection to be // pooled, zero for no pooling // DWORD _csecConnPool; // // Charset of .htm, .idc, .htx // int _nCharset; // // Field Name // #define IDC_FIELDNAME_CHARSET "Charset:" // // Field Value // #define IDC_CHARSET_SJIS "x-sjis" #define IDC_CHARSET_JIS1 "iso-2022-jp" #define IDC_CHARSET_JIS2 "x-jis" #define IDC_CHARSET_EUCJP "x-euc-jp" // Please add field value for other FE (FEFEFE) // // Lookaside // static ALLOC_CACHE_HANDLER * sm_pachOdbcRequests; }; // // Contains a string or dword expression. Used for evaluating template // expressions // class EXPR_VALUE { public: EXPR_VALUE( ODBC_REQ * podbcreq ) { _podbcreq = podbcreq; _dwValue = 0; _tagType = TAG_TYPE_UNKNOWN; } ~EXPR_VALUE() {} BOOL Evaluate( const CHAR * * ppchValue ); BOOL ConvertToInteger( VOID ); BOOL GT( EXPR_VALUE & v2 ); BOOL LT( EXPR_VALUE & v2 ); BOOL EQ( EXPR_VALUE & v2 ); BOOL CONTAINS( EXPR_VALUE & v2 ); TAG_TYPE QueryType( VOID ) const { return _tagType; } VOID SetType( TAG_TYPE type ) { _tagType = type; } DWORD QueryInteger( VOID ) const { return _dwValue; } const CHAR * QueryStr( VOID ) const { return _strValue.QueryStr(); } VOID UpperCase( VOID ) { CharUpperA( _strValue.QueryStr() ); } private: ODBC_REQ * _podbcreq; // // Type of value // TAG_TYPE _tagType; // // Actual values of expression if dword or string // DWORD _dwValue; STRA _strValue; }; // // Prototypes for ODBC connection pooling // BOOL InitializeOdbcPool( VOID ); VOID TerminateOdbcPool( VOID ); HRESULT OpenConnection( IN ODBC_CONNECTION * podbcconnNonPooled, OUT ODBC_CONNECTION * * ppodbcconnToUse, IN DWORD csecPoolODBC, IN const CHAR * pszDataSource, IN const CHAR * pszUserName, IN const CHAR * pszPassword, IN const CHAR * pszLoggedOnUser ); VOID CloseConnection( IN ODBC_CONNECTION * podbcconnPooled, IN BOOL fDelete ); // // Inline so we can use the CloseConnection of the connection pool // __inline VOID ODBC_REQ::Close( VOID ) { // // If we're not using a pooled connection, close it now, otherwise free // it to the pool // if ( _podbcconnPool == &_odbcconn ) { _odbcconn.Close(); } else { CloseConnection( _podbcconnPool, FALSE ); } } #endif //_ODBCREQ_HXX_