2025-04-27 07:49:33 -04:00

551 lines
13 KiB
C++

/*++
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_
#include <parmlist.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,
STR * pstrSymbolValue );
//
// These are the types of tags that we recognize in the template
// file
//
enum TAG_TYPE
{
TAG_TYPE_VALUE = 0, // i.e., a column name with data
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
//
class ODBC_REQ
{
public:
ODBC_REQ( TSVC_CACHE * pCache,
CONST CHAR * pszQueryFile,
CONST CHAR * pszPathInfo,
CONST CHAR * pszParameters,
BOOL fIsAnonymous,
HANDLE hUserToken,
DWORD csecConnPool,
ODBC_REQ_FIND_SYMBOL pfnClientFindSymbol = NULL,
VOID * pFindSymbolContext = NULL,
int nCharset = 0 );
~ODBC_REQ();
BOOL IsValid( VOID ) const
{ return _fValid; }
BOOL OpenQueryFile( BOOL * pfAccessDenied,
BOOL * pfFileNotFound);
BOOL ParseAndQuery( CHAR * pszLoggedOnUser );
BOOL OutputResults( ODBC_REQ_CALLBACK pfnCallback,
PVOID pvContext,
STR * pstrHeaders,
ODBC_REQ_HEADER pfnHeader,
BOOL fIsAuth,
BOOL * pfAccessDenied,
BOOL * pfFileNotFound);
BOOL OutputCachedResults( ODBC_REQ_CALLBACK pfnCallback,
PVOID pvContext );
BOOL AppendHeaders( STR * pstr );
__inline BOOL Close( VOID );
BOOL IsCacheable( VOID ) const
{ return (_csecExpires > 0); }
BOOL LookupSymbol( const CHAR * pchSymbolName,
enum TAG_TYPE * pTagType,
const CHAR * * ppchValue,
DWORD * pcbValue );
BOOL SetErrorText( const CHAR * lpszError )
{ return _strErrorText.Copy( lpszError ); }
BOOL GetLastErrorText( STR * pstrError );
BOOL IsEqual( ODBC_REQ * pOdbcReq );
CHAR * QueryContentType( VOID ) const
{ 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; }
TSVC_CACHE * QueryTsvcCache( VOID ) const
{ return _pCache; }
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() { return _hToken; }
PSECURITY_DESCRIPTOR GetSecDesc() { return _pSecDesc; }
VOID InvalidateSecDesc() { _pSecDesc = NULL; }
BOOL IsAnonymous() { return _fAnonymous; }
protected:
VOID LookupTag( CHAR * pchBeginTag,
const CHAR * * ppchAfterTag,
const CHAR * * ppchDBValue,
DWORD * cbValue,
enum TAG_TYPE * pTagType );
BOOL SendData( ODBC_REQ_CALLBACK pfnCallback,
PVOID pvContext,
const CHAR * pbData,
DWORD cbData,
BUFFER_CHAIN_ITEM * * ppbufOut,
DWORD * pcbOut );
BOOL SendEscapedData( ODBC_REQ_CALLBACK pfnCallback,
PVOID pvContext,
PCSTR pch,
DWORD cbIn,
LPDWORD pcbOut );
BOOL NextRow( BOOL * pfLast );
BOOL ReplaceParams( BUFFER * pbufFile,
PARAM_LIST * pParamList );
BOOL EvaluateExpression( const CHAR * * ppchExpression,
BOOL * pfExprValue );
BOOL 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:
TSVC_CACHE * _pCache;
ODBC_CONNECTION _odbcconn;
ODBC_CONNECTION * _podbcconnPool;
ODBC_STATEMENT * _podbcstmt;
//
// Contains query file and cache info for template merge file
//
BUFFER _bufQueryFile;
DWORD _cbQueryFile;
CACHE_FILE_INFO _cfiTemplateFile;
//
// 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
//
STR _strQueryFile;
//
// PathInfo from ECB
//
STR _strPathInfo;
//
// Full path to template file to merge the results with
//
STR _strTemplateFile;
//
// Data content type, we default to text/html if none is specified
//
STR _strContentType;
//
// Contains the expires time if we are caching this query
//
STR _strExpiresTime;
//
// List of odbc options to set on this connection
//
STR _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;
STR _strTranslationFile;
//
// The impersonation token file opens are performed with
//
HANDLE _hToken;
//
// Holds the Column names and memory for the database values
//
STR * _pstrCols;
STR * _pstrValues;
DWORD * _pcbValues;
DWORD _cCols;
//
// If an error that requires an explanation occurs it's stored here
//
STR _strErrorText;
//
// Contains a client supplied callback for looking up symbols (such as
// HTTP_USER_AGENT). _strSymbolValue is just a storage variable used
// by LookupTag.
//
ODBC_REQ_FIND_SYMBOL _pfnClientFindSymbol;
VOID * _pFindSymbolContext;
STR _strSymbolValue;
//
// Contains an array of queries
//
STR _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)
};
//
// 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 )
{ CharUpper( _strValue.QueryStr() ); }
private:
ODBC_REQ * _podbcreq;
//
// Type of value
//
TAG_TYPE _tagType;
//
// Actual values of expression if dword or string
//
DWORD _dwValue;
STR _strValue;
};
//
// Prototypes for ODBC connection pooling
//
BOOL
InitializeOdbcPool(
VOID
);
VOID
TerminateOdbcPool(
VOID
);
BOOL
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 BOOL ODBC_REQ::Close( VOID )
{
delete _podbcstmt;
_podbcstmt = NULL;
//
// If we're not using a pooled connection, close it now, otherwise free
// it to the pool
//
if ( _podbcconnPool == &_odbcconn )
{
return _odbcconn.Close();
}
else
{
CloseConnection( _podbcconnPool, FALSE );
}
return TRUE;
}
#endif //_ODBCREQ_HXX_