home *** CD-ROM | disk | FTP | other *** search
- // GetData.cpp -- Data file consumption routines
- //
- // This file is part of Microsoft SQL Server online documentation.
- // Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
- //
- // This source code is an intended supplement to the Microsoft SQL
- // Server online references and related electronic documentation.
- #include "stdafx.h"
- #include "afxtempl.h"
-
- #include "resource.h"
- #include "GetData.h"
-
- #define MAXINTSTR 32
-
- #define DATETIMEADD(pval, c) (*pval) = (((*pval) * 10) + ((c) - '0'))
- #define CHECKBUFFER(cbData,pDataAtExec) (cbData % ALLOCBLOCK ? 0 : 1)
-
- static PSTR ConsumeStringTail(PSTR pin, BOOL bInQuote);
- static PSTR ConsumeValue(PSTR pin);
- static PSTR CheckExtendBuffer(PDATA_AT_EXEC pDataAtExec, UINT cbData);
-
- //////////////////////////////////////////////////////////////////////////
- // ConsumeStringTail -- Chew through the end of a string data item that's
- // too long.
- PSTR ConsumeStringTail
- (
- PSTR pin,
- BOOL bInQuote
- )
- {
- char c;
-
- while ((c = *pin++) != NULL)
- {
- switch (c)
- {
- case ('"'):
- {
- // Check to see if it's an escaped quote character.
- if (!(bInQuote && *pin == '"'))
- {
- bInQuote = !(bInQuote);
- }
- break;
- }
-
- case (','):
- case ('\n'):
- {
- if (!bInQuote)
- {
- return (pin);
- }
-
- break;
- }
- }
- }
-
- // Hit NULL, returns bad pointer.
- return (pin);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // ConsumeValue -- Chew through a data file to find the next delimiter
- // (a ',' or line terminator).
- PSTR ConsumeValue(PSTR pin)
- {
- char c;
-
- while ((c = *pin++) != NULL)
- {
- switch (c)
- {
- case (','):
- case ('\n'):
- {
- return (pin);
- }
-
- default:
- break;
- }
- }
-
- // Hit NULL, return current pointer.
- return (pin);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // FieldData -- Extracts a value from the data file as character data.
- // Ignores enclosing '"' characters, escapes SQL Server quotes.
- //
- // The caller indicates a return buffer for the character data and must
- // ensure that the buffer is large enough to hold the extracted string.
- //
- // Returns: The position of the next data value or NULL on data error.
- PSTR FieldData
- (
- PSTR pin,
- PSTR pout,
- UINT cboutMax,
- UINT* pcbout
- )
- {
- UINT cbData = 0;
- char c;
- BOOL bQuotedText = (*pin == '"' ? TRUE : FALSE);
- BOOL bInQuote = FALSE;
-
- *pcbout = 0;
-
- // Catch case of NULL string as ...,"",... in a data file.
- if (bQuotedText)
- {
- bInQuote = TRUE;
- pin++;
- }
-
- while (cbData < cboutMax)
- {
- switch (c = *pin++)
- {
- case ('"'):
- {
- // Check to see if it's an escaped quote character.
- if (bInQuote && *pin == '"')
- {
- pout[cbData++] = c;
- pin++;
- }
- else
- {
- bInQuote = !(bInQuote);
- }
- break;
- }
-
- case (NULL):
- {
- // Check to see if it's a valid terminator. Either way
- // we're returning from here.
- if (!bQuotedText)
- {
- pout[cbData] = (char) NULL;
- *pcbout = cbData;
- }
-
- return (pin);
- }
-
- case ('\r'):
- {
- if (bInQuote)
- {
- pout[cbData++] = c;
- }
- break;
- }
-
- case (','):
- case ('\n'):
- {
- if (bInQuote)
- {
- pout[cbData++] = c;
- }
- else
- {
- pout[cbData] = (char) NULL;
- *pcbout = cbData;
-
- return (pin);
- }
-
- break;
- }
-
- default:
- {
- pout[cbData++] = c;
- break;
- }
- }
- }
-
- // We fell through, truncating due to too small a buffer used
- // by our caller. Chew up the rest of the column's data.
- pout[--cbData] = (char) NULL;
- *pcbout = cbData;
-
- return (ConsumeStringTail(pin, bInQuote));
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetColNamesFromData -- Yanks column names out of the first line of a
- // data file. Sets the value of pnDataCols to the number of columns found
- // in pin. Builds an array of column names into ppColNames.
- //
- // Returns TRUE if it looks like the line contains column names (all
- // comma delimited strings are enclosed in quotes). FALSE otherwise.
- BOOL GetColNamesFromData
- (
- PSTR pin,
- UINT* pnDataCols,
- PTSTR** ppColNames
- )
- {
- PSTR pColumn;
- PTSTR pColName;
- UINT nDataCols = 0;
- UINT nDataCol;
- UINT cbColName;
- BOOL bGoodCols = TRUE;
- PTSTR* pColNames;
- CList<PTSTR, PTSTR> listColNames;
-
- *pnDataCols = 0;
- *ppColNames = NULL;
-
- pColumn = strtok(pin, ",");
- while (pColumn != NULL && bGoodCols == TRUE)
- {
- cbColName = strlen(pColumn);
- if (*pColumn == '"')
- {
- pColName = new TCHAR[cbColName];
- #ifdef _UNICODE
- MultiByteToWideChar(CP_ACP, 0, pColumn + 1, -1, pColName,
- cbColName);
- #else
- strcpy(pColName, pColumn + 1);
- #endif
- if (pColName[cbColName - 2] == _T('"'))
- {
- pColName[cbColName - 2] = (TCHAR) NULL;
- listColNames.AddTail(pColName);
- nDataCols++;
- }
- else
- {
- bGoodCols = FALSE;
- }
- }
- else
- {
- bGoodCols = FALSE;
- }
-
- pColumn = strtok(NULL, ",");
- }
-
- if (bGoodCols == TRUE)
- {
- pColNames = new PTSTR[nDataCols];
-
- for (nDataCol = 0; nDataCol < nDataCols; nDataCol++)
- {
- pColNames[nDataCol] =
- listColNames.GetAt(listColNames.FindIndex(nDataCol));
- }
-
- *ppColNames = pColNames;
- *pnDataCols = nDataCols;
- }
- else
- {
- for (nDataCol = 0; nDataCol < nDataCols; nDataCol++)
- {
- pColName = listColNames.GetAt(listColNames.FindIndex(nDataCol));
- delete [] pColName;
- }
- }
-
- return (bGoodCols);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetBinaryData -- Converts a character representation of a binary
- // value to its binary equivalent. The character representation is
- // prefixed with "0x" and each binary byte is represented by a two
- // character hexidecimal number. For example, the characters
- // "0x476F6F64" translates to the four byte string "Good".
- //
- // The converted string is returned in the DataAtExec structure passed
- // in. The structure holds the data pointer and the length of the
- // binary data.
- //
- // Returns: The position of the next data value.
- PSTR GetBinaryData
- (
- PSTR pin,
- PBYTE pout,
- UINT cboutMax,
- UINT* pcbout
- )
- {
- UINT cbData = 0;
- char c;
- BYTE bUpper;
- BYTE bLower;
-
- *pcbout = 0;
- if (*pin == ',')
- {
- return (pin++);
- }
-
- if (*pin != '0' || (*(pin + 1) & 0x5F) != 'X')
- {
- AfxMessageBox(IDS_ERR_BINARYFORMAT);
- return (ConsumeValue(pin));
- }
-
- pin += 2;
- while (cbData < cboutMax)
- {
- switch (c = *pin++)
- {
- case ('\r'):
- {
- break;
- }
-
- case (NULL):
- case (','):
- case ('\n'):
- {
- // Any of our field terminators.
- *pcbout = cbData;
- return (pin);
- }
-
- default:
- {
- bUpper = (BYTE) (c > '9' ? c - 'A' + 10 : c - '0');
-
- c = *pin++;
- bLower = (BYTE) (c > '9' ? c - 'A' + 10 : c - '0');
-
- if (bUpper > 15 || bLower > 15)
- {
- AfxMessageBox(IDS_ERR_BINARYCHARACTER);
- return (ConsumeValue(pin));
- }
-
- pout[cbData++] = (bUpper <<= 4) + bLower;
- break;
- }
- }
- }
-
- // Past the end of allowed space.
- return (ConsumeValue(pin));
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetCharData -- Extracts a character value from the data file. The
- // character string must be enclosed in '"' characters.
- //
- // The caller indicates a return buffer for the character data and must
- // ensure that the buffer is large enough to hold the extracted string.
- //
- // Returns: The position of the next data value.
- PSTR GetCharData
- (
- PSTR pin,
- PSTR pout,
- UINT cboutMax,
- UINT* pcbout
- )
- {
- UINT cbData;
- char c;
- BOOL bInQuote = FALSE;
-
- *pcbout = cbData = 0;
- while (cbData < cboutMax)
- {
- switch (c = *pin++)
- {
- case (NULL):
- {
- // NULL is not a valid terminator for a quoted text string.
- return (pin);
- }
-
- case ('"'):
- {
- // Check to see if it's an escaped quote character.
- if (bInQuote && *pin == '"')
- {
- pout[cbData++] = c;
- pin++;
- }
- else
- {
- bInQuote = !(bInQuote);
- }
- break;
- }
-
- case ('\r'):
- {
- if (bInQuote)
- {
- pout[cbData++] = c;
- }
- break;
- }
-
- case (','):
- case ('\n'):
- {
- if (bInQuote)
- {
- pout[cbData++] = c;
- }
- else
- {
- pout[cbData] = (char) NULL;
- *pcbout = cbData;
- return (pin);
- }
-
- break;
- }
-
- default:
- {
- pout[cbData++] = c;
- break;
- }
- }
- }
-
- // Too much data for our parameter; chew up the rest of the
- // data item.
- pout[--cbData] = (char) NULL;
- *pcbout = cbData;
-
- return (ConsumeStringTail(pin, bInQuote));
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetDateData -- Extracts a date value from the data file. Data file
- // dates are in ODBC yyyy-mm-dd hh:mm:ss:ffff format. The string is
- // not enclosed in quotes.
- //
- // The converted string is returned in the ODBC defined timestamp
- // structure received. The length of data chewed is returned so that
- // the caller can determine if the value is NULL.
- //
- // Returns: The position of the next data value.
- PSTR GetDateData(PSTR pin, SQL_TIMESTAMP_STRUCT* pts, UINT* pcbout)
- {
- UINT cbData = 0;
- BOOL bHaveYe = FALSE;
- BOOL bHaveMo = FALSE;
- BOOL bHaveDa = FALSE;
- BOOL bHaveHo = FALSE;
- BOOL bHaveMi = FALSE;
- BOOL bHaveSe = FALSE;
- char c;
-
- // Set default date and time.
- pts->year = 0;
- pts->month = 0;
- pts->day = 0;
- pts->hour = 0;
- pts->minute = 0;
- pts->second = 0;
- pts->fraction = 0;
-
- *pcbout = 0;
- while (TRUE)
- {
- switch (c = *pin++)
- {
- // Handle CRLF as well as LF only text files.
- case ('\r'):
- {
- break;
- }
-
- case (NULL):
- case (','):
- case ('\n'):
- {
- if (bHaveYe && bHaveMo && bHaveDa)
- {
- *pcbout = cbData;
- }
-
- return (pin);
- }
-
- case ('-'):
- {
- // Data error if first char or all date parts are parsed.
- if ((!bHaveYe && pts->year == 0) ||
- (bHaveYe && bHaveMo && bHaveDa))
- {
- return (ConsumeValue(pin));
- }
-
- if (!bHaveYe)
- {
- bHaveYe = TRUE;
- }
- else
- {
- bHaveMo = TRUE;
- }
-
- break;
- }
-
- case (' '):
- {
- // If we hit the delimeter between date and time and
- // we don't have all date parts, or we've hit it a
- // second time, error, return NULL data.
- if (pts->day == 0 || (bHaveYe && bHaveMo && bHaveDa))
- {
- return (ConsumeValue(pin));
- }
-
- bHaveDa = TRUE;
- break;
- }
-
- case (':'):
- {
- if (bHaveHo && bHaveMi && bHaveSe)
- {
- return (ConsumeValue(pin));
- }
-
- if (!bHaveHo)
- {
- bHaveHo = TRUE;
- }
- else
- {
- bHaveMi = TRUE;
- }
- break;
- }
-
- case ('.'):
- {
- // If encountered before hours and minutes retrieved,
- // or after we've got the number of seconds in the time,
- // then the thousands of a second delimiter's an error.
- if (!bHaveHo || !bHaveMi || bHaveSe)
- {
- return (ConsumeValue(pin));
- }
-
- bHaveSe = TRUE;
- }
-
- default:
- {
- if (!isdigit(c))
- {
- return (ConsumeValue(pin));
- }
-
- if (!bHaveYe)
- {
- DATETIMEADD(&(pts->year), c);
- }
- else if (!bHaveMo)
- {
- DATETIMEADD(&(pts->month), c);
- }
- else if (!bHaveDa)
- {
- DATETIMEADD(&(pts->day), c);
- }
- else if (!bHaveHo)
- {
- DATETIMEADD(&(pts->hour), c);
- }
- else if (!bHaveMi)
- {
- DATETIMEADD(&(pts->minute), c);
- }
- else if (!bHaveSe)
- {
- DATETIMEADD(&(pts->second), c);
- }
- else
- {
- DATETIMEADD(&(pts->fraction), c);
- }
-
- cbData++;
- break;
- }
- }
- }
-
- // Function returns from switch statement. Dummy return to satisify
- // compiler.
- return (pin);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetIntegerData -- Extracts an integral value from the data file.
- //
- // The number of digit characters converted is returned to the caller.
- // Zero characters indicate a NULL value.
- //
- // Returns: The position of the next data value.
- PSTR GetIntegerData(PSTR pin, int* piout, UINT* pcbout)
- {
- UINT cbData = 0;
- CHAR c;
- CHAR acData[MAXINTSTR];
-
- *pcbout = 0;
- while (cbData < MAXINTSTR)
- {
- switch (c = *pin++)
- {
- // Handle CRLF as well as LF only text files
- case ('\r'):
- {
- break;
- }
-
- case (NULL):
- case (','):
- case ('\n'):
- {
- acData[cbData] = (char) NULL;
- if (cbData)
- {
- *piout = atoi(acData);
- }
-
- *pcbout = cbData;
- return (pin);
- }
-
- default:
- {
- // If it's a digit, add it to our string. If it's a
- // decimal point and everything up until now has been
- // a digit, return the integer portion.
- if (isdigit(c))
- {
- acData[cbData++] = c;
- }
- else if (c == '.' && cbData)
- {
- acData[cbData] = (char) NULL;
- *piout = atoi(acData);
- *pcbout = cbData;
- return (ConsumeValue(pin));
- }
- else
- {
- return (ConsumeValue(pin));
- }
-
- break;
- }
- }
- }
-
- // We've got some really long string of digits. Whatever it is, we can't
- // do anything of value with it.
- return (ConsumeValue(pin));
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetNumericData -- Extracts a numeric value from the data file.
- // Numeric values are fixed in precision and scale and are represented
- // by NULL-terminated strings of digit characters.
- //
- // Approximate numerics (float and double) are handled here as well,
- // allowing the server (or driver) to convert to internal representation.
- //
- // The number of digit characters extracted is returned to the caller
- // Zero characters extracted indicates a NULL value.
- //
- // Returns: The position of the next data value.
- PSTR GetNumericData
- (
- PSTR pin,
- PSTR pout,
- UINT cboutMax,
- UINT* pcbout
- )
- {
- UINT cbData = 0;
- char c;
-
- *pcbout = 0;
- while (cbData < cboutMax)
- {
- switch (c = *pin++)
- {
- // Handle CRLF as well as LF only text files.
- case ('\r'):
- {
- break;
- }
-
- case (NULL):
- case (','):
- case ('\n'):
- {
- pout[cbData] = (char) NULL;
- *pcbout = cbData;
- return (pin);
- }
-
- default:
- {
- if (isdigit(c) || c == '.' || c == '+' || c == '-'
- || c == 'e' || c == 'E')
- {
- pout[cbData++] = c;
- }
-
- break;
- }
- }
- }
-
- pout[--cbData] = (char) NULL;
- *pcbout = cbData;
- return (ConsumeValue(pin));
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetWCharData -- Extracts a character value from the data file, then
- // converts the character value to wide char. The character string must
- // be enclosed in '"' characters.
- //
- // The caller indicates a return buffer for the character data and must
- // ensure that the buffer is large enough to hold the extracted string.
- //
- // Returns: The position of the next data value.
- PSTR GetWCharData
- (
- PSTR pin,
- WCHAR* pout,
- UINT cboutMax,
- UINT* pcbout
- )
- {
- PSTR pdatanext;
- UINT nchars = cboutMax >> 1;
- PSTR pdatain = new char[nchars];
- UINT cbdatain = 0;
-
- *pcbout = 0;
-
- if (pdatain == NULL)
- {
- return (ConsumeValue(pin));
- }
-
- pdatanext = GetCharData(pin, pdatain, nchars, &cbdatain);
-
- if (cbdatain)
- {
- MultiByteToWideChar(CP_ACP, 0, pdatain, cbdatain,
- pout, nchars);
- *pcbout = cbdatain << 1;
- }
-
- delete [] pdatain;
-
- return (pdatanext);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetLongBinaryData -- Extracts a character value from the data file.
- // The character string begins with the characters "0x" or "0X".
- //
- // The string is returned in the DataAtExec structure passed. The
- // structure holds the data pointer and the length of the text data.
- //
- // Returns: The position of the next data value.
- PSTR GetLongBinaryData
- (
- PSTR pin,
- PDATA_AT_EXEC pDataAtExec
- )
- {
- UINT cbData = 0;
- char c;
- PSTR pDataOut;
-
- if (pDataAtExec->pData == NULL)
- {
- pDataAtExec->pData = new BYTE[ALLOCBLOCK];
- pDataAtExec->cbBuffer = ALLOCBLOCK;
- }
-
- pDataAtExec->cbData = 0;
- if (*pin == _T('0'))
- {
- pin++;
- if (((*pin) & 0x5F) != _T('X'))
- {
- return (ConsumeValue(pin));
- }
-
- pin++;
- }
-
- pDataOut = (PSTR) pDataAtExec->pData;
- while (TRUE)
- {
- switch (c = *pin++)
- {
- case ('\r'):
- {
- break;
- }
-
- case (NULL):
- case (','):
- case ('\n'):
- {
- pDataOut[cbData] = (char) NULL;
- pDataAtExec->cbData = cbData;
-
- return (pin);
- }
-
- default:
- {
- if (!isxdigit(c))
- {
- return (ConsumeValue(pin));
- }
-
- pDataOut[cbData++] = c;
- if (CHECKBUFFER(cbData, pDataAtExec))
- {
- pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
- if (pDataOut == NULL)
- {
- return (ConsumeValue(pin));
- }
- }
-
- break;
- }
- }
- }
-
- // Dummy return for compiler.
- return (pin);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // GetLongCharData -- Extracts a character value from the data file. The
- // character string must be enclosed in '"' characters.
- //
- // The string is returned in the DataAtExec structure passed. The
- // structure holds the data pointer and the length of the text data.
- //
- // Returns: The position of the next data value.
- PSTR GetLongCharData
- (
- PSTR pin,
- PDATA_AT_EXEC pDataAtExec
- )
- {
- UINT cbData = 0;
- char c;
- BOOL bInQuote = FALSE;
- PSTR pDataOut;
-
- pDataAtExec->cbData = 0;
- if (pDataAtExec->pData == NULL)
- {
- pDataAtExec->pData = new BYTE[ALLOCBLOCK];
- if (pDataAtExec->pData == NULL)
- {
- return (ConsumeStringTail(pin, bInQuote));
- }
-
- pDataAtExec->cbBuffer = ALLOCBLOCK;
- }
-
- pDataOut = (PSTR) pDataAtExec->pData;
- while (TRUE)
- {
- switch (c = *pin++)
- {
- case ('"'):
- {
- // If in quotes, test for escaped quote character.
- if (bInQuote && *pin == '"')
- {
- pDataOut[cbData++] = c;
- if (CHECKBUFFER(cbData, pDataAtExec))
- {
- pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
- if (pDataOut == NULL)
- {
- return (ConsumeStringTail(pin, bInQuote));
- }
- }
-
- pin++;
- }
- else
- {
- bInQuote = !(bInQuote);
- }
- break;
- }
-
- // CRLF within the string is respected, otherwise CR is
- // ignored.
- case ('\r'):
- {
- if (bInQuote)
- {
- pDataOut[cbData++] = c;
- if (CHECKBUFFER(cbData, pDataAtExec))
- {
- pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
- if (pDataOut == NULL)
- {
- return (ConsumeStringTail(pin, bInQuote));
- }
- }
- }
-
- break;
- }
-
- case (NULL):
- {
- // If we unexpectedly ran out of string, just return. Else
- // fall through to normal terminator processing.
- if (bInQuote)
- {
- return (pin);
- }
- }
- case (','):
- case ('\n'):
- {
- if (bInQuote)
- {
- pDataOut[cbData++] = c;
- if (CHECKBUFFER(cbData, pDataAtExec))
- {
- pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
- if (pDataOut == NULL)
- {
- return (ConsumeStringTail(pin, bInQuote));
- }
- }
- }
- else
- {
- pDataAtExec->cbData = cbData;
- pDataOut[cbData] = (char) NULL;
-
- return (pin);
- }
-
- break;
- }
-
- default:
- {
- pDataOut[cbData++] = c;
- if (CHECKBUFFER(cbData, pDataAtExec))
- {
- pDataOut = CheckExtendBuffer(pDataAtExec, cbData);
- if (pDataOut == NULL)
- {
- return (ConsumeStringTail(pin, bInQuote));
- }
- }
-
- break;
- }
- }
- }
-
- // Dummy return for compiler.
- return (pin);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // CheckExtendBuffer(PDATA_AT_EXEC pDataAtExec, UINT cbData)
- //
- // Static reallocates buffer if macro check indicates need.
- PSTR CheckExtendBuffer(PDATA_AT_EXEC pDataAtExec, UINT cbData)
- {
- if (cbData == pDataAtExec->cbBuffer)
- {
- UINT cbNew = pDataAtExec->cbBuffer + ALLOCBLOCK;
- PBYTE pNew = new BYTE[cbNew];
-
- if (pNew == NULL)
- {
- // We're out of memory. Free what's allocated here and
- // attempt to launch an error message before doing
- // anything else.
- delete [] pDataAtExec->pData;
- pDataAtExec->pData = NULL;
-
- AfxMessageBox(_T("Memory allocation error."));
- return (NULL);
- }
-
- memcpy(pNew, pDataAtExec->pData, cbData);
- delete [] pDataAtExec->pData;
-
- pDataAtExec->pData = pNew;
- pDataAtExec->cbBuffer = cbNew;
- }
-
- return ((PSTR) pDataAtExec->pData);
- }