windows-nt/Source/XPSP1/NT/inetsrv/query/sqltext/yybase.cxx
2020-09-26 16:20:57 +08:00

630 lines
21 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: YYBase.cxx
//
// Contents: Custom base class for YYPARSER
//
// History: 30-Nov-1999 KyleP Created
//
//----------------------------------------------------------------------------
#pragma hdrstop
#include "msidxtr.h"
#include "yybase.hxx"
//+-------------------------------------------------------------------------
//
// Member: CYYBase::CYYBase, public
//
// Synopsis: Constructor
//
// Arguments: [pParserSession] -- Session state
// [pParserTreeProperties] -- Command properties
// [yylex] -- Lexer
//
// History: 30-Nov-1999 KyleP Created
//
//--------------------------------------------------------------------------
CYYBase::CYYBase( CImpIParserSession* pParserSession,
CImpIParserTreeProperties* pParserTreeProperties,
YYLEXER & yylex )
: m_yylex( yylex ),
m_pIPSession( pParserSession ),
m_pIPTProperties( pParserTreeProperties )
{
}
//+-------------------------------------------------------------------------
//
// Member: CYYBase::~CYYBase, public
//
// Synopsis: Destructor
//
// History: 30-Nov-1999 KyleP Created
//
//--------------------------------------------------------------------------
CYYBase::~CYYBase()
{
}
//+-------------------------------------------------------------------------
//
// Member: CYYBase::CoerceScalar, public
//
// Synopsis: Converts a scalar node to specified type.
//
// Arguments: [dbTypeExpected] -- Expected type
// [ppct] -- Node to convert
//
// Returns: Error if conversion not possible
//
// History: 30-Nov-1999 KyleP Moved from YYPARSER
//
//--------------------------------------------------------------------------
HRESULT CYYBase::CoerceScalar(
DBTYPE dbTypeExpected, // @parm IN | DBTYPE that is expected in current context
DBCOMMANDTREE** ppct ) // @parm IN/OUT | scalar node
{
Assert( VT_I8 == ((PROPVARIANT*)(*ppct)->value.pvValue)->vt ||
VT_UI8 == ((PROPVARIANT*)(*ppct)->value.pvValue)->vt ||
VT_R8 == ((PROPVARIANT*)(*ppct)->value.pvValue)->vt ||
VT_BSTR == ((PROPVARIANT*)(*ppct)->value.pvValue)->vt ||
VT_BOOL == ((PROPVARIANT*)(*ppct)->value.pvValue)->vt ||
VT_FILETIME == ((PROPVARIANT*)(*ppct)->value.pvValue)->vt );
DBTYPE dbType = dbTypeExpected & ~DBTYPE_VECTOR;
if (DBTYPE_STR == (dbType & ~DBTYPE_BYREF))
dbType = VT_LPSTR;
if (DBTYPE_WSTR == (dbType & ~DBTYPE_BYREF))
dbType = VT_LPWSTR;
HRESULT hr = (*ppct)->hrError;
if (S_OK != hr)
goto error;
if (dbType == ((PROPVARIANT*)(*ppct)->value.pvValue)->vt)
return hr;
switch ( ((PROPVARIANT*)(*ppct)->value.pvValue)->vt )
{
case VT_UI8:
{
ULONGLONG uhVal = ((PROPVARIANT*)(*ppct)->value.pvValue)->uhVal.QuadPart;
switch ( dbType )
{
case VT_UI1:
if (uhVal > UCHAR_MAX)
hr = DISP_E_TYPEMISMATCH;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->bVal = (UCHAR)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_UI1;
}
break;
case VT_I1:
if (uhVal > CHAR_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->cVal = (CHAR)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_I1;
}
break;
case VT_UI2:
if (uhVal > USHRT_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->uiVal = (USHORT)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_UI2;
}
break;
case VT_I2:
if (uhVal > SHRT_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->iVal = (SHORT)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_I2;
}
break;
case VT_UI4:
if (uhVal > ULONG_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->ulVal = (ULONG)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_UI4;
}
break;
case VT_I4:
if (uhVal > LONG_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->lVal = (LONG)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_I4;
}
break;
case VT_I8:
if (uhVal > _I64_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->hVal.QuadPart = (LONGLONG)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_I8;
}
break;
case VT_R4:
((PROPVARIANT*)(*ppct)->value.pvValue)->fltVal = (float)(LONGLONG)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_R4;
break;
case VT_R8:
((PROPVARIANT*)(*ppct)->value.pvValue)->dblVal = (double)(LONGLONG)uhVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_R8;
break;
default:
hr = DB_E_CANTCONVERTVALUE;
}
}
break;
case VT_I8:
{
LONGLONG hVal = ((PROPVARIANT*)(*ppct)->value.pvValue)->hVal.QuadPart;
switch ( dbType )
{
case VT_UI1:
case VT_UI2:
case VT_UI4:
case VT_UI8:
hr = DB_E_CANTCONVERTVALUE;
break;
case VT_I1:
if (hVal < CHAR_MIN || hVal > CHAR_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->cVal = (CHAR)hVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_I1;
}
break;
case VT_I2:
if (hVal < SHRT_MIN || hVal > SHRT_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->iVal = (SHORT)hVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_I2;
}
break;
case VT_I4:
if (hVal < LONG_MIN || hVal > LONG_MAX)
hr = DB_E_DATAOVERFLOW;
else
{
((PROPVARIANT*)(*ppct)->value.pvValue)->lVal = (LONG)hVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_I4;
}
break;
case VT_R4:
((PROPVARIANT*)(*ppct)->value.pvValue)->fltVal = (float)hVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_R4;
break;
case VT_R8:
((PROPVARIANT*)(*ppct)->value.pvValue)->dblVal = (double)hVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_R8;
break;
default:
hr = DB_E_CANTCONVERTVALUE;
}
}
break;
case VT_R8:
switch ( dbType )
{
case VT_R4:
((PROPVARIANT*)(*ppct)->value.pvValue)->fltVal =
(float)((PROPVARIANT*)(*ppct)->value.pvValue)->dblVal;
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_R4;
break;
case VT_CY:
hr = VariantChangeTypeEx( (*ppct)->value.pvarValue, // convert in place
(*ppct)->value.pvarValue,
LOCALE_SYSTEM_DEFAULT,
0,
VT_CY );
break;
default:
hr = DB_E_CANTCONVERTVALUE;
}
break;
case VT_BSTR:
switch ( dbType )
{
case VT_R8:
//
// Our syntax doesn't allow for numeric separators in other
// locales than US English. So, use the English US lcid for this
// conversion.
//
hr = VariantChangeTypeEx((*ppct)->value.pvarValue, // convert in place
(*ppct)->value.pvarValue,
MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
SORT_DEFAULT),
0,
VT_R8);
break;
case VT_LPSTR:
{
int cLen = WideCharToMultiByte(
CP_ACP,
0,
((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal,
SysStringLen(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal), // number of characters in string
NULL, // address of buffer for new string
0, // size of buffer
NULL, // address of default for unmappable characters
NULL); // address of flag set when default char. used
LPSTR pszVal = (LPSTR) CoTaskMemAlloc(cLen+1);
if (NULL == pszVal)
hr = E_OUTOFMEMORY;
else
{
cLen = WideCharToMultiByte(
CP_ACP,
0,
((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal,
SysStringLen(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal), // number of characters in string
pszVal, // address of buffer for new string
cLen+1, // size of buffer
NULL, // address of default for unmappable characters
NULL); // address of flag set when default char. used
SysFreeString(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal);
pszVal[cLen] = '\0';
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_LPSTR;
((PROPVARIANT*)(*ppct)->value.pvValue)->pszVal = pszVal;
}
}
break;
case VT_LPWSTR:
{
LPWSTR pwszVal = CoTaskStrDup(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal);
if (NULL == pwszVal)
hr = E_OUTOFMEMORY;
else
{
SysFreeString(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal);
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_LPWSTR;
((PROPVARIANT*)(*ppct)->value.pvValue)->pwszVal = pwszVal;
}
}
break;
case VT_CLSID:
{
GUID* pGuid = (GUID*) CoTaskMemAlloc(sizeof GUID);
if (NULL == pGuid)
hr = E_OUTOFMEMORY;
else
{
BOOL bRet = ParseGuid(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal, *pGuid);
if ( bRet && GUID_NULL != *pGuid )
{
SysFreeString(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal);
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_CLSID;
((PROPVARIANT*)(*ppct)->value.pvValue)->puuid = pGuid;
}
else
{
CoTaskMemFree(pGuid);
hr = DB_E_CANTCONVERTVALUE;
}
}
}
break;
case VT_FILETIME:
case VT_DATE:
{
SYSTEMTIME stValue = {0, 0, 0, 0, 0, 0, 0, 0};
// convert a string to a filetime value
int cItems = swscanf(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal,
L"%4hd/%2hd/%2hd %2hd:%2hd:%2hd:%3hd",
&stValue.wYear,
&stValue.wMonth,
&stValue.wDay,
&stValue.wHour,
&stValue.wMinute,
&stValue.wSecond,
&stValue.wMilliseconds);
if (1 == cItems)
cItems = swscanf(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal,
L"%4hd-%2hd-%2hd %2hd:%2hd:%2hd:%3hd",
&stValue.wYear,
&stValue.wMonth,
&stValue.wDay,
&stValue.wHour,
&stValue.wMinute,
&stValue.wSecond,
&stValue.wMilliseconds );
if (cItems != 3 && cItems != 6 && cItems != 7)
hr = E_FAIL;
//
// Make a sensible split for Year 2000 using the user's system settings
//
if ( stValue.wYear < 100 )
{
DWORD dwYearHigh = 0;
if ( 0 == GetCalendarInfo ( m_pIPSession->GetLCID(),
CAL_GREGORIAN,
CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
0,
0,
&dwYearHigh ) )
{
hr = HRESULT_FROM_WIN32 ( GetLastError() );
}
if ( ( dwYearHigh < 99 ) || ( dwYearHigh > 9999 ) )
dwYearHigh = 2029;
WORD wMaxDecade = (WORD) dwYearHigh % 100;
WORD wMaxCentury = (WORD) dwYearHigh - wMaxDecade;
if ( stValue.wYear <= wMaxDecade )
stValue.wYear += wMaxCentury;
else
stValue.wYear += ( wMaxCentury - 100 );
}
SysFreeString(((PROPVARIANT*)(*ppct)->value.pvValue)->bstrVal);
int iResult = 0;
if (VT_FILETIME == dbType)
iResult = SystemTimeToFileTime(&stValue, &((PROPVARIANT*)(*ppct)->value.pvValue)->filetime);
else
iResult = SystemTimeToVariantTime(&stValue, &((PROPVARIANT*)(*ppct)->value.pvValue)->date);
if (0 == iResult)
{
// SystemTimeTo* conversion failed. Most likely we were given the date in a bogus format.
(*ppct)->hrError = DB_E_CANTCONVERTVALUE;
hr = DB_E_CANTCONVERTVALUE;
}
else
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = dbType;
}
break;
default:
hr = DB_E_CANTCONVERTVALUE;
}
break;
case VT_FILETIME:
switch ( dbType )
{
case VT_DATE:
{
SYSTEMTIME stValue = {0, 0, 0, 0, 0, 0, 0, 0};
if ( FileTimeToSystemTime(&((PROPVARIANT*)(*ppct)->value.pvValue)->filetime, &stValue) )
{
int iResult = SystemTimeToVariantTime(&stValue, &((PROPVARIANT*)(*ppct)->value.pvValue)->date);
if (0 == iResult)
{
// SystemTimeToVariantTime failed. Most likely we were given the date in a bogus format.
(*ppct)->hrError = DB_E_CANTCONVERTVALUE;
hr = DB_E_CANTCONVERTVALUE;
}
else
((PROPVARIANT*)(*ppct)->value.pvValue)->vt = VT_DATE;
}
else
hr = DISP_E_TYPEMISMATCH;
}
break;
default:
hr = DB_E_CANTCONVERTVALUE;
}
break;
default:
hr = DB_E_CANTCONVERTVALUE;
break;
}
error:
if (S_OK != hr)
{
switch ( hr )
{
case DB_E_DATAOVERFLOW:
m_pIPTProperties->SetErrorHResult(hr, MONSQL_OUT_OF_RANGE);
break;
case E_OUTOFMEMORY:
m_pIPTProperties->SetErrorHResult(hr, MONSQL_OUT_OF_MEMORY);
break;
default:
m_pIPTProperties->SetErrorHResult(hr, MONSQL_CANNOT_CONVERT);
}
m_pIPTProperties->SetErrorToken((YY_CHAR*)m_yylex.YYText());
switch ( dbType )
{
case DBTYPE_UI1:
m_pIPTProperties->SetErrorToken(L"DBTYPE_UI1");
break;
case DBTYPE_I1:
m_pIPTProperties->SetErrorToken(L"DBTYPE_I1");
break;
case DBTYPE_UI2:
m_pIPTProperties->SetErrorToken(L"DBTYPE_UI2");
break;
case DBTYPE_UI4:
m_pIPTProperties->SetErrorToken(L"DBTYPE_UI4");
break;
case DBTYPE_UI8:
m_pIPTProperties->SetErrorToken(L"DBTYPE_UI8");
break;
case DBTYPE_I2:
m_pIPTProperties->SetErrorToken(L"DBTYPE_I2");
break;
case DBTYPE_I4:
m_pIPTProperties->SetErrorToken(L"DBTYPE_I4");
break;
case DBTYPE_I8:
m_pIPTProperties->SetErrorToken(L"DBTYPE_I8");
break;
case DBTYPE_R4:
m_pIPTProperties->SetErrorToken(L"DBTYPE_R4");
break;
case DBTYPE_R8:
m_pIPTProperties->SetErrorToken(L"DBTYPE_R8");
break;
case DBTYPE_CY:
m_pIPTProperties->SetErrorToken(L"DBTYPE_CY");
break;
case DBTYPE_DATE:
m_pIPTProperties->SetErrorToken(L"DBTYPE_DATE");
break;
case DBTYPE_BSTR:
m_pIPTProperties->SetErrorToken(L"DBTYPE_BSTR");
break;
case DBTYPE_BOOL:
m_pIPTProperties->SetErrorToken(L"DBTYPE_BOOL");
break;
case DBTYPE_GUID:
m_pIPTProperties->SetErrorToken(L"DBTYPE_GUID");
break;
case DBTYPE_STR:
m_pIPTProperties->SetErrorToken(L"DBTYPE_STR");
break;
case DBTYPE_STR | DBTYPE_BYREF:
m_pIPTProperties->SetErrorToken(L"DBTYPE_STR|DBTYPE_BYREF");
break;
case DBTYPE_WSTR:
m_pIPTProperties->SetErrorToken(L"DBTYPE_WSTR");
break;
case DBTYPE_WSTR | DBTYPE_BYREF:
m_pIPTProperties->SetErrorToken(L"DBTYPE_WSTR | DBTYPE_BYREF");
break;
case VT_FILETIME:
m_pIPTProperties->SetErrorToken(L"VT_FILETIME");
break;
default:
m_pIPTProperties->SetErrorToken(L"DBTYPE_NULL");
break;
}
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CYYBase::yyprimebuffer, public
//
// Synopsis: Prime lexer with text (passthrough to lexer)
//
// Arguments: [pszBuffer] -- Buffer
//
// History: 30-Nov-1999 KyleP Moved from YYPARSER
//
//--------------------------------------------------------------------------
void CYYBase::yyprimebuffer(YY_CHAR *pszBuffer)
{
m_yylex.yyprimebuffer(pszBuffer);
}
//+-------------------------------------------------------------------------
//
// Member: CYYBase::yyprimelexer, public
//
// Synopsis: Prime lexer with initial token (passthrough to lexer)
//
// Arguments: [eToken] -- Token
//
// History: 30-Nov-1999 KyleP Moved from YYPARSER
//
//--------------------------------------------------------------------------
void CYYBase::yyprimelexer(int eToken)
{
m_yylex.yyprimelexer(eToken);
}
//+-------------------------------------------------------------------------
//
// Member: CYYBase::yyerror, protected
//
// Synopsis: Report parsing errors
//
// Arguments: [szError] -- Error string
//
// History: 30-Nov-1999 KyleP Moved from YYPARSER
//
//--------------------------------------------------------------------------
void CYYBase::yyerror( char const * szError )
{
}