windows-nt/Source/XPSP1/NT/admin/wmi/wbem/adapters/odbc/evaluate.cpp
2020-09-26 16:20:57 +08:00

6566 lines
209 KiB
C++

/***************************************************************************/
/* EVALUATE.C */
/* Copyright (C) 1995-96 SYWARE Inc., All rights reserved */
/***************************************************************************/
// Commenting #define out - causing compiler error - not sure if needed, compiles
// okay without it.
//#define WINVER 0x0400
#include "precomp.h"
#include "wbemidl.h"
#include <comdef.h>
//smart pointer
_COM_SMARTPTR_TYPEDEF(IWbemServices, IID_IWbemServices);
_COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, IID_IEnumWbemClassObject);
//_COM_SMARTPTR_TYPEDEF(IWbemContext, IID_IWbemContext );
_COM_SMARTPTR_TYPEDEF(IWbemLocator, IID_IWbemLocator);
#include "drdbdr.h"
#include <time.h>
#include <memory.h>
/***************************************************************************/
#define SECONDS_PER_DAY (60L * 60L * 24L)
typedef struct HFILE_BUFFERtag {
HGLOBAL hGlobal;
HFILE hfile;
UWORD offset;
LPSTR ptr;
char buffer[32768];
} HF_BUFFER, FAR * HFILE_BUFFER;
HFILE_BUFFER _lcreat_buffer(LPCSTR szFilename, int arg)
{
HGLOBAL h;
HFILE_BUFFER hf;
h = GlobalAlloc(GMEM_MOVEABLE, sizeof(HF_BUFFER));
if (h == NULL)
return NULL;
hf = (HFILE_BUFFER) GlobalLock(h);
if (hf == NULL) {
GlobalFree(h);
return NULL;
}
hf->hGlobal = h;
hf->hfile = _lcreat(szFilename, arg);
if (hf->hfile == HFILE_ERROR) {
GlobalUnlock(h);
GlobalFree(h);
return NULL;
}
hf->offset = 0;
hf->ptr = hf->buffer;
return hf;
}
HFILE _lclose_buffer(HFILE_BUFFER hf)
{
HGLOBAL h;
if (hf->offset != 0) {
if ((UINT) hf->offset !=
_lwrite(hf->hfile, hf->buffer, (UINT) hf->offset)) {
h = hf->hGlobal;
_lclose(hf->hfile);
GlobalUnlock(h);
GlobalFree(h);
return HFILE_ERROR;
}
}
if (HFILE_ERROR == _lclose(hf->hfile)) {
h = hf->hGlobal;
GlobalUnlock(h);
GlobalFree(h);
return HFILE_ERROR;
}
h = hf->hGlobal;
GlobalUnlock(h);
GlobalFree(h);
return 0;
}
UINT _lwrite_buffer(HFILE_BUFFER hf, LPSTR ptr, UINT len)
{
UWORD total;
UWORD count;
total = 0;
while (TRUE) {
if (len > sizeof(hf->buffer) - hf->offset)
count = sizeof(hf->buffer) - hf->offset;
else
count = (UWORD) len;
_fmemcpy(hf->ptr, ptr, count);
hf->ptr += (count);
ptr += (count);
hf->offset += (count);
total += (count);
len -= (count);
if (len == 0)
break;
if (sizeof(hf->buffer) !=
_lwrite(hf->hfile, hf->buffer, sizeof(hf->buffer)))
return ((UINT) HFILE_ERROR);
hf->offset = 0;
hf->ptr = hf->buffer;
}
return total;
}
/***************************************************************************/
void INTFUNC DateAdd(DATE_STRUCT date, SWORD offset, DATE_STRUCT FAR *result)
/* Adds specified number of days to a date */
{
static struct tm tm_time;
time_t t;
/* Create time structure */
tm_time.tm_sec = 0;
tm_time.tm_min = 0;
tm_time.tm_hour = 0;
tm_time.tm_mday = date.day + offset;
tm_time.tm_mon = date.month - 1;
tm_time.tm_year = (date.year >= 1900 ? date.year - 1900 : 0);
tm_time.tm_wday = 0;
tm_time.tm_yday = 0;
tm_time.tm_isdst = 0;
/* Correct values */
t = mktime(&tm_time);
if (t == -1) {
result->year = 0;
result->month = 0;
result->day = 0;
return;
}
/* Return answer */
result->year = tm_time.tm_year + 1900;
result->month = tm_time.tm_mon + 1;
result->day = (WORD) tm_time.tm_mday;
}
/***************************************************************************/
int INTFUNC DateDifference(DATE_STRUCT leftDate, DATE_STRUCT rightDate)
/* Compares two dates. */
{
static struct tm tm_time;
time_t left_t;
time_t right_t;
/* Create left value */
tm_time.tm_sec = 0;
tm_time.tm_min = 0;
tm_time.tm_hour = 0;
tm_time.tm_mday = leftDate.day;
tm_time.tm_mon = leftDate.month-1;
tm_time.tm_year = (leftDate.year >= 1900 ? leftDate.year - 1900 : 0);
tm_time.tm_wday = 0;
tm_time.tm_yday = 0;
tm_time.tm_isdst = 0;
left_t = mktime(&tm_time);
/* Create right value */
tm_time.tm_sec = 0;
tm_time.tm_min = 0;
tm_time.tm_hour = 0;
tm_time.tm_mday = rightDate.day;
tm_time.tm_mon = rightDate.month-1;
tm_time.tm_year = (rightDate.year >= 1900 ? rightDate.year - 1900 : 0);
tm_time.tm_wday = 0;
tm_time.tm_yday = 0;
tm_time.tm_isdst = 0;
right_t = mktime(&tm_time);
/* Return answer */
return (int) ((left_t - right_t) / SECONDS_PER_DAY);
}
/***************************************************************************/
int INTFUNC DateCompare(DATE_STRUCT leftDate, DATE_STRUCT rightDate)
/* Compares two dates. */
{
if ( (leftDate.year - rightDate.year) != 0 )
return (int) (leftDate.year -rightDate.year);
else if ( (leftDate.month - rightDate.month) != 0 )
return (int) (leftDate.month -rightDate.month);
else
return (int) (leftDate.day -rightDate.day);
}
/***************************************************************************/
int INTFUNC TimeCompare(TIME_STRUCT leftTime, TIME_STRUCT rightTime)
/* Compares two times. */
{
if ((leftTime.hour - rightTime.hour) != 0)
return (int) (leftTime.hour - rightTime.hour);
else if ((leftTime.minute - rightTime.minute) != 0)
return (int) (leftTime.minute - rightTime.minute);
else
return (int) (leftTime.second - rightTime.second);
}
/***************************************************************************/
int INTFUNC TimestampCompare(TIMESTAMP_STRUCT leftTimestamp,
TIMESTAMP_STRUCT rightTimestamp)
/* Compares two timestamp. */
{
if ((leftTimestamp.year - rightTimestamp.year) != 0)
return (int) (leftTimestamp.year - rightTimestamp.year);
else if ((leftTimestamp.month - rightTimestamp.month) != 0)
return (int) (leftTimestamp.month - rightTimestamp.month);
else if ((leftTimestamp.day - rightTimestamp.day) != 0)
return (int) (leftTimestamp.day - rightTimestamp.day);
else if ((leftTimestamp.hour - rightTimestamp.hour) != 0)
return (int) (leftTimestamp.hour - rightTimestamp.hour);
else if ((leftTimestamp.minute - rightTimestamp.minute) != 0)
return (int) (leftTimestamp.minute - rightTimestamp.minute);
else if ((leftTimestamp.second - rightTimestamp.second) != 0)
return (int) (leftTimestamp.second - rightTimestamp.second);
else if (leftTimestamp.fraction > rightTimestamp.fraction)
return 1;//-1;
else if (leftTimestamp.fraction < rightTimestamp.fraction)
return -1;//1;
else
return 0;
}
/***************************************************************************/
RETCODE INTFUNC NumericCompare(LPSQLNODE lpSqlNode, LPSQLNODE lpSqlNodeLeft,
UWORD Operator, LPSQLNODE lpSqlNodeRight)
/* Compares two numerical valuesas follows: */
/* lpSqlNode->value.Double = lpSqlNodeLeft Operator lpSqlNodeRight */
{
RETCODE err;
UWORD op;
SQLNODE sqlNode;
UCHAR szBuffer[32];
/* What is the type of the left side? */
switch (lpSqlNodeLeft->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
/* Left side is a double or integer. What is the right side? */
switch (lpSqlNodeRight->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
/* Right side is also a double or an integer. Compare them */
switch (Operator) {
case OP_EQ:
if (lpSqlNodeLeft->value.Double ==
lpSqlNodeRight->value.Double)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_NE:
if (lpSqlNodeLeft->value.Double !=
lpSqlNodeRight->value.Double)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LE:
if (lpSqlNodeLeft->value.Double <=
lpSqlNodeRight->value.Double)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LT:
if (lpSqlNodeLeft->value.Double <
lpSqlNodeRight->value.Double)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GE:
if (lpSqlNodeLeft->value.Double >=
lpSqlNodeRight->value.Double)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GT:
if (lpSqlNodeLeft->value.Double >
lpSqlNodeRight->value.Double)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LIKE:
case OP_NOTLIKE:
default:
return ERR_INTERNAL;
}
break;
case TYPE_NUMERIC:
/* Right side is a numeric. Is left side a double? */
if (lpSqlNodeLeft->sqlDataType == TYPE_DOUBLE) {
/* Yes. Promote the right side to a double */
sqlNode = *lpSqlNodeRight;
sqlNode.sqlDataType = TYPE_DOUBLE;
sqlNode.sqlSqlType = SQL_DOUBLE;
sqlNode.sqlPrecision = 15;
sqlNode.sqlScale = NO_SCALE;
err = CharToDouble(lpSqlNodeRight->value.String,
s_lstrlen(lpSqlNodeRight->value.String), FALSE,
-1.7E308, 1.7E308, &(sqlNode.value.Double));
if (err != ERR_SUCCESS)
return err;
/* Compare the two doubles */
err = NumericCompare(lpSqlNode, lpSqlNodeLeft, Operator,
&sqlNode);
if (err != ERR_SUCCESS)
return err;
}
/* Right side is a numeric. Is left side an integer? */
else { /* (lpSqlNodeLeft->sqlDataType == TYPE_INTEGER) */
/* Yes. Promote the left side to a numeric */
sqlNode = *lpSqlNodeLeft;
sqlNode.sqlDataType = TYPE_NUMERIC;
sqlNode.sqlSqlType = SQL_NUMERIC;
sqlNode.sqlPrecision = 10;
sqlNode.sqlScale = 0;
if (lpSqlNodeLeft->value.Double != 0.0)
wsprintf((LPSTR)szBuffer, "%ld", (long) lpSqlNodeLeft->value.Double);
else
s_lstrcpy((char*)szBuffer, "");
sqlNode.value.String = (LPUSTR)szBuffer;
/* Compare the two numerics */
err = NumericCompare(lpSqlNode, &sqlNode, Operator,
lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
}
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_NUMERIC:
/* Left side is a numeric. What is the right side? */
switch (lpSqlNodeRight->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
/* Right side is a double or integer. Swap left and right and */
/* then do the comaprison */
switch (Operator) {
case OP_EQ:
op = OP_EQ;
break;
case OP_NE:
op = OP_NE;
break;
case OP_LE:
op = OP_GE;
break;
case OP_LT:
op = OP_GT;
break;
case OP_GE:
op = OP_LE;
break;
case OP_GT:
op = OP_LT;
break;
case OP_LIKE:
case OP_NOTLIKE:
default:
return ERR_INTERNAL;
}
err = NumericCompare(lpSqlNode, lpSqlNodeRight, op,
lpSqlNodeLeft);
if (err != ERR_SUCCESS)
return err;
break;
case TYPE_NUMERIC:
/* Right side is also numeric. Compare them as numeric */
err = BCDCompare(lpSqlNode, lpSqlNodeLeft, Operator, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
return ERR_SUCCESS;
}
/***************************************************************************/
SWORD INTFUNC ToInteger(LPSQLNODE lpSqlNode)
/* Returns the value of the node (as an integer). If the data type of the */
/* node is incompatible, zerois returned */
{
double dbl;
RETCODE err;
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
return ((SWORD) lpSqlNode->value.Double);
case TYPE_NUMERIC:
err = CharToDouble(lpSqlNode->value.String,
s_lstrlen(lpSqlNode->value.String), FALSE,
-1.7E308, 1.7E308, &dbl);
if (err != ERR_SUCCESS)
return 0;
return ((SWORD) dbl);
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
default:
return 0;
}
}
/***************************************************************************/
RETCODE INTFUNC NumericAlgebra(LPSQLNODE lpSqlNode, LPSQLNODE lpSqlNodeLeft,
UWORD Operator, LPSQLNODE lpSqlNodeRight,
LPUSTR lpWorkBuffer1, LPUSTR lpWorkBuffer2,
LPUSTR lpWorkBuffer3)
/* Perfoms algebraic operation in two numerical or char values as follows: */
/* lpSqlNode lpSqlNodeLeft Operator lpSqlNodeRight */
{
RETCODE err;
SQLNODE sqlNode;
UCHAR szBuffer[32];
/* What is the type of the left side? */
switch (lpSqlNodeLeft->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
/* Left side is a double or integer. What is the right side? */
switch (lpSqlNodeRight != NULL ? lpSqlNodeRight->sqlDataType :
lpSqlNodeLeft->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
/* Right side is also a double or an integer. Do the operation */
switch (Operator) {
case OP_NEG:
lpSqlNode->value.Double = -(lpSqlNodeLeft->value.Double);
break;
case OP_PLUS:
lpSqlNode->value.Double = lpSqlNodeLeft->value.Double +
lpSqlNodeRight->value.Double;
break;
case OP_MINUS:
lpSqlNode->value.Double = lpSqlNodeLeft->value.Double -
lpSqlNodeRight->value.Double;
break;
case OP_TIMES:
lpSqlNode->value.Double = lpSqlNodeLeft->value.Double *
lpSqlNodeRight->value.Double;
break;
case OP_DIVIDEDBY:
if (lpSqlNodeRight->value.Double != 0.0)
lpSqlNode->value.Double = lpSqlNodeLeft->value.Double /
lpSqlNodeRight->value.Double;
else
return ERR_ZERODIVIDE;
break;
default:
return ERR_INTERNAL;
break;
}
break;
case TYPE_NUMERIC:
/* Right side is a numeric. Is left side a double? */
if (lpSqlNodeLeft->sqlDataType == TYPE_DOUBLE) {
/* Yes. Promote the right side to a double */
sqlNode = *lpSqlNodeRight;
sqlNode.sqlDataType = TYPE_DOUBLE;
sqlNode.sqlSqlType = SQL_DOUBLE;
sqlNode.sqlPrecision = 15;
sqlNode.sqlScale = NO_SCALE;
err = CharToDouble(lpSqlNodeRight->value.String,
s_lstrlen(lpSqlNodeRight->value.String), FALSE,
-1.7E308, 1.7E308, &(sqlNode.value.Double));
if (err != ERR_SUCCESS)
return err;
/* Compute the result */
err = NumericAlgebra(lpSqlNode, lpSqlNodeLeft, Operator,
&sqlNode, lpWorkBuffer1, lpWorkBuffer2,
lpWorkBuffer3);
if (err != ERR_SUCCESS)
return err;
}
/* Right side is a numeric. Is left side an integer? */
else { /* (lpSqlNodeLeft->sqlDataType == TYPE_INTEGER) */
/* Yes. Promote the left side to a numeric */
sqlNode = *lpSqlNodeLeft;
sqlNode.sqlDataType = TYPE_NUMERIC;
sqlNode.sqlSqlType = SQL_NUMERIC;
sqlNode.sqlPrecision = 10;
sqlNode.sqlScale = 0;
if (lpSqlNodeLeft->value.Double != 0.0)
wsprintf((LPSTR)szBuffer, "%ld", (long) lpSqlNodeLeft->value.Double);
else
s_lstrcpy((char*)szBuffer, "");
sqlNode.value.String = (LPUSTR)szBuffer;
/* Compute the result */
err = NumericAlgebra(lpSqlNode, &sqlNode, Operator,
lpSqlNodeRight, lpWorkBuffer1,
lpWorkBuffer2, lpWorkBuffer3);
if (err != ERR_SUCCESS)
return err;
}
break;
case TYPE_DATE:
/* Right side is a date. Do the operation */
switch (Operator) {
case OP_PLUS:
DateAdd(lpSqlNodeRight->value.Date,
ToInteger(lpSqlNodeLeft),
&(lpSqlNode->value.Date));
break;
case OP_NEG:
case OP_MINUS:
case OP_TIMES:
case OP_DIVIDEDBY:
default:
return ERR_INTERNAL;
}
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_TIME:
case TYPE_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_NUMERIC:
/* Left side is a numeric. What is the right side? */
switch (lpSqlNodeRight != NULL ? lpSqlNodeRight->sqlDataType :
lpSqlNodeLeft->sqlDataType) {
case TYPE_DOUBLE:
/* Right side is a double. Promote the left side to a double */
sqlNode = *lpSqlNodeLeft;
sqlNode.sqlDataType = TYPE_DOUBLE;
sqlNode.sqlSqlType = SQL_DOUBLE;
sqlNode.sqlPrecision = 15;
sqlNode.sqlScale = NO_SCALE;
err = CharToDouble(lpSqlNodeLeft->value.String,
s_lstrlen(lpSqlNodeLeft->value.String), FALSE,
-1.7E308, 1.7E308, &(sqlNode.value.Double));
if (err != ERR_SUCCESS)
return err;
/* Compute the result */
err = NumericAlgebra(lpSqlNode, &sqlNode, Operator,
lpSqlNodeRight, lpWorkBuffer1,
lpWorkBuffer2, lpWorkBuffer3);
if (err != ERR_SUCCESS)
return err;
break;
case TYPE_INTEGER:
/* Right side is an integer. Promote the right side to nuemric */
sqlNode = *lpSqlNodeRight;
sqlNode.sqlDataType = TYPE_NUMERIC;
sqlNode.sqlSqlType = SQL_NUMERIC;
sqlNode.sqlPrecision = 10;
sqlNode.sqlScale = 0;
if (lpSqlNodeRight->value.Double != 0.0)
wsprintf((LPSTR)szBuffer, "%ld", (long) lpSqlNodeRight->value.Double);
else
s_lstrcpy((char*)szBuffer, "");
sqlNode.value.String = szBuffer;
/* Compute the result */
err = NumericAlgebra(lpSqlNode, lpSqlNodeLeft, Operator,
&sqlNode, lpWorkBuffer1, lpWorkBuffer2,
lpWorkBuffer3);
if (err != ERR_SUCCESS)
return err;
break;
case TYPE_NUMERIC:
/* Right side is also numeric. Do the operation */
err = BCDAlgebra(lpSqlNode, lpSqlNodeLeft, Operator,
lpSqlNodeRight, lpWorkBuffer1,
lpWorkBuffer2, lpWorkBuffer3);
if (err != ERR_SUCCESS)
return err;
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_DATE:
/* Left side is a date. What operator? */
switch (Operator) {
case OP_NEG:
return ERR_INTERNAL;
break;
case OP_PLUS:
DateAdd(lpSqlNodeLeft->value.Date,
ToInteger(lpSqlNodeRight),
&(lpSqlNode->value.Date));
break;
case OP_MINUS:
switch (lpSqlNodeRight->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
case TYPE_NUMERIC:
DateAdd(lpSqlNodeLeft->value.Date, (SWORD)
-(ToInteger(lpSqlNodeRight)),
&(lpSqlNode->value.Date));
break;
case TYPE_CHAR:
case TYPE_BINARY:
return ERR_INTERNAL;
break;
case TYPE_DATE:
lpSqlNode->value.Double = DateDifference(
lpSqlNodeLeft->value.Date,
lpSqlNodeRight->value.Date);
break;
case TYPE_TIME:
return ERR_INTERNAL;
break;
case TYPE_TIMESTAMP:
return ERR_NOTSUPPORTED;
break;
}
break;
case OP_TIMES:
case OP_DIVIDEDBY:
default:
return ERR_INTERNAL;
break;
}
break;
case TYPE_CHAR:
/* Left side is character. Concatenate */
if ((lpSqlNodeRight->sqlDataType != TYPE_CHAR) ||
(Operator != OP_PLUS))
return ERR_INTERNAL;
if ((s_lstrlen(lpSqlNodeLeft->value.String) +
s_lstrlen(lpSqlNodeRight->value.String)) > lpSqlNode->sqlPrecision)
return ERR_CONCATOVERFLOW;
s_lstrcpy(lpSqlNode->value.String, lpSqlNodeLeft->value.String);
s_lstrcat(lpSqlNode->value.String, lpSqlNodeRight->value.String);
break;
case TYPE_BINARY:
case TYPE_TIME:
case TYPE_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC SetParameterValue(LPSTMT lpstmt,
LPSQLNODE lpSqlNodeParameter,
SDWORD FAR *pcbOffset,
SWORD fCType,
PTR rgbValue,
SDWORD cbValue)
/* Sets the value of a parameter node to the value given. If fCType is */
/* SQL_C_CHAR and the parameter is TYPE_CHAR (or if fCType is SQL_C_BINARY */
/* and the parameter is TYPE_BINARY), the parameter is written at offset */
/* (*pcbOffset) and (*pcbOffset) is incremented by the number of */
/* of characters written. */
{
SWORD err;
SDWORD cbOffset;
DATE_STRUCT FAR *lpDate;
TIME_STRUCT FAR *lpTime;
TIMESTAMP_STRUCT FAR *lpTimestamp;
static time_t t;
struct tm *ts;
UCHAR szValue[20];
LPUSTR lpszValue;
SDWORD cbVal;
LPUSTR lpszVal;
SDWORD i;
UCHAR nibble;
LPUSTR lpFrom;
LPUSTR lpTo;
/* Null data? */
err = SQL_SUCCESS;
if (cbValue == SQL_NULL_DATA) {
/* Yes. Set the value to NULL */
lpSqlNodeParameter->sqlIsNull = TRUE;
switch (lpSqlNodeParameter->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
lpSqlNodeParameter->value.Double = 0.0;
break;
case TYPE_NUMERIC:
lpSqlNodeParameter->value.String = ToString(
lpstmt->lpSqlStmt, lpSqlNodeParameter->node.parameter.Value);
s_lstrcpy(lpSqlNodeParameter->value.String, "");
break;
case TYPE_CHAR:
lpSqlNodeParameter->value.String = ToString(
lpstmt->lpSqlStmt, lpSqlNodeParameter->node.parameter.Value);
s_lstrcpy(lpSqlNodeParameter->value.String, "");
break;
case TYPE_DATE:
lpSqlNodeParameter->value.Date.year = 0;
lpSqlNodeParameter->value.Date.month = 0;
lpSqlNodeParameter->value.Date.day = 0;
break;
case TYPE_TIME:
lpSqlNodeParameter->value.Time.hour = 0;
lpSqlNodeParameter->value.Time.minute = 0;
lpSqlNodeParameter->value.Time.second = 0;
break;
case TYPE_TIMESTAMP:
lpSqlNodeParameter->value.Timestamp.year = 0;
lpSqlNodeParameter->value.Timestamp.month = 0;
lpSqlNodeParameter->value.Timestamp.day = 0;
lpSqlNodeParameter->value.Timestamp.hour = 0;
lpSqlNodeParameter->value.Timestamp.minute = 0;
lpSqlNodeParameter->value.Timestamp.second = 0;
lpSqlNodeParameter->value.Timestamp.fraction = 0;
break;
case TYPE_BINARY:
lpSqlNodeParameter->value.Binary = ToString(
lpstmt->lpSqlStmt, lpSqlNodeParameter->node.parameter.Value);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 0;
break;
default:
return ERR_NOTSUPPORTED;
}
}
else {
/* No. Set the value to not NULL */
lpSqlNodeParameter->sqlIsNull = FALSE;
/* Put the data value into the parse tree */
switch (lpSqlNodeParameter->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (fCType == SQL_C_BINARY) {
switch (lpSqlNodeParameter->sqlSqlType) {
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
return ERR_INTERNAL;
case SQL_BIT:
fCType = SQL_C_BIT;
break;
case SQL_TINYINT:
fCType = SQL_C_TINYINT;
break;
case SQL_SMALLINT:
fCType = SQL_C_SHORT;
break;
case SQL_INTEGER:
fCType = SQL_C_LONG;
break;
case SQL_REAL:
fCType = SQL_C_FLOAT;
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
return ERR_INTERNAL;
case SQL_FLOAT:
case SQL_DOUBLE:
fCType = SQL_C_DOUBLE;
break;
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
default:
return ERR_INTERNAL;
}
}
switch (fCType) {
case SQL_C_CHAR:
err = CharToDouble((LPUSTR)rgbValue, cbValue, FALSE, -1.7E308,
1.7E308, &(lpSqlNodeParameter->value.Double));
if (err != ERR_SUCCESS)
return err;
break;
case SQL_C_SSHORT:
lpSqlNodeParameter->value.Double = (double)
*((short far *) rgbValue);
break;
case SQL_C_USHORT:
lpSqlNodeParameter->value.Double = (double)
*((unsigned short far *) rgbValue);
break;
case SQL_C_SLONG:
lpSqlNodeParameter->value.Double = (double)
*((long far *) rgbValue);
break;
case SQL_C_ULONG:
lpSqlNodeParameter->value.Double = (double)
*((unsigned long far *) rgbValue);
break;
case SQL_C_FLOAT:
lpSqlNodeParameter->value.Double = (double)
*((float far *) rgbValue);
break;
case SQL_C_DOUBLE:
lpSqlNodeParameter->value.Double =
*((double far *) rgbValue);
break;
case SQL_C_BIT:
lpSqlNodeParameter->value.Double = (double)
*((unsigned char far *) rgbValue);
break;
case SQL_C_STINYINT:
lpSqlNodeParameter->value.Double = (double)
*((char far *) rgbValue);
break;
case SQL_C_UTINYINT:
lpSqlNodeParameter->value.Double = (double)
*((unsigned char far *) rgbValue);
break;
case SQL_C_DATE:
case SQL_C_TIME:
case SQL_C_TIMESTAMP:
return ERR_NOTCONVERTABLE;
case SQL_C_BINARY:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_NUMERIC:
if (fCType == SQL_C_BINARY) {
switch (lpSqlNodeParameter->sqlSqlType) {
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_BIT:
case SQL_TINYINT:
case SQL_SMALLINT:
case SQL_INTEGER:
case SQL_REAL:
return ERR_INTERNAL;
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
fCType = SQL_C_CHAR;
break;
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
default:
return ERR_INTERNAL;
}
}
lpSqlNodeParameter->value.String = ToString(
lpstmt->lpSqlStmt, lpSqlNodeParameter->node.parameter.Value);
switch (fCType) {
case SQL_C_CHAR:
/* Get true length of source string */
lpszValue = (LPUSTR) rgbValue;
if (cbValue == SQL_NTS)
cbValue = s_lstrlen(lpszValue);
else if (cbValue < 0)
cbValue = 0;
/* Make sure the number is well formed: Leading blanks... */
lpszVal = lpszValue;
cbVal = cbValue;
while ((cbVal > 0) && (*lpszVal == ' ')) {
lpszVal++;
cbVal--;
}
/* ...a minus sign... */
if ((cbVal > 0) && (*lpszVal == '-')) {
lpszVal++;
cbVal--;
}
/* ...some digits... */
while ((cbVal > 0) && (*lpszVal >= '0')&&(*lpszVal <= '9')) {
lpszVal++;
cbVal--;
}
/* ...a decimal point... */
if ((cbVal > 0) && (*lpszVal == '.')) {
lpszVal++;
cbVal--;
}
/* ...some more digits... */
while ((cbVal > 0) && (*lpszVal >= '0')&&(*lpszVal <= '9')) {
lpszVal++;
cbVal--;
}
/* ...some trailing blanks. */
while ((cbVal > 0) && (*lpszVal == ' ')) {
lpszVal++;
cbVal--;
}
/* If there is anything else, error */
if (cbVal != 0) {
if (cbValue <= MAX_TOKEN_SIZE) {
_fmemcpy(lpstmt->szError, lpszValue, (SWORD) cbValue);
lpstmt->szError[cbValue] = '\0';
}
else {
_fmemcpy(lpstmt->szError, lpszValue, MAX_TOKEN_SIZE);
lpstmt->szError[MAX_TOKEN_SIZE] = '\0';
}
return ERR_MALFORMEDNUMBER;
}
break;
case SQL_C_SSHORT:
wsprintf((LPSTR)szValue, "%d", *((short far *) rgbValue));
lpszValue = szValue;
cbValue = s_lstrlen((char*)szValue);
break;
case SQL_C_USHORT:
wsprintf((LPSTR)szValue, "%u", *((unsigned short far *) rgbValue));
lpszValue = szValue;
cbValue = s_lstrlen((char*)szValue);
break;
case SQL_C_SLONG:
wsprintf((LPSTR)szValue, "%ld", *((long far *) rgbValue));
lpszValue = szValue;
cbValue = lstrlen((char*)szValue);
break;
case SQL_C_ULONG:
wsprintf((LPSTR)szValue, "%lu", *((unsigned long far *) rgbValue));
lpszValue = szValue;
cbValue = s_lstrlen((char*)szValue);
break;
case SQL_C_FLOAT:
if (DoubleToChar((double) *((float far *) rgbValue),
FALSE,
lpSqlNodeParameter->value.String,
lpSqlNodeParameter->sqlPrecision + 2 + 1))
lpSqlNodeParameter->value.String[
lpSqlNodeParameter->sqlPrecision + 2 + 1 - 1] = '\0';
lpszValue = lpSqlNodeParameter->value.String;
cbValue = s_lstrlen(lpSqlNodeParameter->value.String);
break;
case SQL_C_DOUBLE:
if (DoubleToChar(*((double far *) rgbValue),
FALSE,
lpSqlNodeParameter->value.String,
lpSqlNodeParameter->sqlPrecision + 2 + 1))
lpSqlNodeParameter->value.String[
lpSqlNodeParameter->sqlPrecision + 2 + 1 - 1] = '\0';
lpszValue = lpSqlNodeParameter->value.String;
cbValue = s_lstrlen(lpSqlNodeParameter->value.String);
break;
case SQL_C_BIT:
wsprintf((LPSTR)szValue, "%d", (short)
*((unsigned char far *) rgbValue));
lpszValue = szValue;
cbValue = s_lstrlen((char*)szValue);
break;
case SQL_C_STINYINT:
wsprintf((LPSTR)szValue, "%d", (short)
*((char far *) rgbValue));
lpszValue = szValue;
cbValue = s_lstrlen((char*)szValue);
break;
case SQL_C_UTINYINT:
wsprintf((LPSTR)szValue, "%d", (short)
*((unsigned char far *) rgbValue));
lpszValue = szValue;
cbValue = s_lstrlen((char*)szValue);
break;
case SQL_C_DATE:
case SQL_C_TIME:
case SQL_C_TIMESTAMP:
return ERR_NOTCONVERTABLE;
break;
case SQL_C_BINARY:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
/* Normalize the result */
err = BCDNormalize(lpszValue, cbValue,
lpSqlNodeParameter->value.String,
lpSqlNodeParameter->sqlPrecision + 2 + 1,
lpSqlNodeParameter->sqlPrecision,
lpSqlNodeParameter->sqlScale);
break;
case TYPE_CHAR:
lpSqlNodeParameter->value.String = ToString(
lpstmt->lpSqlStmt, lpSqlNodeParameter->node.parameter.Value);
switch (fCType) {
case SQL_C_CHAR:
/* Get true lengthof source string */
if (cbValue == SQL_NTS)
cbValue = s_lstrlen((char*)rgbValue);
else if (cbValue < 0)
cbValue = 0;
/* Figure out the offset to write at */
if (pcbOffset != NULL)
cbOffset = *pcbOffset;
else
cbOffset = 0;
/* Make sure we don't write past the end of the buffer */
if (cbValue > (MAX_CHAR_LITERAL_LENGTH - cbOffset)) {
cbValue = MAX_CHAR_LITERAL_LENGTH - cbOffset;
err = ERR_DATATRUNCATED;
}
/* Copy the data */
_fmemcpy(lpSqlNodeParameter->value.String + cbOffset,
rgbValue, (SWORD) cbValue);
lpSqlNodeParameter->value.String[cbValue + cbOffset] = '\0';
if (pcbOffset != NULL)
*pcbOffset += (cbValue);
break;
case SQL_C_SSHORT:
wsprintf((LPSTR) lpSqlNodeParameter->value.String, "%d",
*((short far *) rgbValue));
break;
case SQL_C_USHORT:
wsprintf((LPSTR) lpSqlNodeParameter->value.String, "%u",
*((unsigned short far *) rgbValue));
break;
case SQL_C_SLONG:
wsprintf((LPSTR) lpSqlNodeParameter->value.String, "%ld",
*((long far *) rgbValue));
break;
case SQL_C_ULONG:
wsprintf((LPSTR) lpSqlNodeParameter->value.String, "%lu",
*((unsigned long far *) rgbValue));
break;
case SQL_C_FLOAT:
if (DoubleToChar((double) *((float far *) rgbValue), TRUE,
lpSqlNodeParameter->value.String,
MAX_CHAR_LITERAL_LENGTH))
lpSqlNodeParameter->value.String[
MAX_CHAR_LITERAL_LENGTH - 1] = '\0';
break;
case SQL_C_DOUBLE:
if (DoubleToChar(*((double far *) rgbValue), TRUE,
lpSqlNodeParameter->value.String,
MAX_CHAR_LITERAL_LENGTH))
lpSqlNodeParameter->value.String[
MAX_CHAR_LITERAL_LENGTH - 1] = '\0';
break;
case SQL_C_BIT:
wsprintf((LPSTR) lpSqlNodeParameter->value.String, "%d", (short)
*((unsigned char far *) rgbValue));
break;
case SQL_C_STINYINT:
wsprintf((LPSTR) lpSqlNodeParameter->value.String, "%d", (short)
*((char far *) rgbValue));
break;
case SQL_C_UTINYINT:
wsprintf((LPSTR) lpSqlNodeParameter->value.String, "%d", (short)
*((unsigned char far *) rgbValue));
break;
case SQL_C_DATE:
DateToChar((DATE_STRUCT far *) rgbValue,
lpSqlNodeParameter->value.String);
break;
case SQL_C_TIME:
TimeToChar((TIME_STRUCT far *) rgbValue,
lpSqlNodeParameter->value.String);
break;
case SQL_C_TIMESTAMP:
TimestampToChar((TIMESTAMP_STRUCT far *) rgbValue,
lpSqlNodeParameter->value.String);
break;
case SQL_C_BINARY:
/* Get true lengthof source string */
if (cbValue < 0)
cbValue = 0;
/* Figure out the offset to write at */
if (pcbOffset != NULL)
cbOffset = *pcbOffset;
else
cbOffset = 0;
/* Make sure we don't write past the end of the buffer */
if (cbValue > (MAX_CHAR_LITERAL_LENGTH - cbOffset)) {
cbValue = MAX_CHAR_LITERAL_LENGTH - cbOffset;
err = ERR_DATATRUNCATED;
}
/* Copy the data */
_fmemcpy(lpSqlNodeParameter->value.String + cbOffset,
rgbValue, (SWORD) cbValue);
lpSqlNodeParameter->value.String[cbValue + cbOffset] = '\0';
if (pcbOffset != NULL)
*pcbOffset += (cbValue);
break;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_DATE:
switch (fCType) {
case SQL_C_CHAR:
err = CharToDate((LPUSTR)rgbValue, cbValue,
&(lpSqlNodeParameter->value.Date));
if (err != ERR_SUCCESS)
return err;
break;
case SQL_C_SSHORT:
case SQL_C_USHORT:
case SQL_C_SLONG:
case SQL_C_ULONG:
case SQL_C_FLOAT:
case SQL_C_DOUBLE:
case SQL_C_BIT:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
return ERR_NOTCONVERTABLE;
case SQL_C_DATE:
lpSqlNodeParameter->value.Date =
*((DATE_STRUCT far *) rgbValue);
break;
case SQL_C_TIME:
return ERR_NOTCONVERTABLE;
case SQL_C_TIMESTAMP:
lpTimestamp = (TIMESTAMP_STRUCT far *) rgbValue;
lpSqlNodeParameter->value.Date.year = lpTimestamp->year;
lpSqlNodeParameter->value.Date.month = lpTimestamp->month;
lpSqlNodeParameter->value.Date.day = lpTimestamp->day;
break;
case SQL_C_BINARY:
lpSqlNodeParameter->value.Date =
*((DATE_STRUCT far *) rgbValue);
break;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_TIME:
switch (fCType) {
case SQL_C_CHAR:
err = CharToTime((LPUSTR)rgbValue, cbValue,
&(lpSqlNodeParameter->value.Time));
if (err != ERR_SUCCESS)
return err;
break;
case SQL_C_SSHORT:
case SQL_C_USHORT:
case SQL_C_SLONG:
case SQL_C_ULONG:
case SQL_C_FLOAT:
case SQL_C_DOUBLE:
case SQL_C_BIT:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
return ERR_NOTCONVERTABLE;
case SQL_C_DATE:
return ERR_NOTCONVERTABLE;
case SQL_C_TIME:
lpSqlNodeParameter->value.Time =
*((TIME_STRUCT far *) rgbValue);
break;
case SQL_C_TIMESTAMP:
lpTimestamp = (TIMESTAMP_STRUCT far *) rgbValue;
lpSqlNodeParameter->value.Time.hour = lpTimestamp->hour;
lpSqlNodeParameter->value.Time.minute = lpTimestamp->minute;
lpSqlNodeParameter->value.Time.second = lpTimestamp->second;
break;
case SQL_C_BINARY:
lpSqlNodeParameter->value.Time =
*((TIME_STRUCT far *) rgbValue);
break;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_TIMESTAMP:
switch (fCType) {
case SQL_C_CHAR:
err = CharToTimestamp((LPUSTR)rgbValue, cbValue,
&(lpSqlNodeParameter->value.Timestamp));
if (err != ERR_SUCCESS)
return err;
break;
case SQL_C_SSHORT:
case SQL_C_USHORT:
case SQL_C_SLONG:
case SQL_C_ULONG:
case SQL_C_FLOAT:
case SQL_C_DOUBLE:
case SQL_C_BIT:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
return ERR_NOTCONVERTABLE;
case SQL_C_DATE:
lpDate = (DATE_STRUCT far *) rgbValue;
lpSqlNodeParameter->value.Timestamp.year = lpDate->year;
lpSqlNodeParameter->value.Timestamp.month = lpDate-> month;
lpSqlNodeParameter->value.Timestamp.day = lpDate-> day;
lpSqlNodeParameter->value.Timestamp.hour = 0;
lpSqlNodeParameter->value.Timestamp.minute = 0;
lpSqlNodeParameter->value.Timestamp.second = 0;
lpSqlNodeParameter->value.Timestamp.fraction = 0;
break;
case SQL_C_TIME:
lpTime = (TIME_STRUCT far *) rgbValue;
time(&t);
ts = localtime(&t);
lpSqlNodeParameter->value.Timestamp.year = ts->tm_year + 1900;
lpSqlNodeParameter->value.Timestamp.month = ts->tm_mon + 1;
lpSqlNodeParameter->value.Timestamp.day = (UWORD) ts->tm_mday;
lpSqlNodeParameter->value.Timestamp.hour = (WORD) lpTime->hour;
lpSqlNodeParameter->value.Timestamp.minute = lpTime->minute;
lpSqlNodeParameter->value.Timestamp.second = lpTime->second;
lpSqlNodeParameter->value.Timestamp.fraction = 0;
break;
case SQL_C_TIMESTAMP:
lpSqlNodeParameter->value.Timestamp =
*((TIMESTAMP_STRUCT far *) rgbValue);
break;
case SQL_C_BINARY:
lpSqlNodeParameter->value.Timestamp =
*((TIMESTAMP_STRUCT far *) rgbValue);
break;
default:
return ERR_NOTSUPPORTED;
}
break;
case TYPE_BINARY:
lpSqlNodeParameter->value.Binary = ToString(
lpstmt->lpSqlStmt, lpSqlNodeParameter->node.parameter.Value);
switch (fCType) {
case SQL_C_CHAR:
/* Get true length of source string */
if (cbValue == SQL_NTS)
cbValue = s_lstrlen((char*)rgbValue);
else if (cbValue < 0)
cbValue = 0;
/* If am odd numbe of characters, discard the last one */
if (((cbValue/2) * 2) != cbValue)
cbValue--;
/* Figure out the offset to write at */
if (pcbOffset != NULL)
cbOffset = *pcbOffset;
else
cbOffset = 0;
/* Make sure we don't write past the end of the buffer */
if (cbValue > ((MAX_BINARY_LITERAL_LENGTH - cbOffset) * 2)) {
cbValue = (MAX_BINARY_LITERAL_LENGTH - cbOffset) * 2;
err = ERR_DATATRUNCATED;
}
/* Copy the data */
lpFrom = (LPUSTR) rgbValue;
lpTo = BINARY_DATA(lpSqlNodeParameter->value.Binary) +
cbOffset;
for (i=0; i < cbValue; i++) {
/* Convert the next character to a binary digit */
if ((*lpFrom >= '0') && (*lpFrom <= '9'))
nibble = *lpFrom - '0';
else if ((*lpFrom >= 'A') && (*lpFrom <= 'F'))
nibble = *lpFrom - 'A';
else if ((*lpFrom >= 'a') && (*lpFrom <= 'f'))
nibble = *lpFrom - 'a';
else
return ERR_NOTCONVERTABLE;
/* Are we writing the left or right side of the byte? */
if (((i/2) * 2) != i) {
/* The left side. Shift the nibble over */
*lpTo = nibble << 4;
}
else {
/* The right side. Add the nibble in */
*lpTo |= (nibble);
/* Point at next binary byte */
lpTo++;
}
/* Look at next character */
lpFrom++;
}
/* Set the new length */
if (cbOffset == 0)
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) =
cbValue/2;
else
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) =
(cbValue/2)+
BINARY_LENGTH(lpSqlNodeParameter->value.Binary);
/* Return new offset */
if (pcbOffset != NULL)
*pcbOffset += (cbValue/2);
break;
case SQL_C_SSHORT:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 2);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 2;
break;
case SQL_C_USHORT:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 2);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 2;
break;
case SQL_C_SLONG:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 4);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 4;
break;
case SQL_C_ULONG:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 4);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 4;
break;
case SQL_C_FLOAT:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 4);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 4;
break;
case SQL_C_DOUBLE:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 8);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 8;
break;
case SQL_C_BIT:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 1);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 1;
break;
case SQL_C_STINYINT:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 1);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 1;
break;
case SQL_C_UTINYINT:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 1);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 1;
break;
case SQL_C_DATE:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 6);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 6;
break;
case SQL_C_TIME:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 6);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 6;
break;
case SQL_C_TIMESTAMP:
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary),
rgbValue, 16);
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = 16;
break;
case SQL_C_BINARY:
/* Get true lengthof source string */
if (cbValue < 0)
cbValue = 0;
/* Figure out the offset to write at */
if (pcbOffset != NULL)
cbOffset = *pcbOffset;
else
cbOffset = 0;
/* Make sure we don't write past the end of the buffer */
if (cbValue > (MAX_BINARY_LITERAL_LENGTH - cbOffset)) {
cbValue = MAX_BINARY_LITERAL_LENGTH - cbOffset;
err = ERR_DATATRUNCATED;
}
/* Copy the data */
_fmemcpy(BINARY_DATA(lpSqlNodeParameter->value.Binary) +
cbOffset, rgbValue, (SWORD) cbValue);
if (cbOffset == 0)
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = cbValue;
else
BINARY_LENGTH(lpSqlNodeParameter->value.Binary) = cbValue+
BINARY_LENGTH(lpSqlNodeParameter->value.Binary);
if (pcbOffset != NULL)
*pcbOffset += (cbValue);
break;
default:
return ERR_NOTSUPPORTED;
}
break;
default:
return ERR_NOTSUPPORTED;
}
}
return err;
}
/***************************************************************************/
RETCODE INTFUNC Rewind(LPSTMT lpstmt, LPSQLNODE lpSqlNode,
BOOL fOuterJoinIsNull)
/* Rewinds the table or table list identified by lpSqlNode */
{
#define MAX_RESTRICTIONS 10
LPSQLTREE lpSql;
SWORD err;
LPSQLNODE lpSqlNodeComparison;
LPSQLNODE lpSqlNodeColumn;
LPSQLNODE lpSqlNodeValue;
LPSQLNODE lpSqlNodeTable;
LPSQLNODE lpSqlNodeTables;
SQLNODEIDX idxRestrict;
UWORD cRestrict;
UWORD fOperator[MAX_RESTRICTIONS];
SWORD fCType[MAX_RESTRICTIONS];
PTR rgbValue[MAX_RESTRICTIONS];
SDWORD cbValue[MAX_RESTRICTIONS];
UWORD icol[MAX_RESTRICTIONS];
lpSql = lpstmt->lpSqlStmt;
switch (lpSqlNode->sqlNodeType) {
case NODE_TYPE_TABLES:
/* Rewind this table */
lpSqlNodeTable = ToNode(lpSql, lpSqlNode->node.tables.Table);
err = Rewind(lpstmt, lpSqlNodeTable, fOuterJoinIsNull);
if (err != ERR_SUCCESS)
return err;
/* Are there other tables on the list? */
if (lpSqlNode->node.tables.Next != NO_SQLNODE) {
/* Yes. Find next record */
while (TRUE) {
/* Is this the right side of a NULL outer join? */
if ((lpSqlNodeTable->node.table.OuterJoinPredicate !=
NO_SQLNODE) && fOuterJoinIsNull)
/* Yes. This table has NULLs also */
err = ISAM_EOF;
else {
/* No. Position the current table to the next record */
err = ISAMNextRecord(lpSqlNodeTable->node.table.Handle, lpstmt);
if ((err == NO_ISAM_ERR) || (err == ISAM_EOF))
lpstmt->fISAMTxnStarted = TRUE;
}
/* End of file? */
if (err == ISAM_EOF) {
/* Yes. Is this table the right side of an outer join */
if (lpSqlNodeTable->node.table.OuterJoinPredicate ==
NO_SQLNODE) {
/* No. No more records */
return ERR_NODATAFOUND;
}
else {
/* Yes. Use a record of all nulls */
err = ERR_SUCCESS;
lpSqlNodeTable->node.table.AllNull = TRUE;
fOuterJoinIsNull = TRUE;
}
}
else if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
/* Rewind the other tables */
lpSqlNodeTables = ToNode(lpSql, lpSqlNode->node.tables.Next);
err = Rewind(lpstmt, lpSqlNodeTables, fOuterJoinIsNull);
if (err == ERR_SUCCESS)
break;
if (err != ERR_NODATAFOUND)
return err;
}
}
break;
case NODE_TYPE_TABLE:
/* Did the optimizer find any restrictions? */
if (lpSqlNode->node.table.Restrict != 0) {
/* Yes. For each restriction found... */
cRestrict = 0;
idxRestrict = lpSqlNode->node.table.Restrict;
while (idxRestrict != NO_SQLNODE) {
/* Get the restriction */
lpSqlNodeComparison = ToNode(lpSql, idxRestrict);
/* Get the column */
lpSqlNodeColumn = ToNode(lpSql, lpSqlNodeComparison->node.comparison.Left);
icol[cRestrict] = lpSqlNodeColumn->node.column.Id;
/* Get the operator */
switch (lpSqlNodeComparison->node.comparison.Operator) {
case OP_EQ:
fOperator[cRestrict] = ISAM_OP_EQ;
break;
case OP_NE:
fOperator[cRestrict] = ISAM_OP_NE;
break;
case OP_LE:
fOperator[cRestrict] = ISAM_OP_LE;
break;
case OP_LT:
fOperator[cRestrict] = ISAM_OP_LT;
break;
case OP_GE:
fOperator[cRestrict] = ISAM_OP_GE;
break;
case OP_GT:
fOperator[cRestrict] = ISAM_OP_GT;
break;
default:
return ERR_INTERNAL;
}
/* Calculate the key value */
lpSqlNodeValue = ToNode(lpSql,
lpSqlNodeComparison->node.comparison.Right);
err = EvaluateExpression(lpstmt, lpSqlNodeValue);
if (err != ERR_SUCCESS)
return err;
/* Put restriction on the list */
switch (lpSqlNodeValue->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
fCType[cRestrict] = SQL_C_DOUBLE;
rgbValue[cRestrict] = &(lpSqlNodeValue->value.Double);
cbValue[cRestrict] = lpSqlNodeValue->sqlIsNull ?
SQL_NULL_DATA : sizeof(double);
break;
case TYPE_NUMERIC:
fCType[cRestrict] = SQL_C_CHAR;
rgbValue[cRestrict] = lpSqlNodeValue->value.String;
cbValue[cRestrict] = lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
s_lstrlen(lpSqlNodeValue->value.String);
break;
case TYPE_CHAR:
fCType[cRestrict] = SQL_C_CHAR;
rgbValue[cRestrict] = lpSqlNodeValue->value.String;
cbValue[cRestrict] = lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
s_lstrlen(lpSqlNodeValue->value.String);
break;
case TYPE_DATE:
fCType[cRestrict] = SQL_C_DATE;
rgbValue[cRestrict] = &(lpSqlNodeValue->value.Date),
cbValue[cRestrict] = lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(DATE_STRUCT);
break;
case TYPE_TIME:
fCType[cRestrict] = SQL_C_TIME;
rgbValue[cRestrict] = &(lpSqlNodeValue->value.Time);
cbValue[cRestrict] = lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(TIME_STRUCT);
break;
case TYPE_TIMESTAMP:
fCType[cRestrict] = SQL_C_TIMESTAMP;
rgbValue[cRestrict] = &(lpSqlNodeValue->value.Timestamp);
cbValue[cRestrict] = lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(TIMESTAMP_STRUCT);
break;
case TYPE_BINARY:
fCType[cRestrict] = SQL_C_BINARY;
rgbValue[cRestrict] = BINARY_DATA(lpSqlNodeValue->value.Binary);
cbValue[cRestrict] = lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
BINARY_LENGTH(lpSqlNodeValue->value.Binary);
break;
default:
return ERR_NOTSUPPORTED;
}
/* Increase count */
cRestrict++;
/* Leave loop if maximum number of restrictions found */
if (cRestrict >= MAX_RESTRICTIONS)
break;
/* Point at next restriction */
idxRestrict = lpSqlNodeComparison->node.comparison.NextRestrict;
}
/* Apply the restriction */
err = ISAMRestrict(lpSqlNode->node.table.Handle, cRestrict,
icol, fOperator, fCType, rgbValue, cbValue);
if ((err != NO_ISAM_ERR) && (err != ISAM_NOTSUPPORTED)) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
else if (err == NO_ISAM_ERR)
lpstmt->fISAMTxnStarted = TRUE;
}
/* Rewind the table */
err = ISAMRewind(lpSqlNode->node.table.Handle);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
lpSqlNode->node.table.Rewound = TRUE;
lpSqlNode->node.table.AllNull = FALSE;
break;
default:
return ERR_INTERNAL;
}
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC NextRawRecord (LPSTMT lpstmt,
LPSQLNODE lpSqlNode)
/* Finds the next record in in the table or table list. */
/* */
/* If a list of tables is given, the leftmost table spins the slowest */
/* and the rightmost table spins the fastest. In otherwords, for each */
/* row in a table, we iterate over the rows in the tables after that table */
{
LPSQLTREE lpSql;
SWORD err;
LPSQLNODE lpSqlNodeTable;
LPSQLNODE lpSqlNodeTables;
LPSQLNODE lpSqlNodeOuterJoinPredicate;
lpSql = lpstmt->lpSqlStmt;
switch (lpSqlNode->sqlNodeType) {
case NODE_TYPE_TABLES:
/* Are there any more tables on the list? */
lpSqlNodeTable = ToNode(lpSql, lpSqlNode->node.tables.Table);
if (lpSqlNode->node.tables.Next != NO_SQLNODE) {
/* Yes. Look for next record in the rest of the list */
while (TRUE) {
/* Move to the next record on rest of the table list */
lpSqlNodeTables = ToNode(lpSql, lpSqlNode->node.tables.Next);
err = NextRawRecord(lpstmt, lpSqlNodeTables);
if ((err != ERR_SUCCESS) && (err != ERR_NODATAFOUND))
return err;
/* If a no more records, continue below */
if (err == ERR_NODATAFOUND)
break;
/* Is this table on right side of an outer join? */
if (lpSqlNodeTable->node.table.OuterJoinPredicate !=
NO_SQLNODE) {
/* Yes. Are we on the row of NULLs? */
if (!lpSqlNodeTable->node.table.AllNull) {
/* No. Test ON predicate */
lpSqlNodeOuterJoinPredicate = ToNode(lpSql,
lpSqlNodeTable->node.table.OuterJoinPredicate);
/* Test outer join criteria */
err = EvaluateExpression(lpstmt,
lpSqlNodeOuterJoinPredicate);
if (err != ERR_SUCCESS)
return err;
/* If record does not pass outer join criteria, */
/* try next one */
if ((lpSqlNodeOuterJoinPredicate->sqlIsNull) ||
(lpSqlNodeOuterJoinPredicate->value.Double !=
TRUE)) {
continue;
}
/* If record passes outer join criteria, use it */
else {
lpSqlNodeTable->node.table.Rewound = FALSE;
}
}
}
break;
}
/* If a record was found, return it */
if (err == ERR_SUCCESS)
break;
}
/* Loop until a record is found */
while (TRUE) {
/* Position to the next record in this table. */
err = NextRawRecord(lpstmt, lpSqlNodeTable);
if (err != ERR_SUCCESS)
return err;
/* More tables on the list? */
if (lpSqlNode->node.tables.Next != NO_SQLNODE) {
/* Yes. Rewind the other tables on the list */
lpSqlNodeTables = ToNode(lpSql, lpSqlNode->node.tables.Next);
err = Rewind(lpstmt, lpSqlNodeTables,
lpSqlNodeTable->node.table.AllNull);
if (err == ERR_NODATAFOUND)
continue;
if (err != ERR_SUCCESS)
return err;
/* Get the first record from the other tables on the list */
err = NextRawRecord(lpstmt, lpSqlNodeTables);
if (err == ERR_NODATAFOUND)
continue;
if (err != ERR_SUCCESS)
return err;
}
/* Is this table on right side of an outer join? */
if (lpSqlNodeTable->node.table.OuterJoinPredicate !=
NO_SQLNODE) {
/* Yes. Are we on the row of NULLs? */
if (!lpSqlNodeTable->node.table.AllNull) {
/* No. Test ON predicate */
lpSqlNodeOuterJoinPredicate = ToNode(lpSql,
lpSqlNodeTable->node.table.OuterJoinPredicate);
/* Test outer join criteria */
err = EvaluateExpression(lpstmt,
lpSqlNodeOuterJoinPredicate);
if (err != ERR_SUCCESS)
return err;
/* If record does not pass outer join criteria, */
/* try next one */
if ((lpSqlNodeOuterJoinPredicate->sqlIsNull) ||
(lpSqlNodeOuterJoinPredicate->value.Double != TRUE)) {
continue;
}
/* If record passes outer join criteria, use it */
else {
lpSqlNodeTable->node.table.Rewound = FALSE;
}
}
}
break;
}
break;
case NODE_TYPE_TABLE:
/* If currently on a record of all NULLs, error */
if ((lpSqlNode->node.table.OuterJoinPredicate != NO_SQLNODE) &&
lpSqlNode->node.table.AllNull)
return ERR_NODATAFOUND;
/* Are we already on a record of all nulls? */
if (lpSqlNode->node.table.AllNull)
/* Yes. Stay there */
err = ISAM_EOF;
else {
/* No. Get the next record from the ISAM */
err = ISAMNextRecord(lpSqlNode->node.table.Handle, lpstmt);
if ((err == NO_ISAM_ERR) || (err == ISAM_EOF))
lpstmt->fISAMTxnStarted = TRUE;
}
if (err == ISAM_EOF) {
/* End of table. If not an outer join, error */
if (lpSqlNode->node.table.OuterJoinPredicate == NO_SQLNODE)
return ERR_NODATAFOUND;
/* If this is not first read, error */
if (!(lpSqlNode->node.table.Rewound))
return ERR_NODATAFOUND;
/* Otherwise, use a record of all NULLs */
lpSqlNode->node.table.AllNull = TRUE;
}
else if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
return err;
}
break;
default:
return ERR_INTERNAL;
}
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC NextRecord (LPSTMT lpstmt,
LPSQLNODE lpSqlNode,
LPSQLNODE lpSqlNodePredicate)
/* Finds the next record in in the table or table list identified by */
/* lpSqlNode that satisfies the predicate lpSqlNodePredicte. */
/* */
/* If a list of tables is given, the leftmost table spins the slowest */
/* and the rightmost table spins the fastest. In otherwords, for each */
/* row in a table, we iterate over the rows in the tables after that table */
{
SWORD err;
/* Loop until a record is found */
while (TRUE) {
/* Go to next record */
err = NextRawRecord(lpstmt, lpSqlNode);
if (err != ERR_SUCCESS)
return err;
/* If no predicate, this record qualifies. */
if (lpSqlNodePredicate == NULL)
break;
/* If the predicate is TRUE, return this record */
err = EvaluateExpression(lpstmt, lpSqlNodePredicate);
if (err != ERR_SUCCESS)
return err;
if (!(lpSqlNodePredicate->sqlIsNull) &&
(lpSqlNodePredicate->value.Double == TRUE))
break;
}
return ERR_SUCCESS;
}
/***************************************************************************/
int INTFUNC lstrcmp_pad(LPUSTR lpszLeft, LPUSTR lpszRight)
/* Compares two string (blank padding the shorter one to the same length */
/* as the longer one). */
{
int cbLeft;
int cbRight;
UCHAR chr;
int result;
/* Get the length of the two strings */
cbLeft = s_lstrlen(lpszLeft);
cbRight = s_lstrlen(lpszRight);
/* If the strings are the same length, use plain old lstrcmp */
if (cbLeft == cbRight)
result = s_lstrcmp(lpszLeft, lpszRight);
/* If the left one is shorter, swap the strings and try again */
else if (cbLeft < cbRight)
result = -(lstrcmp_pad(lpszRight, lpszLeft));
/* Otherwise the right one is shorter... */
else {
/* Truncate the left one to the size of the right one */
chr = lpszLeft[cbRight];
lpszLeft[cbRight] = '\0';
/* Are the strings equal? */
result = s_lstrcmp(lpszLeft, lpszRight);
lpszLeft[cbRight] = chr; /* Untruncate the left one */
if (result == 0) {
/* Yes. Compare remaining characters on the left string to blanks */
while (cbRight < cbLeft) {
result = lpszLeft[cbRight] - ' ';
if (result != 0)
break;
cbRight++;
}
}
}
return result;
}
RETCODE INTFUNC ValueCompare(LPSQLNODE lpSqlNode, LPSQLNODE lpSqlNodeLeft,
UWORD Operator, LPSQLNODE lpSqlNodeRight)
/* Compares two values */
{
RETCODE err;
LONG idx;
/* Compare values */
err = ERR_SUCCESS;
lpSqlNode->sqlIsNull = FALSE;
switch (lpSqlNodeLeft->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
case TYPE_NUMERIC:
err = NumericCompare(lpSqlNode, lpSqlNodeLeft, Operator,
lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
break;
case TYPE_CHAR:
switch (Operator) {
case OP_EQ:
if (lstrcmp_pad(lpSqlNodeLeft->value.String,
lpSqlNodeRight->value.String) == 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_NE:
if (lstrcmp_pad(lpSqlNodeLeft->value.String,
lpSqlNodeRight->value.String) != 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LE:
if (lstrcmp_pad(lpSqlNodeLeft->value.String,
lpSqlNodeRight->value.String) <= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LT:
if (lstrcmp_pad(lpSqlNodeLeft->value.String,
lpSqlNodeRight->value.String) < 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GE:
if (lstrcmp_pad(lpSqlNodeLeft->value.String,
lpSqlNodeRight->value.String) >= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GT:
if (lstrcmp_pad(lpSqlNodeLeft->value.String,
lpSqlNodeRight->value.String) > 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LIKE:
lpSqlNode->value.Double =
PatternMatch(FALSE, lpSqlNodeLeft->value.String,
s_lstrlen(lpSqlNodeLeft->value.String),
lpSqlNodeRight->value.String,
s_lstrlen(lpSqlNodeRight->value.String),
TRUE);
break;
case OP_NOTLIKE:
lpSqlNode->value.Double =
!(PatternMatch(FALSE, lpSqlNodeLeft->value.String,
s_lstrlen(lpSqlNodeLeft->value.String),
lpSqlNodeRight->value.String,
s_lstrlen(lpSqlNodeRight->value.String),
TRUE));
break;
default:
err = ERR_INTERNAL;
break;
}
break;
case TYPE_BINARY:
switch (Operator) {
case OP_EQ:
if (BINARY_LENGTH(lpSqlNodeLeft->value.Binary) ==
BINARY_LENGTH(lpSqlNodeRight->value.Binary)) {
lpSqlNode->value.Double = TRUE;
for (idx = 0;
idx < BINARY_LENGTH(lpSqlNodeRight->value.Binary);
idx++) {
if (BINARY_DATA(lpSqlNodeLeft->value.Binary)[idx] !=
BINARY_DATA(lpSqlNodeRight->value.Binary)[idx]) {
lpSqlNode->value.Double = FALSE;
break;
}
}
}
else
lpSqlNode->value.Double = FALSE;
break;
case OP_NE:
if (BINARY_LENGTH(lpSqlNodeLeft->value.Binary) ==
BINARY_LENGTH(lpSqlNodeRight->value.Binary)) {
lpSqlNode->value.Double = FALSE;
for (idx = 0;
idx < BINARY_LENGTH(lpSqlNodeRight->value.Binary);
idx++) {
if (BINARY_DATA(lpSqlNodeLeft->value.Binary)[idx] !=
BINARY_DATA(lpSqlNodeRight->value.Binary)[idx]) {
lpSqlNode->value.Double = TRUE;
break;
}
}
}
else
lpSqlNode->value.Double = TRUE;
break;
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_LIKE:
case OP_NOTLIKE:
default:
err = ERR_INTERNAL;
break;
}
break;
case TYPE_DATE:
switch (Operator) {
case OP_EQ:
if (DateCompare(lpSqlNodeLeft->value.Date,
lpSqlNodeRight->value.Date) == 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_NE:
if (DateCompare(lpSqlNodeLeft->value.Date,
lpSqlNodeRight->value.Date) != 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LE:
if (DateCompare(lpSqlNodeLeft->value.Date,
lpSqlNodeRight->value.Date) <= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LT:
if (DateCompare(lpSqlNodeLeft->value.Date,
lpSqlNodeRight->value.Date) < 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GE:
if (DateCompare(lpSqlNodeLeft->value.Date,
lpSqlNodeRight->value.Date) >= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GT:
if (DateCompare(lpSqlNodeLeft->value.Date,
lpSqlNodeRight->value.Date) > 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LIKE:
case OP_NOTLIKE:
default:
err = ERR_INTERNAL;
break;
}
break;
case TYPE_TIME:
switch (Operator) {
case OP_EQ:
if (TimeCompare(lpSqlNodeLeft->value.Time,
lpSqlNodeRight->value.Time) == 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_NE:
if (TimeCompare(lpSqlNodeLeft->value.Time,
lpSqlNodeRight->value.Time) != 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LE:
if (TimeCompare(lpSqlNodeLeft->value.Time,
lpSqlNodeRight->value.Time) <= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LT:
if (TimeCompare(lpSqlNodeLeft->value.Time,
lpSqlNodeRight->value.Time) < 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GE:
if (TimeCompare(lpSqlNodeLeft->value.Time,
lpSqlNodeRight->value.Time) >= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GT:
if (TimeCompare(lpSqlNodeLeft->value.Time,
lpSqlNodeRight->value.Time) > 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LIKE:
case OP_NOTLIKE:
default:
err = ERR_INTERNAL;
break;
}
break;
case TYPE_TIMESTAMP:
switch (Operator) {
case OP_EQ:
if (TimestampCompare(lpSqlNodeLeft->value.Timestamp,
lpSqlNodeRight->value.Timestamp) == 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_NE:
if (TimestampCompare(lpSqlNodeLeft->value.Timestamp,
lpSqlNodeRight->value.Timestamp) != 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LE:
if (TimestampCompare(lpSqlNodeLeft->value.Timestamp,
lpSqlNodeRight->value.Timestamp) <= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LT:
if (TimestampCompare(lpSqlNodeLeft->value.Timestamp,
lpSqlNodeRight->value.Timestamp) < 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GE:
if (TimestampCompare(lpSqlNodeLeft->value.Timestamp,
lpSqlNodeRight->value.Timestamp) >= 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_GT:
if (TimestampCompare(lpSqlNodeLeft->value.Timestamp,
lpSqlNodeRight->value.Timestamp) > 0)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
case OP_LIKE:
case OP_NOTLIKE:
default:
err = ERR_INTERNAL;
break;
}
break;
default:
err = ERR_NOTSUPPORTED;
break;
}
return err;
}
/***************************************************************************/
RETCODE INTFUNC RetrieveSortRecordValue(LPSQLNODE lpSqlNodeStmt, LPSQLNODE lpSqlNode,
UDWORD Offset, UDWORD Length)
/* Retrieves a value from a sort record */
{
UCHAR cNullFlag;
UCHAR szBuffer[30];
UWORD len;
UDWORD SortRecordsize;
szBuffer[0] = 0;
/* Position to the value */
if (lpSqlNodeStmt->sqlNodeType != NODE_TYPE_SELECT)
return ERR_INTERNAL;
if (!(lpSqlNodeStmt->node.select.ReturningDistinct))
SortRecordsize = lpSqlNodeStmt->node.select.SortRecordsize;
else
SortRecordsize = lpSqlNodeStmt->node.select.DistinctRecordsize;
if (_llseek(lpSqlNodeStmt->node.select.Sortfile,
(lpSqlNodeStmt->node.select.CurrentRow * SortRecordsize)
+ Offset - 1, 0) == HFILE_ERROR)
return ERR_SORT;
/* Read value */
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (_lread(lpSqlNodeStmt->node.select.Sortfile,
&(lpSqlNode->value.Double),
sizeof(double)) != sizeof(double))
return ERR_SORT;
break;
case TYPE_NUMERIC:
if (_lread(lpSqlNodeStmt->node.select.Sortfile,
lpSqlNode->value.String,
(UINT) Length) != (UINT) Length)
return ERR_SORT;
lpSqlNode->value.String[Length]='\0';
/* Remove trailing blanks */
len = (UWORD) s_lstrlen(lpSqlNode->value.String);
while ((len > 0) && (lpSqlNode->value.String[len-1] == ' ')) {
lpSqlNode->value.String[len-1] = '\0';
len--;
}
break;
case TYPE_CHAR:
if (_lread(lpSqlNodeStmt->node.select.Sortfile,
lpSqlNode->value.String,
(UINT) Length) != (UINT) Length)
return ERR_SORT;
lpSqlNode->value.String[Length]='\0';
/* Remove trailing blanks if need be */
if ((lpSqlNode->sqlSqlType == SQL_VARCHAR) ||
(lpSqlNode->sqlSqlType == SQL_LONGVARCHAR)) {
len = (UWORD) s_lstrlen(lpSqlNode->value.String);
while ((len > 0) && (lpSqlNode->value.String[len-1] == ' ')) {
lpSqlNode->value.String[len-1] = '\0';
len--;
}
}
break;
case TYPE_DATE:
if (_lread(lpSqlNodeStmt->node.select.Sortfile, szBuffer,
(UINT) Length) != (UINT) Length)
return ERR_SORT;
CharToDate((LPUSTR)szBuffer, Length, &(lpSqlNode->value.Date));
break;
case TYPE_TIME:
if (_lread(lpSqlNodeStmt->node.select.Sortfile, szBuffer,
(UINT) Length) != (UINT) Length)
return ERR_SORT;
CharToTime((LPUSTR)szBuffer, Length, &(lpSqlNode->value.Time));
break;
case TYPE_TIMESTAMP:
if (_lread(lpSqlNodeStmt->node.select.Sortfile, szBuffer,
(UINT) Length) != (UINT) Length)
return ERR_SORT;
CharToTimestamp((LPUSTR)szBuffer, Length, &(lpSqlNode->value.Timestamp));
break;
case TYPE_BINARY:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
/* Read NULL flag */
if (_lread(lpSqlNodeStmt->node.select.Sortfile, &cNullFlag, 1) != 1)
return ERR_SORT;
switch (cNullFlag) {
case NULL_FLAG:
lpSqlNode->sqlIsNull = TRUE;
break;
case NOT_NULL_FLAG:
lpSqlNode->sqlIsNull = FALSE;
break;
default:
return ERR_SORT;
}
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC TxnCapableForDDL(LPSTMT lpstmt)
/* Makes sure the DDL statements can be executed if DML statements were */
/* encountered */
{
LPSTMT lpstmtOther;
RETCODE err;
/* What transaction capabilities are allowed? */
switch (lpstmt->lpdbc->lpISAM->fTxnCapable) {
case SQL_TC_NONE:
/* No transactions. Allow all DDL statements all the time */
break;
case SQL_TC_DML:
/* Transactions can never DDL statements */
for (lpstmtOther = lpstmt->lpdbc->lpstmts;
lpstmtOther != NULL;
lpstmtOther = lpstmtOther->lpNext) {
if (lpstmtOther->fDMLTxn)
return ERR_DDLENCOUNTERD;
}
break;
case SQL_TC_DDL_COMMIT:
/* Transactions that contain DDL statements cause a commit */
for (lpstmtOther = lpstmt->lpdbc->lpstmts;
lpstmtOther != NULL;
lpstmtOther = lpstmtOther->lpNext) {
if (lpstmtOther->fDMLTxn) {
err = SQLTransact(SQL_NULL_HENV, (HDBC)lpstmt->lpdbc,
SQL_COMMIT);
if ((err != SQL_SUCCESS) && (err != SQL_SUCCESS_WITH_INFO)) {
lpstmt->errcode = lpstmt->lpdbc->errcode;
s_lstrcpy(lpstmt->szISAMError, lpstmt->lpdbc->szISAMError);
return err;
}
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
return ERR_DDLSTATEMENTLOST;
else
return ERR_DDLCAUSEDACOMMIT;
}
}
break;
case SQL_TC_DDL_IGNORE:
/* DDL statements are ignored within a transaction */
for (lpstmtOther = lpstmt->lpdbc->lpstmts;
lpstmtOther != NULL;
lpstmtOther = lpstmtOther->lpNext) {
if (lpstmtOther->fDMLTxn)
return ERR_DDLIGNORED;
}
break;
case SQL_TC_ALL:
/* Allow all DDL statements all the time */
break;
}
return ERR_SUCCESS;
}
/***************************************************************************/
/***************************************************************************/
RETCODE INTFUNC FetchRow(LPSTMT lpstmt, LPSQLNODE lpSqlNode)
/* Fetch the next row from a SELECT */
{
LPSQLNODE lpSqlNodeTable;
LPSQLNODE lpSqlNodeTables;
LPSQLNODE lpSqlNodePredicate;
LPSQLNODE lpSqlNodeHaving;
SQLNODEIDX idxTables;
ISAMBOOKMARK bookmark;
RETCODE err;
// ODBCTRACE("\nWBEM ODBC Driver : FetchRow\n");
/* Error if after the last row */
if (lpSqlNode->node.select.CurrentRow == AFTER_LAST_ROW)
return ERR_NODATAFOUND;
/* Is there a sort file to read from */
if (lpSqlNode->node.select.Sortfile == HFILE_ERROR) {
/* No. Get the table list and predicate node. */
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.select.Tables);
if (lpSqlNode->node.select.Predicate == NO_SQLNODE)
lpSqlNodePredicate = NULL;
else
lpSqlNodePredicate = ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.select.Predicate);
/* Get the next record */
err = NextRecord(lpstmt, lpSqlNodeTables, lpSqlNodePredicate);
if (err == ERR_NODATAFOUND) {
lpSqlNode->node.select.CurrentRow = AFTER_LAST_ROW;
return err;
}
else if (err != ERR_SUCCESS)
return err;
/* Set row flag */
if (lpSqlNode->node.select.CurrentRow == BEFORE_FIRST_ROW)
lpSqlNode->node.select.CurrentRow = 0;
else
lpSqlNode->node.select.CurrentRow++;
}
else if (!(lpSqlNode->node.select.ReturningDistinct)) {
/* Yes. Look for next record in sort file */
if (lpSqlNode->node.select.Having == NO_SQLNODE)
lpSqlNodeHaving = NULL;
else
lpSqlNodeHaving =
ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.select.Having);
while (TRUE) {
/* Set row flag */
if (lpSqlNode->node.select.CurrentRow == BEFORE_FIRST_ROW) {
if (lpSqlNode->node.select.RowCount != 0) {
lpSqlNode->node.select.CurrentRow = 0;
}
else {
lpSqlNode->node.select.CurrentRow = AFTER_LAST_ROW;
return ERR_NODATAFOUND;
}
}
else if (lpSqlNode->node.select.CurrentRow ==
lpSqlNode->node.select.RowCount-1) {
lpSqlNode->node.select.CurrentRow = AFTER_LAST_ROW;
return ERR_NODATAFOUND;
}
else
lpSqlNode->node.select.CurrentRow++;
/* If no HAVING clause, this record qualifies */
if (lpSqlNodeHaving == NULL)
break;
/* If HAVING condition is satisfied, this record qualifies */
err = EvaluateExpression(lpstmt, lpSqlNodeHaving);
if (err != ERR_SUCCESS)
return err;
if (!(lpSqlNodeHaving->sqlIsNull) &&
(lpSqlNodeHaving->value.Double == TRUE))
break;
}
/* Is there a group by? */
if ((lpSqlNode->node.select.Groupbycolumns == NO_SQLNODE) &&
(!lpSqlNode->node.select.ImplicitGroupby)) {
/* No. Position to bookmarks in that row */
if (_llseek(lpSqlNode->node.select.Sortfile,
(lpSqlNode->node.select.CurrentRow *
lpSqlNode->node.select.SortRecordsize) +
lpSqlNode->node.select.SortBookmarks - 1, 0) == HFILE_ERROR)
return ERR_SORT;
/* For each table... */
idxTables = lpSqlNode->node.select.Tables;
while (idxTables != NO_SQLNODE) {
/* Get the table node */
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt, idxTables);
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeTables->node.tables.Table);
/* Read the bookmark for it */
if (_lread(lpSqlNode->node.select.Sortfile, &bookmark,
sizeof(ISAMBOOKMARK)) != sizeof(ISAMBOOKMARK))
return ERR_SORT;
/* Position to that record */
if (bookmark.currentRecord == NULL_BOOKMARK)
{
lpSqlNodeTable->node.table.AllNull = TRUE;
}
else
{
lpSqlNodeTable->node.table.AllNull = FALSE;
err = ISAMPosition(lpSqlNodeTable->node.table.Handle, &bookmark);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
}
/* Point at next table */
idxTables = lpSqlNodeTables->node.tables.Next;
}
}
}
else {
/* Yes. Look for next record in DISTINCT file. Set row flag */
if (lpSqlNode->node.select.CurrentRow == BEFORE_FIRST_ROW) {
if (lpSqlNode->node.select.RowCount != 0) {
lpSqlNode->node.select.CurrentRow = 0;
}
else {
lpSqlNode->node.select.CurrentRow = AFTER_LAST_ROW;
return ERR_NODATAFOUND;
}
}
else if (lpSqlNode->node.select.CurrentRow ==
lpSqlNode->node.select.RowCount-1) {
lpSqlNode->node.select.CurrentRow = AFTER_LAST_ROW;
return ERR_NODATAFOUND;
}
else
lpSqlNode->node.select.CurrentRow++;
}
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC EvaluateExpression(LPSTMT lpstmt, LPSQLNODE lpSqlNode)
/* Eavluates an SQL expression by walking the parse tree, computing */
/* the value of each node with respect to a database record, and */
/* storing the result in the string area. */
{
// ODBCTRACE ("\nWBEM ODBC Driver : EvaluateExpression\n");
LPSQLTREE lpSql;
LPSQLNODE lpSqlNodeLeft = 0;
LPSQLNODE lpSqlNodeRight = 0;
RETCODE err;
SQLNODEIDX idxValues;
LPSQLNODE lpSqlNodeValues;
LPUSTR lpWorkBuffer1;
LPUSTR lpWorkBuffer2;
LPUSTR lpWorkBuffer3;
BOOL fReturningDistinct;
LPSQLNODE lpSqlNodeSelect;
BOOL fTruncation;
BOOL fIsNull;
lpSql = lpstmt->lpSqlStmt;
if (lpSqlNode == NULL)
return ERR_INTERNAL;
err = ERR_SUCCESS;
switch (lpSqlNode->sqlNodeType) {
case NODE_TYPE_NONE:
case NODE_TYPE_ROOT:
case NODE_TYPE_CREATE:
case NODE_TYPE_DROP:
case NODE_TYPE_SELECT:
case NODE_TYPE_INSERT:
case NODE_TYPE_DELETE:
case NODE_TYPE_UPDATE:
case NODE_TYPE_CREATEINDEX:
case NODE_TYPE_DROPINDEX:
case NODE_TYPE_PASSTHROUGH:
case NODE_TYPE_TABLES:
case NODE_TYPE_VALUES:
case NODE_TYPE_COLUMNS:
case NODE_TYPE_SORTCOLUMNS:
case NODE_TYPE_GROUPBYCOLUMNS:
case NODE_TYPE_UPDATEVALUES:
case NODE_TYPE_CREATECOLS:
case NODE_TYPE_TABLE:
err = ERR_INTERNAL;
break;
case NODE_TYPE_BOOLEAN:
/* Evaluate the left child node */
lpSqlNodeLeft = ToNode(lpSql, lpSqlNode->node.boolean.Left);
err = EvaluateExpression(lpstmt, lpSqlNodeLeft);
if (err != ERR_SUCCESS)
return err;
/* Is this an AND? */
if (lpSqlNode->node.boolean.Operator == OP_AND) {
LPSQLNODE lpSqlNodeAnd;
BOOL sqlIsNull;
BOOL fResult;
/* Yes. Look at each sub-expression */
lpSqlNodeAnd = lpSqlNode;
sqlIsNull = FALSE;
fResult = TRUE;
while (TRUE) {
/* If the left child is FALSE, return FALSE */
if (!((BOOL) lpSqlNodeLeft->value.Double)) {
sqlIsNull = FALSE;
fResult = FALSE;
break;
}
/* If the left child is NULL, the result may be NULL */
else if (lpSqlNodeLeft->sqlIsNull) {
sqlIsNull = TRUE;
fResult = FALSE;
}
/* Get the right child */
lpSqlNodeRight = ToNode(lpSql, lpSqlNode->node.boolean.Right);
/* Is it an AND node? */
if ((lpSqlNodeRight->sqlNodeType != NODE_TYPE_BOOLEAN) ||
(lpSqlNodeRight->node.boolean.Operator != OP_AND)) {
/* No. Evaluate it */
err = EvaluateExpression(lpstmt, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
/* If the right child is FALSE, return FALSE */
if (!((BOOL) lpSqlNodeRight->value.Double)) {
sqlIsNull = FALSE;
fResult = FALSE;
}
/* If the right child is NULL, the result is NULL */
else if (lpSqlNodeRight->sqlIsNull) {
sqlIsNull = TRUE;
fResult = FALSE;
}
/* Leave the loop */
break;
}
/* Point to right and continue to walk down the AND nodes */
lpSqlNode = lpSqlNodeRight;
lpSqlNodeLeft = ToNode(lpSql, lpSqlNode->node.boolean.Left);
err = EvaluateExpression(lpstmt, lpSqlNodeLeft);
if (err != ERR_SUCCESS)
return err;
}
/* Return result */
lpSqlNodeAnd->sqlIsNull = sqlIsNull;
lpSqlNodeAnd->value.Double = fResult;
break;
}
/* Is there a right child? */
if (lpSqlNode->node.boolean.Right != NO_SQLNODE) {
/* Yes. Evaluate it */
lpSqlNodeRight = ToNode(lpSql, lpSqlNode->node.boolean.Right);
err = EvaluateExpression(lpstmt, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
}
if (lpSqlNode->node.boolean.Operator != OP_NOT && lpSqlNodeRight == 0)
return ERR_INTERNAL;
/* Perform the operation. */
switch (lpSqlNode->node.boolean.Operator) {
case OP_NOT:
/* If child is NULL, return NULL */
if (lpSqlNodeLeft->sqlIsNull) {
lpSqlNode->sqlIsNull = TRUE;
break;
}
/* Evaluate expression */
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Double = !((BOOL) lpSqlNodeLeft->value.Double);
break;
case OP_AND:
/* Is left child NULL or TRUE? */
if ((lpSqlNodeLeft->sqlIsNull) ||
((BOOL) lpSqlNodeLeft->value.Double)) {
/* Yes. If right child is NULL, return NULL */
if (lpSqlNodeRight->sqlIsNull)
lpSqlNode->sqlIsNull = TRUE;
/* If right child TRUE, return left child */
else if ((BOOL) lpSqlNodeRight->value.Double) {
lpSqlNode->sqlIsNull = lpSqlNodeLeft->sqlIsNull;
lpSqlNode->value.Double = lpSqlNodeLeft->value.Double;
}
/* Otherwise right child must be FALSE, return FALSE */
else {
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Double = FALSE;
}
}
/* Otherwise left child must be FALSE, return FALSE */
else {
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Double = FALSE;
}
break;
case OP_OR:
/* Is left child NULL or FALSE? */
if ((lpSqlNodeLeft->sqlIsNull) ||
(!((BOOL) lpSqlNodeLeft->value.Double))) {
/* Yes. If right child is NULL, return NULL */
if (lpSqlNodeRight->sqlIsNull)
lpSqlNode->sqlIsNull = TRUE;
/* If right child FALSE, return left child */
else if (!((BOOL) lpSqlNodeRight->value.Double)) {
lpSqlNode->sqlIsNull = lpSqlNodeLeft->sqlIsNull;
lpSqlNode->value.Double = lpSqlNodeLeft->value.Double;
}
/* Otherwise right child must be TRUE, return TRUE */
else {
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Double = TRUE;
}
}
/* Otherwise left child must be TRUE, return TRUE */
else {
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Double = TRUE;
}
break;
default:
err = ERR_INTERNAL;
break;
}
break;
case NODE_TYPE_COMPARISON:
// ODBCTRACE ("\nWBEM ODBC Driver : NODE_TYPE_COMPARISON\n");
/* Evaluate the left child */
if (lpSqlNode->node.comparison.Operator != OP_EXISTS) {
lpSqlNodeLeft = ToNode(lpSql, lpSqlNode->node.comparison.Left);
err = EvaluateExpression(lpstmt, lpSqlNodeLeft);
if (err != ERR_SUCCESS)
return err;
}
/* EXISTS operator? */
if (lpSqlNode->node.comparison.Operator == OP_EXISTS) {
/* Do the sub-select */
lpSqlNodeSelect = ToNode(lpSql, lpSqlNode->node.comparison.Left);
err = ExecuteQuery(lpstmt, lpSqlNodeSelect);
if (err == ERR_DATATRUNCATED)
err = ERR_SUCCESS;
if ((err != ERR_SUCCESS) && (err != ERR_NODATAFOUND))
return err;
/* Try to fetch a row */
if (err == ERR_SUCCESS) {
err = FetchRow(lpstmt, lpSqlNodeSelect);
if ((err != ERR_SUCCESS) && (err != ERR_NODATAFOUND))
return err;
}
/* Return result */
lpSqlNode->sqlIsNull = FALSE;
if (err == ERR_NODATAFOUND)
lpSqlNode->value.Double = FALSE;
else
lpSqlNode->value.Double = TRUE;
}
/* Nested sub-select? */
else if (lpSqlNode->node.comparison.SelectModifier !=
SELECT_NOTSELECT) {
/* Yes. If left child is NULL, return NULL */
if (lpSqlNodeLeft->sqlIsNull) {
lpSqlNode->sqlIsNull = TRUE;
lpSqlNode->value.Double = 0;
break;
}
/* Do the sub-select */
fTruncation = FALSE;
lpSqlNodeSelect = ToNode(lpSql, lpSqlNode->node.comparison.Right);
lpSqlNodeRight = ToNode(lpSql, lpSqlNodeSelect->node.select.Values);
lpSqlNodeRight = ToNode(lpSql, lpSqlNodeRight->node.values.Value);
err = ExecuteQuery(lpstmt,
ToNode(lpSql, lpSqlNode->node.comparison.Right));
if (err == ERR_DATATRUNCATED) {
fTruncation = TRUE;
err = ERR_SUCCESS;
}
if ((err != ERR_SUCCESS) && (err != ERR_NODATAFOUND))
return err;
/* Get the first value */
if (err == ERR_SUCCESS) {
// ODBCTRACE ("\nWBEM ODBC Driver : Get the first value\n");
err = FetchRow(lpstmt, lpSqlNodeSelect);
if ((err != ERR_SUCCESS) && (err != ERR_NODATAFOUND))
return err;
}
/* Does the select return any rows? */
if (err == ERR_NODATAFOUND) {
/* No. Return result */
lpSqlNode->sqlIsNull = FALSE;
switch (lpSqlNode->node.comparison.SelectModifier) {
case SELECT_NOTSELECT:
return ERR_INTERNAL;
case SELECT_ALL:
lpSqlNode->value.Double = TRUE;
break;
case SELECT_ANY:
lpSqlNode->value.Double = FALSE;
break;
case SELECT_ONE:
return ERR_NOTSINGLESELECT;
break;
case SELECT_EXISTS:
default:
return ERR_INTERNAL;
}
}
else {
/* Yes. For each value returned */
fIsNull = FALSE;
while (TRUE) {
/* Get value */
err = EvaluateExpression(lpstmt, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
/* Null value? */
if (!lpSqlNodeRight->sqlIsNull) {
/* No. Compare the values */
err = ValueCompare(lpSqlNode, lpSqlNodeLeft,
lpSqlNode->node.comparison.Operator,
lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
/* Add it into the result */
switch (lpSqlNode->node.comparison.SelectModifier) {
case SELECT_NOTSELECT:
return ERR_INTERNAL;
case SELECT_ALL:
if (lpSqlNode->value.Double == FALSE) {
lpSqlNode->sqlIsNull = FALSE;
if (fTruncation)
return ERR_DATATRUNCATED;
return ERR_SUCCESS;
}
break;
case SELECT_ANY:
if (lpSqlNode->value.Double == TRUE) {
lpSqlNode->sqlIsNull = FALSE;
if (fTruncation)
return ERR_DATATRUNCATED;
return ERR_SUCCESS;
}
break;
case SELECT_ONE:
break;
case SELECT_EXISTS:
default:
return ERR_INTERNAL;
}
}
else
fIsNull = TRUE;
/* Get next value */
// ODBCTRACE ("\nWBEM ODBC Driver : Get next value\n");
err = FetchRow(lpstmt, lpSqlNodeSelect);
if (err == ERR_NODATAFOUND)
break;
if (err != ERR_SUCCESS)
return err;
/* Error if too mnay values */
if (lpSqlNode->node.comparison.SelectModifier==SELECT_ONE)
return ERR_NOTSINGLESELECT;
}
/* Figure out final answer */
err = ERR_SUCCESS;
if (fIsNull) {
lpSqlNode->sqlIsNull = TRUE;
lpSqlNode->value.Double = 0;
}
else {
lpSqlNode->sqlIsNull = FALSE;
switch (lpSqlNode->node.comparison.SelectModifier) {
case SELECT_NOTSELECT:
return ERR_INTERNAL;
case SELECT_ALL:
lpSqlNode->value.Double = TRUE;
break;
case SELECT_ANY:
lpSqlNode->value.Double = FALSE;
break;
case SELECT_ONE:
/* This was set by the call to ValueCompare above */
break;
case SELECT_EXISTS:
default:
return ERR_INTERNAL;
}
}
/* Return truncation error if need be */
if (fTruncation)
err = ERR_DATATRUNCATED;
}
}
/* IN or NOT IN operator? */
else if ((lpSqlNode->node.comparison.Operator != OP_IN) &&
(lpSqlNode->node.comparison.Operator != OP_NOTIN)) {
/* No. Evaluate the right child */
lpSqlNodeRight = ToNode(lpSql, lpSqlNode->node.comparison.Right);
err = EvaluateExpression(lpstmt, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
/* Could this be an "IS NULL" or "IS NOT NULL" expression? */
if (lpSqlNodeRight->sqlIsNull &&
((lpSqlNodeRight->sqlNodeType == NODE_TYPE_NULL) ||
(lpSqlNodeRight->sqlNodeType == NODE_TYPE_PARAMETER))) {
/* Possibly. Is this an "IS NULL" expression? */
if (lpSqlNode->node.comparison.Operator == OP_EQ) {
/* Yes. Return TRUE if the left child is NULL. */
lpSqlNode->sqlIsNull = FALSE;
if (lpSqlNodeLeft->sqlIsNull)
lpSqlNode->value.Double = TRUE;
else
lpSqlNode->value.Double = FALSE;
break;
}
/* Is this an "IS NOT NULL" expression? */
else if (lpSqlNode->node.comparison.Operator == OP_NE) {
/* Yes. Return FALSE if the left child is NULL. */
lpSqlNode->sqlIsNull = FALSE;
if (lpSqlNodeLeft->sqlIsNull)
lpSqlNode->value.Double = FALSE;
else
lpSqlNode->value.Double = TRUE;
break;
}
}
/* If either child is NULL, return NULL */
if (lpSqlNodeLeft->sqlIsNull || lpSqlNodeRight->sqlIsNull) {
lpSqlNode->sqlIsNull = TRUE;
lpSqlNode->value.Double = 0;
break;
}
/* Compare values */
err = ValueCompare(lpSqlNode, lpSqlNodeLeft,
lpSqlNode->node.comparison.Operator, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
}
else {
/* Yes. If test value is NULL, return NULL */
if (lpSqlNodeLeft->sqlIsNull) {
lpSqlNode->sqlIsNull = TRUE;
lpSqlNode->value.Double = 0;
break;
}
/* Set up the default answer */
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Double = FALSE;
/* For each value on list... */
idxValues = lpSqlNode->node.comparison.Right;
while (idxValues != NO_SQLNODE) {
/* Get the value */
lpSqlNodeValues = ToNode(lpSql, idxValues);
lpSqlNodeRight = ToNode(lpSql, lpSqlNodeValues->node.values.Value);
err = EvaluateExpression(lpstmt, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
/* Point at next value */
idxValues = lpSqlNodeValues->node.values.Next;
/* If this value is NULL, go on to the next one */
if (lpSqlNodeRight->sqlIsNull)
continue;
/* Compare this value to the test value */
err = ValueCompare(lpSqlNode, lpSqlNodeLeft, OP_EQ,
lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
/* If value was found, leave */
if (lpSqlNode->value.Double == TRUE)
break;
}
/* If NOT IN operator, negate the answer */
if (lpSqlNode->node.comparison.Operator == OP_NOTIN) {
if (lpSqlNode->value.Double == TRUE)
lpSqlNode->value.Double = FALSE;
else
lpSqlNode->value.Double = TRUE;
}
}
break;
case NODE_TYPE_ALGEBRAIC:
/* Set up return buffer */
switch (lpSqlNode->sqlDataType) {
case TYPE_NUMERIC:
lpSqlNode->value.String =
ToString(lpSql,lpSqlNode->node.algebraic.Value);
break;
case TYPE_CHAR:
lpSqlNode->value.String =
ToString(lpSql,lpSqlNode->node.algebraic.Value);
break;
case TYPE_DOUBLE:
case TYPE_INTEGER:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
break;
case TYPE_BINARY:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
/* Is this value in the sort DISTINCT record? */
lpSqlNodeSelect = ToNode(lpSql,
lpSqlNode->node.algebraic.EnclosingStatement);
if (lpSqlNodeSelect->sqlNodeType != NODE_TYPE_SELECT)
fReturningDistinct = FALSE;
else
fReturningDistinct = lpSqlNodeSelect->node.select.ReturningDistinct;
if (!fReturningDistinct) {
/* No. Evaluate the left child */
lpSqlNodeLeft = ToNode(lpSql, lpSqlNode->node.algebraic.Left);
err = EvaluateExpression(lpstmt, lpSqlNodeLeft);
if (err != ERR_SUCCESS)
return err;
/* If left child is NULL, the expression is null */
if (lpSqlNodeLeft->sqlIsNull) {
lpSqlNode->sqlIsNull = TRUE;
break;
}
/* Evaluate the right child (if any) */
if (lpSqlNode->node.algebraic.Right != NO_SQLNODE) {
lpSqlNodeRight = ToNode(lpSql, lpSqlNode->node.algebraic.Right);
err = EvaluateExpression(lpstmt, lpSqlNodeRight);
if (err != ERR_SUCCESS)
return err;
/* If right child is NULL, the expression is null */
if (lpSqlNodeRight->sqlIsNull) {
lpSqlNode->sqlIsNull = TRUE;
break;
}
}
else
lpSqlNodeRight = NULL;
/* Result is not null */
lpSqlNode->sqlIsNull = FALSE;
/* Perform the operation */
lpWorkBuffer1 = NULL;
lpWorkBuffer2 = NULL;
lpWorkBuffer3 = NULL;
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
break;
case TYPE_NUMERIC:
if ((lpSqlNode->node.algebraic.Operator == OP_TIMES) ||
(lpSqlNode->node.algebraic.Operator == OP_DIVIDEDBY)) {
lpWorkBuffer1 =
ToString(lpSql,lpSqlNode->node.algebraic.WorkBuffer1);
if (lpSqlNode->node.algebraic.Operator == OP_DIVIDEDBY) {
lpWorkBuffer2 =
ToString(lpSql,lpSqlNode->node.algebraic.WorkBuffer2);
lpWorkBuffer3 =
ToString(lpSql,lpSqlNode->node.algebraic.WorkBuffer3);
}
}
break;
case TYPE_CHAR:
break;
case TYPE_BINARY:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
err = NumericAlgebra(lpSqlNode, lpSqlNodeLeft,
lpSqlNode->node.algebraic.Operator, lpSqlNodeRight,
lpWorkBuffer1, lpWorkBuffer2, lpWorkBuffer3);
if (err != ERR_SUCCESS)
return err;
}
else {
/* Yes. Get the record */
err = RetrieveSortRecordValue(lpSqlNodeSelect, lpSqlNode,
lpSqlNode->node.algebraic.DistinctOffset,
lpSqlNode->node.algebraic.DistinctLength);
if (err != ERR_SUCCESS)
return err;
}
break;
case NODE_TYPE_SCALAR:
/* Set up return buffer */
switch (lpSqlNode->sqlDataType) {
case TYPE_NUMERIC:
lpSqlNode->value.String =
ToString(lpSql,lpSqlNode->node.scalar.Value);
break;
case TYPE_CHAR:
lpSqlNode->value.String =
ToString(lpSql,lpSqlNode->node.scalar.Value);
break;
case TYPE_DOUBLE:
case TYPE_INTEGER:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
break;
case TYPE_BINARY:
lpSqlNode->value.String =
ToString(lpSql,lpSqlNode->node.scalar.Value);
break;
default:
return ERR_NOTSUPPORTED;
}
/* Is this value in the sort DISTINCT record? */
lpSqlNodeSelect = ToNode(lpSql,
lpSqlNode->node.scalar.EnclosingStatement);
if (lpSqlNodeSelect->sqlNodeType != NODE_TYPE_SELECT)
fReturningDistinct = FALSE;
else
fReturningDistinct = lpSqlNodeSelect->node.select.ReturningDistinct;
if (!fReturningDistinct) {
/* Perform the operation */
err = EvaluateScalar(lpstmt, lpSqlNode);
if (err != ERR_SUCCESS)
return err;
}
else {
/* Yes. Get the record */
err = RetrieveSortRecordValue(lpSqlNodeSelect, lpSqlNode,
lpSqlNode->node.scalar.DistinctOffset,
lpSqlNode->node.scalar.DistinctLength);
if (err != ERR_SUCCESS)
return err;
}
break;
case NODE_TYPE_AGGREGATE:
/* Set up return buffer */
switch (lpSqlNode->sqlDataType) {
case TYPE_NUMERIC:
lpSqlNode->value.String =
ToString(lpSql,lpSqlNode->node.aggregate.Value);
break;
case TYPE_CHAR:
lpSqlNode->value.String =
ToString(lpSql,lpSqlNode->node.aggregate.Value);
break;
case TYPE_DOUBLE:
case TYPE_INTEGER:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
break;
case TYPE_BINARY:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
/* Retrieve the value */
lpSqlNodeSelect = ToNode(lpSql,
lpSqlNode->node.aggregate.EnclosingStatement);
if (lpSqlNodeSelect->sqlNodeType != NODE_TYPE_SELECT)
fReturningDistinct = FALSE;
else
fReturningDistinct = lpSqlNodeSelect->node.select.ReturningDistinct;
if (fReturningDistinct) {
err = RetrieveSortRecordValue(lpSqlNodeSelect, lpSqlNode,
lpSqlNode->node.aggregate.DistinctOffset,
lpSqlNode->node.aggregate.DistinctLength);
}
else {
err = RetrieveSortRecordValue(lpSqlNodeSelect, lpSqlNode,
lpSqlNode->node.aggregate.Offset,
lpSqlNode->node.aggregate.Length);
}
if (err != ERR_SUCCESS)
return err;
break;
case NODE_TYPE_COLUMN:
/* Set up return buffer */
switch (lpSqlNode->sqlDataType) {
case TYPE_NUMERIC:
lpSqlNode->value.String = ToString(lpSql,lpSqlNode->node.column.Value);
break;
case TYPE_CHAR:
lpSqlNode->value.String = ToString(lpSql,lpSqlNode->node.column.Value);
break;
case TYPE_DOUBLE:
case TYPE_INTEGER:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
break;
case TYPE_BINARY:
lpSqlNode->value.Binary = ToString(lpSql,lpSqlNode->node.column.Value);
break;
default:
return ERR_NOTSUPPORTED;
}
/* Is this column in the sort DISTINCT record? */
lpSqlNodeSelect = ToNode(lpSql,
lpSqlNode->node.column.EnclosingStatement);
if (lpSqlNodeSelect->sqlNodeType != NODE_TYPE_SELECT)
fReturningDistinct = FALSE;
else
fReturningDistinct = lpSqlNodeSelect->node.select.ReturningDistinct;
if (fReturningDistinct) {
/* Yes. Retrieve the value */
err = RetrieveSortRecordValue(lpSqlNodeSelect, lpSqlNode,
lpSqlNode->node.column.DistinctOffset,
lpSqlNode->node.column.DistinctLength);
if (err != ERR_SUCCESS)
return err;
}
/* Is this column in the sort record? */
else if (!(lpSqlNode->node.column.InSortRecord)) {
SDWORD size;
LPSQLNODE lpSqlNodeTable;
/* No. Get the column value from the current record */
lpSqlNodeTable = ToNode(lpSql, lpSqlNode->node.column.Table);
if (!(lpSqlNodeTable->node.table.AllNull)) {
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
err = ISAMGetData(lpSqlNodeTable->node.table.Handle,
lpSqlNode->node.column.Id, 0, SQL_C_DOUBLE,
&(lpSqlNode->value.Double), sizeof(double),
&size);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
if (size == SQL_NULL_DATA)
lpSqlNode->sqlIsNull = TRUE;
else
lpSqlNode->sqlIsNull = FALSE;
break;
case TYPE_NUMERIC:
err = ISAMGetData(lpSqlNodeTable->node.table.Handle,
lpSqlNode->node.column.Id, 0, SQL_C_CHAR,
lpSqlNode->value.String,
(SDWORD) (1 + 2 + lpSqlNode->sqlPrecision),
&size);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
if (size == SQL_NULL_DATA)
lpSqlNode->sqlIsNull = TRUE;
else {
lpSqlNode->sqlIsNull = FALSE;
BCDNormalize(lpSqlNode->value.String,
s_lstrlen(lpSqlNode->value.String),
lpSqlNode->value.String,
lpSqlNode->sqlPrecision + 2 + 1,
lpSqlNode->sqlPrecision,
lpSqlNode->sqlScale);
}
break;
case TYPE_CHAR:
err = ISAMGetData(lpSqlNodeTable->node.table.Handle,
lpSqlNode->node.column.Id, 0, SQL_C_CHAR,
lpSqlNode->value.String,
(SDWORD) (1 + lpSqlNode->sqlPrecision),
&size);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
if (size == SQL_NULL_DATA)
lpSqlNode->sqlIsNull = TRUE;
else
lpSqlNode->sqlIsNull = FALSE;
break;
case TYPE_DATE:
err = ISAMGetData(lpSqlNodeTable->node.table.Handle,
lpSqlNode->node.column.Id, 0, SQL_C_DATE,
&(lpSqlNode->value.Date), sizeof(DATE_STRUCT),
&size);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
if (size == SQL_NULL_DATA)
lpSqlNode->sqlIsNull = TRUE;
else
lpSqlNode->sqlIsNull = FALSE;
break;
case TYPE_TIME:
err = ISAMGetData(lpSqlNodeTable->node.table.Handle,
lpSqlNode->node.column.Id, 0, SQL_C_TIME,
&(lpSqlNode->value.Time), sizeof(TIME_STRUCT),
&size);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
if (size == SQL_NULL_DATA)
lpSqlNode->sqlIsNull = TRUE;
else
lpSqlNode->sqlIsNull = FALSE;
break;
case TYPE_TIMESTAMP:
err = ISAMGetData(lpSqlNodeTable->node.table.Handle,
lpSqlNode->node.column.Id, 0, SQL_C_TIMESTAMP,
&(lpSqlNode->value.Timestamp), sizeof(TIMESTAMP_STRUCT),
&size);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
if (size == SQL_NULL_DATA)
lpSqlNode->sqlIsNull = TRUE;
else
lpSqlNode->sqlIsNull = FALSE;
break;
case TYPE_BINARY:
err = ISAMGetData(lpSqlNodeTable->node.table.Handle,
lpSqlNode->node.column.Id, 0, SQL_C_BINARY,
BINARY_DATA(lpSqlNode->value.Binary),
(SDWORD) lpSqlNode->sqlPrecision,
&size);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
if (size == SQL_NULL_DATA) {
lpSqlNode->sqlIsNull = TRUE;
BINARY_LENGTH(lpSqlNode->value.Binary) = 0;
}
else {
lpSqlNode->sqlIsNull = FALSE;
BINARY_LENGTH(lpSqlNode->value.Binary) = size;
}
break;
default:
err = ERR_NOTSUPPORTED;
break;
}
}
else {
err = NO_ISAM_ERR;
lpSqlNode->sqlIsNull = TRUE;
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
lpSqlNode->value.Double = 0.0;
break;
case TYPE_NUMERIC:
s_lstrcpy(lpSqlNode->value.String, "");
break;
case TYPE_CHAR:
s_lstrcpy(lpSqlNode->value.String, "");
break;
case TYPE_DATE:
lpSqlNode->value.Date.year = 0;
lpSqlNode->value.Date.month = 0;
lpSqlNode->value.Date.day = 0;
break;
case TYPE_TIME:
lpSqlNode->value.Time.hour = 0;
lpSqlNode->value.Time.minute = 0;
lpSqlNode->value.Time.second = 0;
break;
case TYPE_TIMESTAMP:
lpSqlNode->value.Timestamp.year = 0;
lpSqlNode->value.Timestamp.month = 0;
lpSqlNode->value.Timestamp.day = 0;
lpSqlNode->value.Timestamp.hour = 0;
lpSqlNode->value.Timestamp.minute = 0;
lpSqlNode->value.Timestamp.second = 0;
lpSqlNode->value.Timestamp.fraction = 0;
break;
case TYPE_BINARY:
BINARY_LENGTH(lpSqlNode->value.Binary) = 0;
break;
default:
err = ERR_NOTSUPPORTED;
break;
}
}
}
else {
/* Yes. Retrieve the value */
err = RetrieveSortRecordValue(lpSqlNodeSelect, lpSqlNode,
lpSqlNode->node.column.Offset,
lpSqlNode->node.column.Length);
if (err != ERR_SUCCESS)
return err;
}
break;
case NODE_TYPE_STRING:
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.String = ToString(lpSql, lpSqlNode->node.string.Value);
break;
case NODE_TYPE_NUMERIC:
lpSqlNode->sqlIsNull = FALSE;
switch(lpSqlNode->sqlDataType) {
case TYPE_NUMERIC:
lpSqlNode->value.String =
ToString(lpSql, lpSqlNode->node.numeric.Numeric);
break;
case TYPE_DOUBLE:
case TYPE_INTEGER:
lpSqlNode->value.Double = lpSqlNode->node.numeric.Value;
break;
case TYPE_CHAR:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
case TYPE_BINARY:
default:
return ERR_INTERNAL;
}
break;
case NODE_TYPE_PARAMETER:
break;
case NODE_TYPE_USER:
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.String =
(LPUSTR) ISAMUser(ToNode(lpSql, ROOT_SQLNODE)->node.root.lpISAM);
break;
case NODE_TYPE_NULL:
lpSqlNode->sqlIsNull = TRUE;
break;
case NODE_TYPE_DATE:
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Date = lpSqlNode->node.date.Value;
break;
case NODE_TYPE_TIME:
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Time = lpSqlNode->node.time.Value;
break;
case NODE_TYPE_TIMESTAMP:
lpSqlNode->sqlIsNull = FALSE;
lpSqlNode->value.Timestamp = lpSqlNode->node.timestamp.Value;
break;
default:
return ERR_INTERNAL;
}
return err;
}
/***************************************************************************/
RETCODE INTFUNC Sort(LPSTMT lpstmt, LPSQLNODE lpSqlNodeSelect)
/* Sorts results of a SELECT statement */
{
// ODBCTRACE("\nWBEM ODBC Driver : Sort\n");
#ifdef WIN32
UCHAR szTempDir[MAX_PATHNAME_SIZE+1];
szTempDir[0] = 0;
#endif
UCHAR szFilename[MAX_PATHNAME_SIZE+1];
szFilename[0] = 0;
HFILE_BUFFER hfSortfile;
HFILE hfSortfile2;
LPSQLNODE lpSqlNodeTables;
LPSQLNODE lpSqlNodePredicate;
RETCODE err;
SQLNODEIDX idxSortcolumns;
LPSQLNODE lpSqlNodeSortcolumns;
SQLNODEIDX idxGroupbycolumns;
LPSQLNODE lpSqlNodeGroupbycolumns;
LPSQLNODE lpSqlNodeColumn;
SDWORD len;
PTR ptr;
SQLNODEIDX idxTableList;
LPSQLNODE lpSqlNodeTableList;
LPSQLNODE lpSqlNodeTable;
ISAMBOOKMARK bookmark;
UCHAR szBuffer[20+TIMESTAMP_SCALE+1];
long recordCount;
int sortStatus;
UCHAR cNullFlag;
SQLNODEIDX idxAggregate;
LPSQLNODE lpSqlNodeAggregate;
LPSQLNODE lpSqlNodeExpression;
double dbl;
szBuffer[0] = 0;
/* Create temporary file */
#ifdef WIN32
if (!GetTempPath(MAX_PATHNAME_SIZE+1, (LPSTR)szTempDir))
return ERR_SORT;
if (!GetTempFileName((LPSTR)szTempDir, "LEM", 0, (LPSTR)szFilename))
return ERR_SORT;
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szFilename);
#endif
hfSortfile = _lcreat_buffer((LPCSTR) szFilename, 0);
if (hfSortfile == NULL)
return ERR_SORT;
/* Get the table list and predicate node. */
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.Tables);
if (lpSqlNodeSelect->node.select.Predicate == NO_SQLNODE)
lpSqlNodePredicate = NULL;
else
lpSqlNodePredicate = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.Predicate);
/* For each record of result set... */
lpSqlNodeSelect->node.select.RowCount = 0;
while (TRUE) {
/* Get the next record */
err = NextRecord(lpstmt, lpSqlNodeTables,
lpSqlNodePredicate);
if (err == ERR_NODATAFOUND) {
if (lpSqlNodeSelect->node.select.CurrentRow == BEFORE_FIRST_ROW) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
lpSqlNodeSelect->node.select.CurrentRow = AFTER_LAST_ROW;
return ERR_SUCCESS;
}
break;
}
else if (err != ERR_SUCCESS) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* Set row flag */
if (lpSqlNodeSelect->node.select.CurrentRow == BEFORE_FIRST_ROW)
lpSqlNodeSelect->node.select.CurrentRow = 0;
else
lpSqlNodeSelect->node.select.CurrentRow++;
/* Increase row count */
(lpSqlNodeSelect->node.select.RowCount)++;
/* If there is a GROUP BY, puts the columns in the sort file in */
/* the order specified by the GROUP BY list. Otherwise put the */
/* the column in the sort file in the order specified by the */
/* ORDER BY list. For each sort key value or group by value... */
if (lpSqlNodeSelect->node.select.ImplicitGroupby) {
idxGroupbycolumns = NO_SQLNODE;
idxSortcolumns = NO_SQLNODE;
}
else {
idxGroupbycolumns = lpSqlNodeSelect->node.select.Groupbycolumns;
if (idxGroupbycolumns == NO_SQLNODE)
idxSortcolumns = lpSqlNodeSelect->node.select.Sortcolumns;
else
idxSortcolumns = NO_SQLNODE;
}
while ((idxSortcolumns != NO_SQLNODE) ||
(idxGroupbycolumns != NO_SQLNODE)) {
/* Get next column */
if (idxGroupbycolumns != NO_SQLNODE) {
lpSqlNodeGroupbycolumns =
ToNode(lpstmt->lpSqlStmt, idxGroupbycolumns);
lpSqlNodeColumn = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeGroupbycolumns->node.groupbycolumns.Column);
}
else {
lpSqlNodeSortcolumns =
ToNode(lpstmt->lpSqlStmt, idxSortcolumns);
lpSqlNodeColumn = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSortcolumns->node.sortcolumns.Column);
}
/* Get its value */
err = EvaluateExpression(lpstmt, lpSqlNodeColumn);
if (err != ERR_SUCCESS) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* Get length and pointer to key value */
switch (lpSqlNodeColumn->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (lpSqlNodeColumn->sqlIsNull)
lpSqlNodeColumn->value.Double = -1.7E308; //RAID 27433
len = sizeof(double);
ptr = &(lpSqlNodeColumn->value.Double);
break;
case TYPE_NUMERIC:
if (lpSqlNodeColumn->sqlIsNull)
(lpSqlNodeColumn->value.String)[0] = 0;
len = lpSqlNodeColumn->sqlPrecision + 2;
ptr = lpSqlNodeColumn->value.String;
/* (blank pad string values) */
while (s_lstrlen(lpSqlNodeColumn->value.String) < len)
s_lstrcat(lpSqlNodeColumn->value.String, " ");
break;
case TYPE_CHAR:
if (lpSqlNodeColumn->sqlIsNull)
(lpSqlNodeColumn->value.String)[0] = 0;
len = lpSqlNodeColumn->sqlPrecision;
ptr = lpSqlNodeColumn->value.String;
/* (blank pad string values) */
while (s_lstrlen(lpSqlNodeColumn->value.String) < len)
s_lstrcat(lpSqlNodeColumn->value.String, " ");
break;
case TYPE_BINARY:
if (lpSqlNodeColumn->sqlIsNull)
BINARY_LENGTH(lpSqlNodeColumn->value.Binary) = 0;
len = lpSqlNodeColumn->sqlPrecision;
ptr = BINARY_DATA(lpSqlNodeColumn->value.Binary);
/* (zero pad binary values) */
while (BINARY_LENGTH(lpSqlNodeColumn->value.Binary) < len) {
BINARY_DATA(lpSqlNodeColumn->value.Binary)[
BINARY_LENGTH(lpSqlNodeColumn->value.Binary)] = 0;
BINARY_LENGTH(lpSqlNodeColumn->value.Binary) =
BINARY_LENGTH(lpSqlNodeColumn->value.Binary) + 1;
}
break;
case TYPE_DATE:
if (lpSqlNodeColumn->sqlIsNull) {
lpSqlNodeColumn->value.Date.year = 0;
lpSqlNodeColumn->value.Date.month = 0;
lpSqlNodeColumn->value.Date.day = 0;
}
DateToChar(&(lpSqlNodeColumn->value.Date), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
case TYPE_TIME:
if (lpSqlNodeColumn->sqlIsNull) {
lpSqlNodeColumn->value.Time.hour = 0;
lpSqlNodeColumn->value.Time.minute = 0;
lpSqlNodeColumn->value.Time.second = 0;
}
TimeToChar(&(lpSqlNodeColumn->value.Time), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
case TYPE_TIMESTAMP:
if (lpSqlNodeColumn->sqlIsNull) {
lpSqlNodeColumn->value.Timestamp.year = 0;
lpSqlNodeColumn->value.Timestamp.month = 0;
lpSqlNodeColumn->value.Timestamp.day = 0;
lpSqlNodeColumn->value.Timestamp.hour = 0;
lpSqlNodeColumn->value.Timestamp.minute = 0;
lpSqlNodeColumn->value.Timestamp.second = 0;
lpSqlNodeColumn->value.Timestamp.fraction = 0;
}
TimestampToChar(&(lpSqlNodeColumn->value.Timestamp), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
default:
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
}
/* Put value into the file */
if (_lwrite_buffer(hfSortfile, (LPSTR) ptr, (UINT) len) != (UINT) len) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Put inthe null flag */
if (lpSqlNodeColumn->sqlIsNull)
cNullFlag = NULL_FLAG;
else
cNullFlag = NOT_NULL_FLAG;
if (_lwrite_buffer(hfSortfile, (LPSTR) &cNullFlag, 1) != 1) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Point at next key value */
if (idxGroupbycolumns != NO_SQLNODE)
idxGroupbycolumns =
lpSqlNodeGroupbycolumns->node.groupbycolumns.Next;
else
idxSortcolumns = lpSqlNodeSortcolumns->node.sortcolumns.Next;
}
/* Put the AGG function values into the record */
idxAggregate = lpSqlNodeSelect->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Get next aggregate */
lpSqlNodeAggregate = ToNode(lpstmt->lpSqlStmt, idxAggregate);
/* Get its value */
if (lpSqlNodeAggregate->node.aggregate.Operator != AGG_COUNT) {
lpSqlNodeExpression = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeAggregate->node.aggregate.Expression);
err = EvaluateExpression(lpstmt, lpSqlNodeExpression);
if (err != ERR_SUCCESS) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
}
/* Get length and pointer to key value */
switch (lpSqlNodeAggregate->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (lpSqlNodeAggregate->node.aggregate.Operator != AGG_COUNT) {
if (lpSqlNodeExpression->sqlDataType != TYPE_NUMERIC) {
if (lpSqlNodeExpression->sqlIsNull)
lpSqlNodeExpression->value.Double = 0.0;
len = sizeof(double);
ptr = &(lpSqlNodeExpression->value.Double);
}
else {
CharToDouble(lpSqlNodeExpression->value.String,
s_lstrlen(lpSqlNodeExpression->value.String),
FALSE, -1.7E308, 1.7E308, &dbl);
len = sizeof(double);
ptr = &dbl;
}
}
else {
lpSqlNodeAggregate->value.Double = 1.0;
len = sizeof(double);
ptr = &(lpSqlNodeAggregate->value.Double);
}
break;
case TYPE_NUMERIC:
if (lpSqlNodeExpression->sqlIsNull)
(lpSqlNodeExpression->value.String)[0] = 0;
len = lpSqlNodeAggregate->node.aggregate.Length;
ptr = lpSqlNodeExpression->value.String;
/* (blank pad string values) */
while (s_lstrlen(lpSqlNodeExpression->value.String) < len)
s_lstrcat(lpSqlNodeExpression->value.String, " ");
break;
case TYPE_CHAR:
if (lpSqlNodeExpression->sqlIsNull)
(lpSqlNodeExpression->value.String)[0] = 0;
len = lpSqlNodeAggregate->node.aggregate.Length;
ptr = lpSqlNodeExpression->value.String;
/* (blank pad string values) */
while (s_lstrlen(lpSqlNodeExpression->value.String) < len)
s_lstrcat(lpSqlNodeExpression->value.String, " ");
break;
case TYPE_BINARY:
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
case TYPE_DATE:
if (lpSqlNodeExpression->sqlIsNull) {
lpSqlNodeExpression->value.Date.year = 0;
lpSqlNodeExpression->value.Date.month = 0;
lpSqlNodeExpression->value.Date.day = 0;
}
DateToChar(&(lpSqlNodeExpression->value.Date), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
case TYPE_TIME:
if (lpSqlNodeExpression->sqlIsNull) {
lpSqlNodeExpression->value.Time.hour = 0;
lpSqlNodeExpression->value.Time.minute = 0;
lpSqlNodeExpression->value.Time.second = 0;
}
TimeToChar(&(lpSqlNodeExpression->value.Time), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
case TYPE_TIMESTAMP:
if (lpSqlNodeExpression->sqlIsNull) {
lpSqlNodeExpression->value.Timestamp.year = 0;
lpSqlNodeExpression->value.Timestamp.month = 0;
lpSqlNodeExpression->value.Timestamp.day = 0;
lpSqlNodeExpression->value.Timestamp.hour = 0;
lpSqlNodeExpression->value.Timestamp.minute = 0;
lpSqlNodeExpression->value.Timestamp.second = 0;
lpSqlNodeExpression->value.Timestamp.fraction = 0;
}
TimestampToChar(&(lpSqlNodeExpression->value.Timestamp), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
default:
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
}
/* Put value into the file */
if (_lwrite_buffer(hfSortfile, (LPSTR) ptr, (UINT) len) != (UINT) len) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Put inthe null flag */
if (lpSqlNodeAggregate->node.aggregate.Operator == AGG_COUNT)
cNullFlag = NOT_NULL_FLAG;
else if (lpSqlNodeExpression->sqlIsNull)
cNullFlag = NULL_FLAG;
else
cNullFlag = NOT_NULL_FLAG;
if (_lwrite_buffer(hfSortfile, (LPSTR) &cNullFlag, 1) != 1) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Point at next value */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
/* For each record in table list... */
if (lpSqlNodeSelect->node.select.ImplicitGroupby)
idxTableList = NO_SQLNODE;
else if (lpSqlNodeSelect->node.select.Groupbycolumns == NO_SQLNODE)
idxTableList = lpSqlNodeSelect->node.select.Tables;
else
idxTableList = NO_SQLNODE;
while (idxTableList != NO_SQLNODE) {
/* Get table */
lpSqlNodeTableList = ToNode(lpstmt->lpSqlStmt, idxTableList);
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeTableList->node.tables.Table);
/* Get bookmark of current record */
if (lpSqlNodeTable->node.table.AllNull)
{
bookmark.currentRecord = NULL_BOOKMARK;
}
else
{
err = ISAMGetBookmark(lpSqlNodeTable->node.table.Handle, &bookmark);
if (err != ERR_SUCCESS) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
}
/* Put value into the file */
if (_lwrite_buffer(hfSortfile, (LPSTR) &bookmark, sizeof(ISAMBOOKMARK))
!= sizeof(ISAMBOOKMARK)) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Point at next table */
idxTableList = lpSqlNodeTableList->node.tables.Next;
}
}
if (_lclose_buffer(hfSortfile) == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Sort the file */
if (!(lpSqlNodeSelect->node.select.ImplicitGroupby)) {
/* Sort the file */
s_1mains((LPSTR) szFilename, (LPSTR) szFilename, (LPSTR)
ToString(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.SortDirective),
&recordCount, &sortStatus);
if (sortStatus != 0) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
lpSqlNodeSelect->node.select.RowCount = recordCount;
}
/* Open destination file */
hfSortfile2 = _lopen((LPCSTR) szFilename, OF_READ);
if (hfSortfile2 == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Save name and handle to file of sorted records */
s_lstrcpy(ToString(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.SortfileName), szFilename);
lpSqlNodeSelect->node.select.Sortfile = hfSortfile2;
lpSqlNodeSelect->node.select.ReturningDistinct = FALSE;
/* Set up to read first row */
lpSqlNodeSelect->node.select.CurrentRow = BEFORE_FIRST_ROW;
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC GroupBy(LPSTMT lpstmt, LPSQLNODE lpSqlNodeSelect)
/* Does GROUP BY on results of a SELECT statement */
{
#ifdef WIN32
UCHAR szTempDir[MAX_PATHNAME_SIZE+1];
szTempDir[0] = 0;
#endif
UCHAR szFilename[MAX_PATHNAME_SIZE+1];
szFilename[0] = 0;
HFILE_BUFFER hfGroupbyfile;
HFILE hfGroupbyfile2;
HGLOBAL hGlobal;
LPUSTR lpResultRecord;
LPUSTR lpCurrentRecord;
SDWORD cRowCount;
SDWORD irow;
SQLNODEIDX idxAggregate;
LPSQLNODE lpSqlNodeAggregate;
LPUSTR lpValue;
LPUSTR lpValueNullFlag;
LPUSTR lpAggregateValue;
LPUSTR lpAggregateValueNullFlag;
/* If nothing to group, just return */
if (lpSqlNodeSelect->node.select.RowCount == 0)
return ERR_SUCCESS;
/* Create temporary file for the result of the group by */
#ifdef WIN32
if (!GetTempPath(MAX_PATHNAME_SIZE+1, (LPSTR)szTempDir))
return ERR_GROUPBY;
if (!GetTempFileName((LPSTR)szTempDir, "LEM", 0, (LPSTR)szFilename))
return ERR_GROUPBY;
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szFilename);
#endif
hfGroupbyfile = _lcreat_buffer((LPCSTR) szFilename, 0);
if (hfGroupbyfile == NULL)
return ERR_GROUPBY;
/* Allocate space for a result record buffer */
hGlobal = GlobalAlloc(GMEM_MOVEABLE,
(2 * lpSqlNodeSelect->node.select.SortRecordsize));
if (hGlobal == NULL ||
(lpResultRecord = (LPUSTR) GlobalLock(hGlobal)) == NULL) {
if (hGlobal)
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_MEMALLOCFAIL;
}
/* Allocate space for current record key buffer */
lpCurrentRecord = lpResultRecord + lpSqlNodeSelect->node.select.SortRecordsize;
/* Position to the first record */
if (_llseek(lpSqlNodeSelect->node.select.Sortfile, 0, 0) == HFILE_ERROR) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
/* Read the first record into the result record buffer */
if (_lread(lpSqlNodeSelect->node.select.Sortfile, lpResultRecord,
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) !=
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
/* Initialize the count for averages */
idxAggregate = lpSqlNodeSelect->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Get the function */
lpSqlNodeAggregate = ToNode(lpstmt->lpSqlStmt, idxAggregate);
/* Average operator? */
if (lpSqlNodeAggregate->node.aggregate.Operator == AGG_AVG) {
/* Yes. Point to the value */
lpAggregateValue = lpResultRecord +
lpSqlNodeAggregate->node.aggregate.Offset - 1;
lpAggregateValueNullFlag = lpAggregateValue +
lpSqlNodeAggregate->node.aggregate.Length;
/* If not null, set count to one. Otherwise zero */
switch (*lpAggregateValueNullFlag) {
case NULL_FLAG:
lpSqlNodeAggregate->node.aggregate.Count = 0.0;
break;
case NOT_NULL_FLAG:
lpSqlNodeAggregate->node.aggregate.Count = 1.0;
break;
default:
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
}
/* Do next aggregate */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
/* For each record... */
cRowCount = 0;
for (irow = 1; irow < lpSqlNodeSelect->node.select.RowCount; irow++) {
/* Read current record */
if (_lread(lpSqlNodeSelect->node.select.Sortfile, lpCurrentRecord,
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) !=
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
/* Does group by key match the key in the result record buffer? */
if (_fmemcmp(lpResultRecord, lpCurrentRecord,
(size_t) lpSqlNodeSelect->node.select.SortKeysize)) {
/* No. Calculate averages */
idxAggregate = lpSqlNodeSelect->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Get the function */
lpSqlNodeAggregate = ToNode(lpstmt->lpSqlStmt, idxAggregate);
/* Average operator? */
if (lpSqlNodeAggregate->node.aggregate.Operator == AGG_AVG) {
/* Yes. Point to the value */
lpAggregateValue = lpResultRecord +
lpSqlNodeAggregate->node.aggregate.Offset - 1;
lpAggregateValueNullFlag = lpAggregateValue +
lpSqlNodeAggregate->node.aggregate.Length;
/* If not null, calculate average */
if (*lpAggregateValueNullFlag == NOT_NULL_FLAG)
*((double FAR *) lpAggregateValue) /=
(lpSqlNodeAggregate->node.aggregate.Count);
}
/* Do next aggregate */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
/* Write result record buffer to the file */
if (_lwrite_buffer(hfGroupbyfile, (LPSTR) lpResultRecord,
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) !=
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
/* Increase count of number of records written */
cRowCount++;
/* Copy current record to the result record buffer */
_fmemcpy(lpResultRecord, lpCurrentRecord,
(size_t) lpSqlNodeSelect->node.select.SortRecordsize);
/* Initialize the count for averages */
idxAggregate = lpSqlNodeSelect->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Get the function */
lpSqlNodeAggregate = ToNode(lpstmt->lpSqlStmt, idxAggregate);
/* Average operator? */
if (lpSqlNodeAggregate->node.aggregate.Operator == AGG_AVG) {
/* Yes. Point to the value */
lpAggregateValue = lpResultRecord +
lpSqlNodeAggregate->node.aggregate.Offset - 1;
lpAggregateValueNullFlag = lpAggregateValue +
lpSqlNodeAggregate->node.aggregate.Length;
/* If not null, set count to one. Otherwise zero */
switch (*lpAggregateValueNullFlag) {
case NULL_FLAG:
lpSqlNodeAggregate->node.aggregate.Count = 0.0;
break;
case NOT_NULL_FLAG:
lpSqlNodeAggregate->node.aggregate.Count = 1.0;
break;
default:
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
}
/* Do next aggregate */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
}
else {
/* Yes. For each aggregate function... */
idxAggregate = lpSqlNodeSelect->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Get the function */
lpSqlNodeAggregate = ToNode(lpstmt->lpSqlStmt, idxAggregate);
/* Point to the value */
lpValue = lpCurrentRecord +
lpSqlNodeAggregate->node.aggregate.Offset - 1;
lpValueNullFlag = lpValue +
lpSqlNodeAggregate->node.aggregate.Length;
lpAggregateValue = lpResultRecord +
lpSqlNodeAggregate->node.aggregate.Offset - 1;
lpAggregateValueNullFlag = lpAggregateValue +
lpSqlNodeAggregate->node.aggregate.Length;
/* Null value? */
if (*lpValueNullFlag == NOT_NULL_FLAG) {
/* No. Is aggregate value null? */
if (*lpAggregateValueNullFlag == NOT_NULL_FLAG) {
/* No. Is a TYPE_NUMERIC involved? */
if (lpSqlNodeAggregate->sqlDataType != TYPE_NUMERIC) {
/* No. Incorporate field value into aggregate */
switch (lpSqlNodeAggregate->node.aggregate.Operator) {
case AGG_AVG:
case AGG_SUM:
switch (lpSqlNodeAggregate->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
*((double FAR *) lpAggregateValue) +=
(*((double FAR *) lpValue));
break;
case TYPE_NUMERIC:
case TYPE_CHAR:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
case TYPE_BINARY:
default:
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
}
/* Increase count */
if (lpSqlNodeAggregate->node.aggregate.Operator == AGG_AVG)
lpSqlNodeAggregate->node.aggregate.Count += (1.0);
break;
case AGG_COUNT:
*((double FAR *) lpAggregateValue) += (1.0);
break;
case AGG_MAX:
switch (lpSqlNodeAggregate->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (*((double FAR *) lpAggregateValue) <
*((double FAR *) lpValue))
*((double FAR *) lpAggregateValue) =
*((double FAR *) lpValue);
break;
case TYPE_CHAR:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
if (_fmemcmp(lpValue,
lpAggregateValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length)
> 0)
_fmemcpy(lpAggregateValue,
lpValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length);
break;
case TYPE_NUMERIC:
case TYPE_BINARY:
default:
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
}
break;
case AGG_MIN:
switch (lpSqlNodeAggregate->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (*((double FAR *) lpAggregateValue) >
*((double FAR *) lpValue))
*((double FAR *) lpAggregateValue) =
*((double FAR *) lpValue);
break;
case TYPE_CHAR:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
if (_fmemcmp(lpValue,
lpAggregateValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length)
< 0)
_fmemcpy(lpAggregateValue,
lpValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length);
break;
case TYPE_NUMERIC:
case TYPE_BINARY:
default:
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
}
break;
}
}
else {
SQLNODE left;
SQLNODE right;
SQLNODE result;
/* These buffers must be large enough to */
/* accomodate the largest SQL_NUMERIC or */
/* SQL_DECIMAL */
UCHAR szBufferLeft[64];
UCHAR szBufferRight[64];
UWORD len;
UCHAR szBufferResult[64];
RETCODE err;
/* Yes. Incorporate field value into aggregate */
switch (lpSqlNodeAggregate->node.aggregate.Operator) {
case AGG_AVG:
case AGG_COUNT:
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
case AGG_MAX:
/* Create left value */
left = *lpSqlNodeAggregate;
_fmemcpy(szBufferLeft, lpAggregateValue,
(size_t)
lpSqlNodeAggregate->node.aggregate.Length);
szBufferLeft[lpSqlNodeAggregate->node.
aggregate.Length] = '\0';
len = (UWORD) s_lstrlen(szBufferLeft);
while ((len > 0) &&
(szBufferLeft[len-1] == ' ')) {
szBufferLeft[len-1] = '\0';
len--;
}
left.value.String = (LPUSTR)szBufferLeft;
/* Create right value */
right = *lpSqlNodeAggregate;
_fmemcpy(szBufferRight, lpValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length);
szBufferRight[lpSqlNodeAggregate->node.
aggregate.Length] = '\0';
len = (UWORD) s_lstrlen(szBufferRight);
while ((len > 0) &&
(szBufferRight[len-1] == ' ')) {
szBufferRight[len-1] = '\0';
len--;
}
right.value.String = (LPUSTR)szBufferRight;
/* Compare the values */
result.sqlNodeType = NODE_TYPE_COMPARISON;
result.node.comparison.Operator = OP_LT;
result.node.comparison.SelectModifier = SELECT_NOTSELECT;
result.node.comparison.Left = NO_SQLNODE;
result.node.comparison.Right = NO_SQLNODE;
result.node.comparison.fSelectivity = 0;
result.node.comparison.NextRestrict = NO_SQLNODE;
result.sqlDataType = TYPE_INTEGER;
result.sqlSqlType = SQL_BIT;
result.sqlPrecision = 1;
result.sqlScale = 0;
err = NumericCompare(&result, &left,
OP_LT, &right);
if (err != ERR_SUCCESS) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* If this value is bigger, save it */
if (result.value.Double == TRUE)
_fmemcpy(lpAggregateValue, lpValue,
(size_t)
lpSqlNodeAggregate->node.aggregate.Length);
break;
case AGG_MIN:
/* Create left value */
left = *lpSqlNodeAggregate;
_fmemcpy(szBufferLeft, lpAggregateValue,
(size_t)
lpSqlNodeAggregate->node.aggregate.Length);
szBufferLeft[lpSqlNodeAggregate->node.
aggregate.Length] = '\0';
len = (UWORD) s_lstrlen(szBufferLeft);
while ((len > 0) &&
(szBufferLeft[len-1] == ' ')) {
szBufferLeft[len-1] = '\0';
len--;
}
left.value.String = (LPUSTR)szBufferLeft;
/* Create right value */
right = *lpSqlNodeAggregate;
_fmemcpy(szBufferRight, lpValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length);
szBufferRight[lpSqlNodeAggregate->node.
aggregate.Length] = '\0';
len = (UWORD) s_lstrlen(szBufferRight);
while ((len > 0) &&
(szBufferRight[len-1] == ' ')) {
szBufferRight[len-1] = '\0';
len--;
}
right.value.String = (LPUSTR)szBufferRight;
/* Compare the values */
result.sqlNodeType = NODE_TYPE_COMPARISON;
result.node.comparison.Operator = OP_GT;
result.node.comparison.SelectModifier = SELECT_NOTSELECT;
result.node.comparison.Left = NO_SQLNODE;
result.node.comparison.Right = NO_SQLNODE;
result.node.comparison.fSelectivity = 0;
result.node.comparison.NextRestrict = NO_SQLNODE;
result.sqlDataType = TYPE_INTEGER;
result.sqlSqlType = SQL_BIT;
result.sqlPrecision = 1;
result.sqlScale = 0;
err = NumericCompare(&result, &left,
OP_GT, &right);
if (err != ERR_SUCCESS) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* If this value is smaller, save it */
if (result.value.Double == TRUE)
_fmemcpy(lpAggregateValue, lpValue,
(size_t)
lpSqlNodeAggregate->node.aggregate.Length);
break;
case AGG_SUM:
/* Create left value */
left = *lpSqlNodeAggregate;
_fmemcpy(szBufferLeft, lpAggregateValue,
(size_t)
lpSqlNodeAggregate->node.aggregate.Length);
szBufferLeft[lpSqlNodeAggregate->node.
aggregate.Length] = '\0';
len = (UWORD) s_lstrlen(szBufferLeft);
while ((len > 0) &&
(szBufferLeft[len-1] == ' ')) {
szBufferLeft[len-1] = '\0';
len--;
}
left.value.String = (LPUSTR)szBufferLeft;
/* Create right value */
right = *lpSqlNodeAggregate;
_fmemcpy(szBufferRight, lpValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length);
szBufferRight[lpSqlNodeAggregate->node.
aggregate.Length] = '\0';
len = (UWORD) s_lstrlen(szBufferRight);
while ((len > 0) &&
(szBufferRight[len-1] == ' ')) {
szBufferRight[len-1] = '\0';
len--;
}
right.value.String = (LPUSTR)szBufferRight;
/* Add the left value to the right */
result = *lpSqlNodeAggregate;
result.value.String = (LPUSTR)szBufferResult;
err = NumericAlgebra(&result, &left,
OP_PLUS, &right, NULL, NULL, NULL);
if (err != ERR_SUCCESS) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* Save the result */
while (s_lstrlen(szBufferResult) < (SDWORD)
lpSqlNodeAggregate->node.aggregate.Length)
s_lstrcat(szBufferResult, " ");
_fmemcpy(lpAggregateValue, szBufferResult,
(size_t)
lpSqlNodeAggregate->node.aggregate.Length);
break;
}
}
}
else {
/* Yes. Copy value from current record */
_fmemcpy(lpAggregateValue, lpValue, (size_t)
lpSqlNodeAggregate->node.aggregate.Length);
*lpAggregateValueNullFlag = NOT_NULL_FLAG;
/* Initilize average count */
if (lpSqlNodeAggregate->node.aggregate.Operator == AGG_AVG)
lpSqlNodeAggregate->node.aggregate.Count = 1.0;
}
}
/* Do next aggregate */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
}
}
/* Calculate averages */
idxAggregate = lpSqlNodeSelect->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Get the function */
lpSqlNodeAggregate = ToNode(lpstmt->lpSqlStmt, idxAggregate);
/* Average operator? */
if (lpSqlNodeAggregate->node.aggregate.Operator == AGG_AVG) {
/* Yes. Point to the value */
lpAggregateValue = lpResultRecord +
lpSqlNodeAggregate->node.aggregate.Offset - 1;
lpAggregateValueNullFlag = lpAggregateValue +
lpSqlNodeAggregate->node.aggregate.Length;
/* If not null, calculate average */
if (*lpAggregateValueNullFlag == NOT_NULL_FLAG)
*((double FAR *) lpAggregateValue) /=
(lpSqlNodeAggregate->node.aggregate.Count);
}
/* Do next aggregate */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
/* Copy last record to the result record buffer */
if (_lwrite_buffer(hfGroupbyfile, (LPSTR) lpResultRecord,
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) !=
(UINT) lpSqlNodeSelect->node.select.SortRecordsize) {
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
_lclose_buffer(hfGroupbyfile);
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
/* Increase count of number of records written */
cRowCount++;
/* Free buffers */
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
/* Close the file */
if (_lclose_buffer(hfGroupbyfile) == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
/* Reopen the file for reading */
hfGroupbyfile2 = _lopen((LPCSTR) szFilename, OF_READ);
if (hfGroupbyfile2 == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename);
return ERR_GROUPBY;
}
/* Remove the sort file */
_lclose(lpSqlNodeSelect->node.select.Sortfile);
DeleteFile((LPCSTR) ToString(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.SortfileName));
/* Save name and handle to file of group by records */
s_lstrcpy(ToString(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.SortfileName), szFilename);
lpSqlNodeSelect->node.select.Sortfile = hfGroupbyfile2;
lpSqlNodeSelect->node.select.ReturningDistinct = FALSE;
/* Save total number of records in the group by file */
lpSqlNodeSelect->node.select.RowCount = cRowCount;
/* Set up to read first row */
lpSqlNodeSelect->node.select.CurrentRow = BEFORE_FIRST_ROW;
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC Distinct(LPSTMT lpstmt, LPSQLNODE lpSqlNodeSelect)
/* Generates results for SELECT DISTINCT */
{
// ODBCTRACE("\nWBEM ODBC Driver : Distinct\n");
UCHAR szTempDir[MAX_PATHNAME_SIZE+1];
szTempDir[0] = 0;
UCHAR szFilename[MAX_PATHNAME_SIZE+1];
UCHAR szFilename2[MAX_PATHNAME_SIZE+1];
szFilename[0] = 0;
szFilename2[0] = 0;
HFILE_BUFFER hfSortfile;
HFILE hfSortfile2;
LPSQLNODE lpSqlNodeTables;
LPSQLNODE lpSqlNodePredicate;
LPSQLNODE lpSqlNodeHaving;
RETCODE err;
SQLNODEIDX idxTableList;
LPSQLNODE lpSqlNodeTableList;
LPSQLNODE lpSqlNodeTable;
ISAMBOOKMARK bookmark;
SQLNODEIDX idxValues;
LPSQLNODE lpSqlNodeValues;
LPSQLNODE lpSqlNodeValue;
SDWORD len;
PTR ptr;
#define NUM_LEN 5
UCHAR szFormat[16];
UCHAR szBuffer[20+TIMESTAMP_SCALE+1];
UCHAR szSortDirective[64 + 3 + MAX_PATHNAME_SIZE];
long recordCount;
int sortStatus;
UCHAR cNullFlag;
BOOL fGotOne;
szBuffer[0] = 0;
/* Create temporary file */
#ifdef WIN32
if (!GetTempPath(MAX_PATHNAME_SIZE+1, (LPSTR)szTempDir))
return ERR_SORT;
if (!GetTempFileName((LPSTR)szTempDir, "LEM", 0, (LPSTR)szFilename))
return ERR_SORT;
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szFilename);
#endif
hfSortfile = _lcreat_buffer((LPCSTR) szFilename, 0);
if (hfSortfile == NULL)
return ERR_SORT;
/* For each record of result set... */
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.Tables);
if (lpSqlNodeSelect->node.select.Predicate == NO_SQLNODE)
lpSqlNodePredicate = NULL;
else
lpSqlNodePredicate = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.Predicate);
if (lpSqlNodeSelect->node.select.Having == NO_SQLNODE)
lpSqlNodeHaving = NULL;
else
lpSqlNodeHaving = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.Having);
wsprintf((LPSTR) szFormat, "%%0%dd", (UWORD) NUM_LEN);
while (TRUE) {
/* Is there a sort file to read from? */
if (lpSqlNodeSelect->node.select.Sortfile == HFILE_ERROR) {
/* No. Get the next record */
try
{
err = NextRecord(lpstmt, lpSqlNodeTables, lpSqlNodePredicate);
}
catch(...)
{
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_MEMALLOCFAIL;
}
if (err == ERR_NODATAFOUND) {
lpSqlNodeSelect->node.select.CurrentRow = AFTER_LAST_ROW;
break;
}
else if (err != ERR_SUCCESS) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* Set row flag */
if (lpSqlNodeSelect->node.select.CurrentRow == BEFORE_FIRST_ROW)
lpSqlNodeSelect->node.select.CurrentRow = 0;
else
lpSqlNodeSelect->node.select.CurrentRow++;
}
else {
/* Yes. Look for next record in sort file */
while (TRUE) {
/* Set row flag */
if (lpSqlNodeSelect->node.select.CurrentRow == BEFORE_FIRST_ROW) {
if (lpSqlNodeSelect->node.select.RowCount != 0) {
lpSqlNodeSelect->node.select.CurrentRow = 0;
}
else {
lpSqlNodeSelect->node.select.CurrentRow = AFTER_LAST_ROW;
break;
}
}
else if (lpSqlNodeSelect->node.select.CurrentRow ==
lpSqlNodeSelect->node.select.RowCount-1) {
lpSqlNodeSelect->node.select.CurrentRow = AFTER_LAST_ROW;
break;
}
else
lpSqlNodeSelect->node.select.CurrentRow++;
/* If no HAVING clause, this record qualifies */
if (lpSqlNodeHaving == NULL)
break;
/* If HAVING condition is satisfied, this record qualifies */
err = EvaluateExpression(lpstmt, lpSqlNodeHaving);
if (err != ERR_SUCCESS) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
if (!(lpSqlNodeHaving->sqlIsNull) &&
(lpSqlNodeHaving->value.Double == TRUE))
break;
}
if (lpSqlNodeSelect->node.select.CurrentRow == AFTER_LAST_ROW)
break;
/* Is there a group by? */
if ((lpSqlNodeSelect->node.select.Groupbycolumns == NO_SQLNODE) &&
(!lpSqlNodeSelect->node.select.ImplicitGroupby)) {
/* No. Position to bookmarks in that row */
if (_llseek(lpSqlNodeSelect->node.select.Sortfile,
(lpSqlNodeSelect->node.select.CurrentRow *
lpSqlNodeSelect->node.select.SortRecordsize) +
lpSqlNodeSelect->node.select.SortBookmarks - 1, 0)
== HFILE_ERROR) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* For each table... */
idxTableList = lpSqlNodeSelect->node.select.Tables;
while (idxTableList != NO_SQLNODE) {
/* Get the table node */
lpSqlNodeTableList = ToNode(lpstmt->lpSqlStmt,
idxTableList);
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeTableList->node.tables.Table);
/* Read the bookmark for it */
if (_lread(lpSqlNodeSelect->node.select.Sortfile,
&bookmark, sizeof(ISAMBOOKMARK)) !=
sizeof(ISAMBOOKMARK)) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Position to that record */
if (bookmark.currentRecord == NULL_BOOKMARK)
{
lpSqlNodeTable->node.table.AllNull = TRUE;
}
else
{
lpSqlNodeTable->node.table.AllNull = FALSE;
err = ISAMPosition(lpSqlNodeTable->node.table.Handle, &bookmark);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR) lpstmt->szISAMError);
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
}
/* Point at next table */
idxTableList = lpSqlNodeTableList->node.tables.Next;
}
}
}
/* Leave if no more records */
if (lpSqlNodeSelect->node.select.CurrentRow == AFTER_LAST_ROW)
break;
/* Put in the record number */
wsprintf((LPSTR) szBuffer, (LPSTR) szFormat,
(UWORD) lpSqlNodeSelect->node.select.CurrentRow);
CString myBuffer;
myBuffer.Format("WBEM ODBC Driver : Distinct : Record Number = %s\n", szBuffer);
ODBCTRACE(myBuffer);
if (_lwrite_buffer(hfSortfile, (LPSTR) szBuffer, NUM_LEN) != NUM_LEN) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Put the columns in the sort file in the order specified by the */
/* select list. For each value... */
idxValues = lpSqlNodeSelect->node.select.Values;
fGotOne = FALSE;
while (idxValues != NO_SQLNODE) {
/* Get next column */
lpSqlNodeValues = ToNode(lpstmt->lpSqlStmt, idxValues);
lpSqlNodeValue = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeValues->node.values.Value);
/* Does the value need to be put in the file? */
switch (lpSqlNodeValue->sqlNodeType) {
case NODE_TYPE_COLUMN:
case NODE_TYPE_AGGREGATE:
case NODE_TYPE_ALGEBRAIC:
case NODE_TYPE_SCALAR:
/* Yes. Continue below */
fGotOne = TRUE;
break;
case NODE_TYPE_STRING:
case NODE_TYPE_NUMERIC:
case NODE_TYPE_PARAMETER:
case NODE_TYPE_USER:
case NODE_TYPE_NULL:
case NODE_TYPE_DATE:
case NODE_TYPE_TIME:
case NODE_TYPE_TIMESTAMP:
/* No. Go to next value */
idxValues = lpSqlNodeValues->node.values.Next;
continue;
case NODE_TYPE_CREATE:
case NODE_TYPE_DROP:
case NODE_TYPE_SELECT:
case NODE_TYPE_INSERT:
case NODE_TYPE_DELETE:
case NODE_TYPE_UPDATE:
case NODE_TYPE_CREATEINDEX:
case NODE_TYPE_DROPINDEX:
case NODE_TYPE_PASSTHROUGH:
case NODE_TYPE_TABLES:
case NODE_TYPE_VALUES:
case NODE_TYPE_COLUMNS:
case NODE_TYPE_SORTCOLUMNS:
case NODE_TYPE_GROUPBYCOLUMNS:
case NODE_TYPE_UPDATEVALUES:
case NODE_TYPE_CREATECOLS:
case NODE_TYPE_BOOLEAN:
case NODE_TYPE_COMPARISON:
case NODE_TYPE_TABLE:
default:
return ERR_INTERNAL;
}
/* Get its value */
err = EvaluateExpression(lpstmt, lpSqlNodeValue);
if (err != ERR_SUCCESS) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* Get length and pointer to key value */
switch (lpSqlNodeValue->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (lpSqlNodeValue->sqlIsNull)
lpSqlNodeValue->value.Double = 0.0;
len = sizeof(double);
ptr = &(lpSqlNodeValue->value.Double);
break;
case TYPE_NUMERIC:
if (lpSqlNodeValue->sqlIsNull)
(lpSqlNodeValue->value.String)[0] = 0;
len = lpSqlNodeValue->sqlPrecision + 2;
ptr = lpSqlNodeValue->value.String;
/* (blank pad string values) */
while (s_lstrlen(lpSqlNodeValue->value.String) < len)
s_lstrcat(lpSqlNodeValue->value.String, " ");
break;
case TYPE_CHAR:
if (lpSqlNodeValue->sqlIsNull)
(lpSqlNodeValue->value.String)[0] = 0;
len = lpSqlNodeValue->sqlPrecision;
ptr = lpSqlNodeValue->value.String;
ODBCTRACE(_T("\nWBEM ODBC Driver : Distinct : String = "));
if ((LPSTR)ptr)
{
ODBCTRACE((LPSTR)ptr);
CString myString;
myString.Format(" length = %ld\n", s_lstrlen((LPSTR)ptr));
ODBCTRACE(myString);
}
else
{
ODBCTRACE(_T("NULL\n"));
}
/* (blank pad string values) */
while (s_lstrlen(lpSqlNodeValue->value.String) < len)
s_lstrcat(lpSqlNodeValue->value.String, " ");
break;
case TYPE_BINARY:
if (lpSqlNodeValue->sqlIsNull)
BINARY_LENGTH(lpSqlNodeValue->value.Binary) = 0;
len = lpSqlNodeValue->sqlPrecision;
ptr = BINARY_DATA(lpSqlNodeValue->value.Binary);
/* (zero pad binary values) */
while (BINARY_LENGTH(lpSqlNodeValue->value.Binary) < len) {
BINARY_DATA(lpSqlNodeValue->value.Binary)[
BINARY_LENGTH(lpSqlNodeValue->value.Binary)] = 0;
BINARY_LENGTH(lpSqlNodeValue->value.Binary) =
BINARY_LENGTH(lpSqlNodeValue->value.Binary) + 1;
}
break;
case TYPE_DATE:
if (lpSqlNodeValue->sqlIsNull) {
lpSqlNodeValue->value.Date.year = 0;
lpSqlNodeValue->value.Date.month = 0;
lpSqlNodeValue->value.Date.day = 0;
}
DateToChar(&(lpSqlNodeValue->value.Date), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
case TYPE_TIME:
if (lpSqlNodeValue->sqlIsNull) {
lpSqlNodeValue->value.Time.hour = 0;
lpSqlNodeValue->value.Time.minute = 0;
lpSqlNodeValue->value.Time.second = 0;
}
TimeToChar(&(lpSqlNodeValue->value.Time), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
case TYPE_TIMESTAMP:
if (lpSqlNodeValue->sqlIsNull) {
lpSqlNodeValue->value.Timestamp.year = 0;
lpSqlNodeValue->value.Timestamp.month = 0;
lpSqlNodeValue->value.Timestamp.day = 0;
lpSqlNodeValue->value.Timestamp.hour = 0;
lpSqlNodeValue->value.Timestamp.minute = 0;
lpSqlNodeValue->value.Timestamp.second = 0;
lpSqlNodeValue->value.Timestamp.fraction = 0;
}
TimestampToChar(&(lpSqlNodeValue->value.Timestamp), (LPUSTR)szBuffer);
len = s_lstrlen((char*)szBuffer);
ptr = szBuffer;
break;
default:
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_INTERNAL;
}
/* Put value into the file */
if (_lwrite_buffer(hfSortfile, (LPSTR) ptr, (UINT) len) != (UINT) len) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Put in the null flag */
if (lpSqlNodeValue->sqlIsNull)
cNullFlag = NULL_FLAG;
else
cNullFlag = NOT_NULL_FLAG;
if (_lwrite_buffer(hfSortfile, (LPSTR) &cNullFlag, 1) != 1) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Point at next value */
idxValues = lpSqlNodeValues->node.values.Next;
}
/* If no fields in sort record, put a constant in */
if (!fGotOne) {
if (_lwrite_buffer(hfSortfile, "LEM", 3) != 3) {
_lclose_buffer(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
}
}
if (_lclose_buffer(hfSortfile) == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
/* Create a destination file */
#ifdef WIN32
if (!GetTempFileName((LPSTR) szTempDir, "LEM", 0, (LPSTR) szFilename2)) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szFilename2);
#endif
hfSortfile2 = _lcreat((LPCSTR) szFilename2, 0);
if (hfSortfile2 == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
_lclose(hfSortfile2);
/* Sort the file */
s_1mains((LPSTR) szFilename, (LPSTR) szFilename2, (LPSTR)
ToString(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.DistinctDirective),
&recordCount, &sortStatus);
if (sortStatus != 0) {
DeleteFile((LPCSTR) szFilename2);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
DeleteFile((LPCSTR) szFilename);
/* Sort the file again (to put the values back into the original order) */
if (lpSqlNodeSelect->node.select.Sortcolumns != NO_SQLNODE) {
#ifdef WIN32
if (szTempDir[s_lstrlen(szTempDir)-1] != '\\')
s_lstrcat(szTempDir, "\\");
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szTempDir);
while (szTempDir[s_lstrlen(szTempDir)-1] != '\\')
szTempDir[s_lstrlen(szTempDir)-1] = '\0';
#endif
wsprintf((LPSTR) szSortDirective, "S(1,%d,N,A)F(FIX,%d)W(%s)", (WORD) NUM_LEN,
(WORD) lpSqlNodeSelect->node.select.DistinctRecordsize,
(LPSTR) szTempDir);
s_1mains((LPSTR) szFilename2, (LPSTR) szFilename2,
(LPSTR) szSortDirective, &recordCount, &sortStatus);
if (sortStatus != 0) {
DeleteFile((LPCSTR) szFilename2);
return ERR_SORT;
}
}
lpSqlNodeSelect->node.select.RowCount = recordCount;
/* Open destination file */
hfSortfile2 = _lopen((LPCSTR) szFilename2, OF_READ);
if (hfSortfile2 == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename2);
return ERR_SORT;
}
/* Save name and handle to file of sorted records */
s_lstrcpy(ToString(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.SortfileName), szFilename2);
lpSqlNodeSelect->node.select.Sortfile = hfSortfile2;
lpSqlNodeSelect->node.select.ReturningDistinct = TRUE;
/* Set up to read first row */
lpSqlNodeSelect->node.select.CurrentRow = BEFORE_FIRST_ROW;
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC MSAccess(LPSTMT lpstmt, LPSQLNODE lpSqlNodeSelect,
SQLNODEIDX idxSelectStatement)
/* Evaluates optimized MSAccess statement */
{
// ODBCTRACE("\nWBEM ODBC Driver : MSAccess\n");
UCHAR szTempDir[MAX_PATHNAME_SIZE+1];
UCHAR szFilename[MAX_PATHNAME_SIZE+1];
UCHAR szFilename2[MAX_PATHNAME_SIZE+1];
HFILE hfSortfile;
LPSQLNODE lpSqlNodeTables;
LPSQLNODE lpSqlNodeTable;
LPSQLNODE lpSqlNodePredicate;
LPSQLNODE lpSqlNodeKeycondition;
SQLNODEIDX idxPredicate;
SQLNODEIDX idxKeycondition;
RETCODE err;
ISAMBOOKMARK bookmark;
long recordCount;
int sortStatus;
#define NUM_LEN 5
UCHAR szFormat[16];
UCHAR szBuffer[NUM_LEN+1];
UCHAR szSortDirective[64 + 3 + MAX_PATHNAME_SIZE];
/* Create temporary file */
#ifdef WIN32
if (!GetTempPath(MAX_PATHNAME_SIZE+1, (LPSTR) szTempDir))
return ERR_SORT;
if (!GetTempFileName((LPSTR) szTempDir, "LEM", 0, (LPSTR) szFilename))
return ERR_SORT;
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szFilename);
#endif
hfSortfile = _lcreat((LPCSTR) szFilename, 0);
if (hfSortfile == HFILE_ERROR)
return ERR_SORT;
/* Get the table and predicate node. */
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.Tables);
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt, lpSqlNodeTables->node.tables.Table);
lpSqlNodePredicate = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.Predicate);
/* For each of the key conditions...*/
wsprintf((LPSTR) szFormat, "%%0%dd", (UWORD) NUM_LEN);
lpSqlNodeSelect->node.select.RowCount = 0;
while (lpSqlNodePredicate != NULL) {
/* Get the next key condition */
if ((lpSqlNodePredicate->sqlNodeType == NODE_TYPE_BOOLEAN) &&
(lpSqlNodePredicate->node.boolean.Operator == OP_OR)) {
idxKeycondition = lpSqlNodePredicate->node.boolean.Left;
lpSqlNodeKeycondition = ToNode(lpstmt->lpSqlStmt,
idxKeycondition);
idxPredicate = lpSqlNodePredicate->node.boolean.Right;
lpSqlNodePredicate = ToNode(lpstmt->lpSqlStmt, idxPredicate);
}
else {
idxKeycondition = idxPredicate;
lpSqlNodeKeycondition = lpSqlNodePredicate;
idxPredicate = NO_SQLNODE;
lpSqlNodePredicate = NULL;
}
/* Set the optimization predicate */
lpSqlNodeTable->node.table.cRestrict = 0;
lpSqlNodeTable->node.table.Restrict = NO_SQLNODE;
err = FindRestriction(lpstmt->lpSqlStmt,
ISAMCaseSensitive(lpstmt->lpdbc->lpISAM),
lpSqlNodeTable, idxKeycondition, idxSelectStatement,
&(lpSqlNodeTable->node.table.cRestrict),
&(lpSqlNodeTable->node.table.Restrict));
if (err != ERR_SUCCESS) {
lpSqlNodeTable->node.table.cRestrict = 0;
lpSqlNodeTable->node.table.Restrict = NO_SQLNODE;
return err;
}
/* Rewind the table */
err = Rewind(lpstmt, lpSqlNodeTable, FALSE);
if (err != ERR_SUCCESS) {
lpSqlNodeTable->node.table.cRestrict = 0;
lpSqlNodeTable->node.table.Restrict = NO_SQLNODE;
return err;
}
/* Clear the optimization predicate */
lpSqlNodeTable->node.table.cRestrict = 0;
lpSqlNodeTable->node.table.Restrict = NO_SQLNODE;
/* Set up to read first row */
lpSqlNodeSelect->node.select.CurrentRow = BEFORE_FIRST_ROW;
/* For each record of result set... */
while (TRUE) {
/* Get the next record */
err = NextRecord(lpstmt, lpSqlNodeTables,
lpSqlNodeKeycondition);
if (err == ERR_NODATAFOUND)
break;
else if (err != ERR_SUCCESS) {
_lclose(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
/* Set row flag */
if (lpSqlNodeSelect->node.select.CurrentRow == BEFORE_FIRST_ROW)
lpSqlNodeSelect->node.select.CurrentRow = 0;
else
lpSqlNodeSelect->node.select.CurrentRow++;
/* Increase row count */
(lpSqlNodeSelect->node.select.RowCount)++;
/* Get bookmark of current record */
if (lpSqlNodeTable->node.table.AllNull)
{
bookmark.currentRecord = NULL_BOOKMARK;
}
else
{
err = ISAMGetBookmark(lpSqlNodeTable->node.table.Handle, &bookmark);
if (err != ERR_SUCCESS) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
_lclose(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
}
/* Put value into the file */
wsprintf((LPSTR) szBuffer, (LPSTR) szFormat,
(UWORD) lpSqlNodeSelect->node.select.RowCount);
if (_lwrite(hfSortfile, (LPSTR) szBuffer, NUM_LEN) != NUM_LEN) {
_lclose(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
if (_lwrite(hfSortfile, (LPSTR) &bookmark, sizeof(ISAMBOOKMARK))
!= sizeof(ISAMBOOKMARK)) {
_lclose(hfSortfile);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
}
}
if (lpSqlNodeSelect->node.select.RowCount == 0) {
_lclose(hfSortfile);
DeleteFile((LPCSTR) szFilename);
lpSqlNodeSelect->node.select.CurrentRow = AFTER_LAST_ROW;
return ERR_SUCCESS;
}
_lclose(hfSortfile);
/* Create a destination file */
#ifdef WIN32
if (!GetTempFileName((LPSTR) szTempDir, "LEM", 0, (LPSTR) szFilename2)) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szFilename2);
#endif
hfSortfile = _lcreat((LPCSTR) szFilename2, 0);
if (hfSortfile == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
_lclose(hfSortfile);
/* Get name of workspace directory */
#ifdef WIN32
if (szTempDir[s_lstrlen(szTempDir)-1] != '\\')
s_lstrcat(szTempDir, "\\");
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szTempDir);
while (szTempDir[s_lstrlen(szTempDir)-1] != '\\')
szTempDir[s_lstrlen(szTempDir)-1] = '\0';
#endif
/* Sort the file and remove duplicate bookmarks */
wsprintf((LPSTR) szSortDirective, "S(%d,%d,W,A)DUPO(B%d,%d,%d)F(FIX,%d)W(%s)",
(WORD) NUM_LEN+1, (WORD) sizeof(ISAMBOOKMARK),
(WORD) (sizeof(ISAMBOOKMARK) + NUM_LEN), (WORD) NUM_LEN+1,
(WORD) sizeof(ISAMBOOKMARK),
(WORD) (sizeof(ISAMBOOKMARK) + NUM_LEN),
(LPSTR) szTempDir);
s_1mains((LPSTR) szFilename, (LPSTR) szFilename2,
(LPSTR) szSortDirective, &recordCount, &sortStatus);
if (sortStatus != 0) {
DeleteFile((LPCSTR) szFilename2);
DeleteFile((LPCSTR) szFilename);
return ERR_SORT;
}
DeleteFile((LPCSTR) szFilename);
/* Sort the file again (to put the values back into the original order) */
wsprintf((LPSTR) szSortDirective, "S(1,%d,N,A)F(FIX,%d)W(%s)", (WORD) NUM_LEN,
(WORD) (sizeof(ISAMBOOKMARK) + NUM_LEN),
(LPSTR) szTempDir);
s_1mains((LPSTR) szFilename2, (LPSTR) szFilename2,
(LPSTR) szSortDirective, &recordCount, &sortStatus);
if (sortStatus != 0) {
DeleteFile((LPCSTR) szFilename2);
return ERR_SORT;
}
lpSqlNodeSelect->node.select.RowCount = recordCount;
/* Open destination file */
hfSortfile = _lopen((LPCSTR) szFilename2, OF_READ);
if (hfSortfile == HFILE_ERROR) {
DeleteFile((LPCSTR) szFilename2);
return ERR_SORT;
}
/* Save name and handle to file of records found */
s_lstrcpy(ToString(lpstmt->lpSqlStmt,
lpSqlNodeSelect->node.select.SortfileName), szFilename2);
lpSqlNodeSelect->node.select.Sortfile = hfSortfile;
/* Set up to read first row */
lpSqlNodeSelect->node.select.CurrentRow = BEFORE_FIRST_ROW;
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC ExecuteQuery(LPSTMT lpstmt, LPSQLNODE lpSqlNode)
/* Executes the current query */
{
LPUSTR lpstrTablename;
LPUSTR lpstrColumnname;
LPISAMTABLEDEF lpISAMTableDef;
SWORD err;
SWORD finalErr;
SQLNODEIDX idxTables;
SQLNODEIDX idxSqlNodeColumns;
SQLNODEIDX idxSqlNodeValues;
SQLNODEIDX idxSqlNodeSets;
SQLNODEIDX idxSortcolumns;
SQLNODEIDX idxParameter;
LPSQLNODE lpSqlNodeTables;
LPSQLNODE lpSqlNodeTable;
LPSQLNODE lpSqlNodeColumns;
LPSQLNODE lpSqlNodeColumn;
LPSQLNODE lpSqlNodeValues;
LPSQLNODE lpSqlNodeValue;
LPSQLNODE lpSqlNodePredicate;
LPSQLNODE lpSqlNodeSets;
LPSQLNODE lpSqlNodeSortcolumns;
LPSQLNODE lpSqlNodeParameter;
LPSQLNODE lpSqlNodeSelect;
UWORD idx;
BOOL fSelect;
BOOL fSubSelect;
// ODBCTRACE ("\nWBEM ODBC Driver : ExecuteQuery\n");
/* Nested sub-select? */
if (lpSqlNode == NULL) {
/* No. Count of rows is not available */
fSubSelect = FALSE;
lpstmt->cRowCount = -1;
/* If there are passthrough parameters, send them now */
lpSqlNode = ToNode(lpstmt->lpSqlStmt, ROOT_SQLNODE);
if (lpSqlNode->node.root.passthroughParams) {
idxParameter = lpSqlNode->node.root.parameters;
while (idxParameter != NO_SQLNODE) {
lpSqlNodeParameter = ToNode(lpstmt->lpSqlStmt, idxParameter);
switch (lpSqlNodeParameter->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
err = ISAMParameter(lpstmt->lpISAMStatement,
lpSqlNodeParameter->node.parameter.Id,
SQL_C_DOUBLE,
&(lpSqlNodeParameter->value.Double),
lpSqlNodeParameter->sqlIsNull ? SQL_NULL_DATA :
sizeof(double));
break;
case TYPE_NUMERIC:
case TYPE_CHAR:
err = ISAMParameter(lpstmt->lpISAMStatement,
lpSqlNodeParameter->node.parameter.Id,
SQL_C_CHAR, lpSqlNodeParameter->value.String,
lpSqlNodeParameter->sqlIsNull ? SQL_NULL_DATA :
s_lstrlen(lpSqlNodeParameter->value.String));
break;
case TYPE_BINARY:
err = ISAMParameter(lpstmt->lpISAMStatement,
lpSqlNodeParameter->node.parameter.Id,
SQL_C_BINARY,
BINARY_DATA(lpSqlNodeParameter->value.Binary),
lpSqlNodeParameter->sqlIsNull ? SQL_NULL_DATA :
BINARY_LENGTH(lpSqlNodeParameter->value.Binary));
break;
case TYPE_DATE:
err = ISAMParameter(lpstmt->lpISAMStatement,
lpSqlNodeParameter->node.parameter.Id,
SQL_C_DATE, &(lpSqlNodeParameter->value.Date),
lpSqlNodeParameter->sqlIsNull ? SQL_NULL_DATA :
sizeof(DATE_STRUCT));
break;
case TYPE_TIME:
err = ISAMParameter(lpstmt->lpISAMStatement,
lpSqlNodeParameter->node.parameter.Id,
SQL_C_TIME, &(lpSqlNodeParameter->value.Time),
lpSqlNodeParameter->sqlIsNull ? SQL_NULL_DATA :
sizeof(TIME_STRUCT));
break;
case TYPE_TIMESTAMP:
err = ISAMParameter(lpstmt->lpISAMStatement,
lpSqlNodeParameter->node.parameter.Id,
SQL_C_TIMESTAMP,
&(lpSqlNodeParameter->value.Timestamp),
lpSqlNodeParameter->sqlIsNull ? SQL_NULL_DATA :
sizeof(TIMESTAMP_STRUCT));
break;
default:
return ERR_NOTSUPPORTED;
}
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
idxParameter = lpSqlNodeParameter->node.parameter.Next;
}
}
/* Get the root node of the operation */
lpSqlNode = ToNode(lpstmt->lpSqlStmt, ROOT_SQLNODE);
lpSqlNode = ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.root.sql);
}
else {
/* Yes. It is a sub-select */
fSubSelect = TRUE;
}
finalErr = ERR_SUCCESS;
fSelect = FALSE;
switch (lpSqlNode->sqlNodeType) {
/* Create a table */
case NODE_TYPE_CREATE:
/* Make sure this DDL statement is allowed now */
err = TxnCapableForDDL(lpstmt);
if (err == ERR_DDLIGNORED)
return ERR_DDLIGNORED;
else if (err == ERR_DDLCAUSEDACOMMIT)
finalErr = ERR_DDLCAUSEDACOMMIT;
else if (err != ERR_SUCCESS)
return err;
/* Find the table to create */
lpstrTablename = ToString(lpstmt->lpSqlStmt, lpSqlNode->node.create.Table);
/* Create the table */
err = ISAMCreateTable(lpstmt->lpdbc->lpISAM,
(LPUSTR) lpstrTablename, &lpISAMTableDef);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
return err;
}
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
/* Add the columns to the table */
lpSqlNode = ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.create.Columns);
while (TRUE) {
/* Error if wrong node type */
if (lpSqlNode->sqlNodeType != NODE_TYPE_CREATECOLS) {
ISAMCloseTable(lpISAMTableDef);
if (NO_ISAM_ERR ==
ISAMDeleteTable(lpstmt->lpdbc->lpISAM, (LPUSTR) lpstrTablename)) {
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
}
return ERR_INTERNAL;
}
/* Get column name */
lpstrColumnname = ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.createcols.Name);
/* Add the column to the table */
err = ISAMAddColumn(lpISAMTableDef, (LPUSTR) lpstrColumnname,
lpSqlNode->node.createcols.iSqlType,
lpSqlNode->node.createcols.Param1, lpSqlNode->node.createcols.Param2);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
ISAMCloseTable(lpISAMTableDef);
if (NO_ISAM_ERR ==
ISAMDeleteTable(lpstmt->lpdbc->lpISAM, (LPUSTR) lpstrTablename)) {
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
}
return err;
}
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
/* Find next column */
if (lpSqlNode->node.createcols.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.createcols.Next);
}
/* Close the table */
err = ISAMCloseTable(lpISAMTableDef);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
if (NO_ISAM_ERR ==
ISAMDeleteTable(lpstmt->lpdbc->lpISAM, (LPUSTR) lpstrTablename)) {
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
}
return err;
}
break;
/* Drop a table */
case NODE_TYPE_DROP:
/* Make sure this DDL statement is allowed now */
err = TxnCapableForDDL(lpstmt);
if (err == ERR_DDLIGNORED)
return ERR_DDLIGNORED;
else if (err == ERR_DDLCAUSEDACOMMIT)
finalErr = ERR_DDLCAUSEDACOMMIT;
else if (err != ERR_SUCCESS)
return err;
/* Find the table to drop */
lpstrTablename = ToString(lpstmt->lpSqlStmt, lpSqlNode->node.drop.Table);
/* Drop the table */
err = ISAMDeleteTable(lpstmt->lpdbc->lpISAM, (LPUSTR) lpstrTablename);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
return err;
}
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
break;
/* SELECT statement */
case NODE_TYPE_SELECT:
/* Is there a passthrough SQL statement? */
lpstmt->fDMLTxn = TRUE;
fSelect = TRUE;
if (!fSubSelect) {
if (lpstmt->lpISAMStatement != NULL) {
/* Yes. Execute it now */
err = ISAMExecute(lpstmt->lpISAMStatement,
&(lpSqlNode->node.select.RowCount));
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
}
else {
lpSqlNode->node.select.RowCount = -1;
}
}
/* Is there a pushdown sort? */
if ((lpSqlNode->node.select.Sortcolumns != NO_SQLNODE) &&
lpSqlNode->node.select.fPushdownSort) {
UWORD icol[MAX_COLUMNS_IN_ORDER_BY];
BOOL fDescending[MAX_COLUMNS_IN_ORDER_BY];
/* Yes. For each table... */
idxTables = lpSqlNode->node.select.Tables;
while (idxTables != NO_SQLNODE) {
/* If no pushdown sort for this table, leave the loop */
/* (since there will be no pushdowns for any of the */
/* subsequent tables either) */
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt, idxTables);
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeTables->node.tables.Table);
if (lpSqlNodeTable->node.table.Sortcount == 0)
break;
/* Create sort info arrays. For each column in sequence... */
idxSortcolumns = lpSqlNodeTable->node.table.Sortcolumns;
for (idx = 0; idx < lpSqlNodeTable->node.table.Sortcount; idx++) {
/* Get the column description */
lpSqlNodeSortcolumns = ToNode(lpstmt->lpSqlStmt,
idxSortcolumns);
lpSqlNodeColumn = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSortcolumns->node.sortcolumns.Column);
/* Put information into the array */
icol[idx] = lpSqlNodeColumn->node.column.Id;
fDescending[idx] =
lpSqlNodeSortcolumns->node.sortcolumns.Descending;
/* Look at next column */
idxSortcolumns = lpSqlNodeSortcolumns->node.sortcolumns.Next;
}
/* Get the records in sorted order */
err = ISAMSort(lpSqlNodeTable->node.table.Handle,
lpSqlNodeTable->node.table.Sortcount,
icol, fDescending);
/* Can this sort be pushed down? */
if (err == ISAM_NOTSUPPORTED) {
/* No. Turn off all the sorts */
idxTables = lpSqlNode->node.select.Tables;
while (idxTables != NO_SQLNODE) {
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt, idxTables);
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeTables->node.tables.Table);
if (lpSqlNodeTable->node.table.Sortcount == 0)
break;
err = ISAMSort(lpSqlNodeTable->node.table.Handle, 0,
icol, fDescending);
if ((err != NO_ISAM_ERR) &&
(err != ISAM_NOTSUPPORTED)) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
if (err == NO_ISAM_ERR)
lpstmt->fISAMTxnStarted = TRUE;
idxTables = lpSqlNodeTables->node.tables.Next;
}
/* Don't try to do pushdown sort again */
lpSqlNode->node.select.fPushdownSort = FALSE;
/* Leave this loop */
break;
}
else if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
else
lpstmt->fISAMTxnStarted = TRUE;
/* Look at next table */
idxTables = lpSqlNodeTables->node.tables.Next;
}
}
/* Rewind the tables */
lpSqlNodeTables = ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.select.Tables);
err = Rewind(lpstmt, lpSqlNodeTables, FALSE);
if (err == ERR_NODATAFOUND) {
if (!fSubSelect) {
lpstmt->fStmtType = STMT_TYPE_SELECT;
lpstmt->fStmtSubtype = STMT_SUBTYPE_NONE;
lpstmt->cRowCount = 0;
}
lpSqlNode->node.select.RowCount = 0;
lpSqlNode->node.select.CurrentRow = AFTER_LAST_ROW;
if (!fSubSelect) {
lpstmt->icol = NO_COLUMN;
lpstmt->cbOffset = 0;
}
break;
}
else if (err != ERR_SUCCESS)
return err;
/* Show a SELECT statement as the active statement */
if (!fSubSelect) {
lpstmt->fStmtType = STMT_TYPE_SELECT;
lpstmt->fStmtSubtype = STMT_SUBTYPE_NONE;
}
/* So far no data read */
lpSqlNode->node.select.CurrentRow = BEFORE_FIRST_ROW;
/* So far no column read */
if (!fSubSelect) {
lpstmt->icol = NO_COLUMN;
lpstmt->cbOffset = 0;
}
/* Is a sort needed? */
if (((lpSqlNode->node.select.Sortcolumns != NO_SQLNODE) ||
(lpSqlNode->node.select.ImplicitGroupby)) &&
(!lpSqlNode->node.select.fPushdownSort)) {
/* Yes. Do it */
err = Sort(lpstmt, lpSqlNode);
if (err != ERR_SUCCESS)
return err;
}
/* Is group by needed? */
if ((lpSqlNode->node.select.Groupbycolumns != NO_SQLNODE) ||
(lpSqlNode->node.select.ImplicitGroupby)) {
/* Yes. Do it */
err = GroupBy(lpstmt, lpSqlNode);
if (err != ERR_SUCCESS) {
if (lpSqlNode->node.select.Sortfile != HFILE_ERROR) {
_lclose(lpSqlNode->node.select.Sortfile);
lpSqlNode->node.select.Sortfile = HFILE_ERROR;
lpSqlNode->node.select.ReturningDistinct = FALSE;
DeleteFile((LPCSTR) ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.select.SortfileName));
s_lstrcpy(ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.select.SortfileName), "");
}
return err;
}
}
/* Is DISTINCT specified? */
if (lpSqlNode->node.select.Distinct) {
/* Yes. Do it */
err = Distinct(lpstmt, lpSqlNode);
if (err != ERR_SUCCESS) {
if (lpSqlNode->node.select.Sortfile != HFILE_ERROR) {
_lclose(lpSqlNode->node.select.Sortfile);
lpSqlNode->node.select.Sortfile = HFILE_ERROR;
lpSqlNode->node.select.ReturningDistinct = FALSE;
DeleteFile((LPCSTR) ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.select.SortfileName));
s_lstrcpy(ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.select.SortfileName), "");
}
return err;
}
}
/* MSAccess optimization needed? */
if (lpSqlNode->node.select.fMSAccess) {
/* Yes. Do it */
err = MSAccess(lpstmt, lpSqlNode,
ToNode(lpstmt->lpSqlStmt, ROOT_SQLNODE)->node.root.sql);
if (err != ERR_SUCCESS) {
if (lpSqlNode->node.select.Sortfile != HFILE_ERROR) {
_lclose(lpSqlNode->node.select.Sortfile);
lpSqlNode->node.select.Sortfile = HFILE_ERROR;
lpSqlNode->node.select.ReturningDistinct = FALSE;
DeleteFile((LPCSTR) ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.select.SortfileName));
s_lstrcpy(ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.select.SortfileName), "");
}
return err;
}
}
/* Return the row count */
if (!fSubSelect) {
lpstmt->cRowCount = lpSqlNode->node.select.RowCount;
}
break;
/* INSERT statement */
case NODE_TYPE_INSERT:
{
/* Sub-select? */
lpSqlNodeSelect = ToNode(lpstmt->lpSqlStmt,
lpSqlNode->node.insert.Values);
if (lpSqlNodeSelect->sqlNodeType == NODE_TYPE_SELECT) {
err = ExecuteQuery(lpstmt, lpSqlNodeSelect);
if (err == ERR_DATATRUNCATED) {
finalErr = ERR_DATATRUNCATED;
err = ERR_SUCCESS;
}
if ((err != ERR_SUCCESS) && (err != ERR_NODATAFOUND))
return err;
}
else
lpSqlNodeSelect = NULL;
/* Insert rows into the table */
lpstmt->cRowCount = 0;
while (TRUE) {
/* Get next row to insert */
if (lpSqlNodeSelect != NULL) {
if (err == ERR_SUCCESS) {
// ODBCTRACE("\nWBEM ODBC Driver : Get next row to insert\n");
err = FetchRow(lpstmt, lpSqlNodeSelect);
if ((err != ERR_SUCCESS) && (err != ERR_NODATAFOUND))
return err;
}
/* Leave if no more rows */
if (err == ERR_NODATAFOUND)
break;
/* Get list of values */
idxSqlNodeValues = lpSqlNodeSelect->node.select.Values;
}
else {
idxSqlNodeValues = lpSqlNode->node.insert.Values;
}
/* Add a row to the table. */
lpstmt->fDMLTxn = TRUE;
lpSqlNodeTable =
ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.insert.Table);
lpISAMTableDef = lpSqlNodeTable->node.table.Handle;
err = ISAMInsertRecord(lpISAMTableDef);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
/* Evaluate each column value and copy it into the new record. */
idxSqlNodeColumns = lpSqlNode->node.insert.Columns;
while (idxSqlNodeColumns != NO_SQLNODE) {
lpSqlNodeColumns = ToNode(lpstmt->lpSqlStmt, idxSqlNodeColumns);
lpSqlNodeColumn = ToNode(lpstmt->lpSqlStmt, lpSqlNodeColumns->node.columns.Column);
lpSqlNodeValues = ToNode(lpstmt->lpSqlStmt, idxSqlNodeValues);
lpSqlNodeValue = ToNode(lpstmt->lpSqlStmt, lpSqlNodeValues->node.values.Value);
err = EvaluateExpression(lpstmt, lpSqlNodeValue);
if (err != ERR_SUCCESS) {
if (ERR_SUCCESS == ISAMDeleteRecord(lpISAMTableDef))
lpstmt->fISAMTxnStarted = TRUE;
return err;
}
switch (lpSqlNodeColumn->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
{
switch (lpSqlNodeValue->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
lpSqlNodeColumn->value.Double =
lpSqlNodeValue->value.Double;
break;
case TYPE_NUMERIC:
if (!(lpSqlNodeValue->sqlIsNull))
CharToDouble(lpSqlNodeValue->value.String,
s_lstrlen(lpSqlNodeValue->value.String), FALSE,
-1.7E308, 1.7E308,
&(lpSqlNodeColumn->value.Double));
else
lpSqlNodeColumn->value.Double = 0.0;
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
default:
return ERR_INTERNAL;
}
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_DOUBLE,
&(lpSqlNodeColumn->value.Double),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(double));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
}
break;
case TYPE_NUMERIC:
{
lpSqlNodeColumn->value.String = ToString(lpstmt->lpSqlStmt,
lpSqlNodeColumn->node.column.Value);
switch (lpSqlNodeValue->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (!(lpSqlNodeValue->sqlIsNull)) {
if (DoubleToChar(lpSqlNodeValue->value.Double,
FALSE, lpSqlNodeColumn->value.String,
1 + 2 + lpSqlNodeColumn->sqlPrecision)) {
lpSqlNodeColumn->value.String[1 + 2 +
lpSqlNodeColumn->sqlPrecision - 1] = '\0';
finalErr = ERR_DATATRUNCATED;
}
}
else
s_lstrcpy(lpSqlNodeColumn->value.String, "0");
break;
case TYPE_NUMERIC:
s_lstrcpy(lpSqlNodeColumn->value.String,
lpSqlNodeValue->value.String);
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
default:
return ERR_INTERNAL;
}
err = BCDNormalize(lpSqlNodeColumn->value.String,
s_lstrlen(lpSqlNodeColumn->value.String),
lpSqlNodeColumn->value.String,
1 + 2 + lpSqlNodeColumn->sqlPrecision,
lpSqlNodeColumn->sqlPrecision,
lpSqlNodeColumn->sqlScale);
if (err == ERR_DATATRUNCATED) {
finalErr = ERR_DATATRUNCATED;
err = ERR_SUCCESS;
}
if (err == ERR_SUCCESS) {
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_CHAR,
lpSqlNodeColumn->value.String,
lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
s_lstrlen(lpSqlNodeColumn->value.String));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
}
}
break;
case TYPE_CHAR:
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id,
SQL_C_CHAR, lpSqlNodeValue->value.String,
lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
s_lstrlen(lpSqlNodeValue->value.String));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_BINARY:
err = ISAMPutData(lpISAMTableDef, lpSqlNodeColumn->node.column.Id,
SQL_C_BINARY, BINARY_DATA(lpSqlNodeValue->value.Binary),
lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
BINARY_LENGTH(lpSqlNodeValue->value.Binary));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_DATE:
err = ISAMPutData(lpISAMTableDef, lpSqlNodeColumn->node.column.Id,
SQL_C_DATE, &(lpSqlNodeValue->value.Date),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(DATE_STRUCT));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_TIME:
err = ISAMPutData(lpISAMTableDef, lpSqlNodeColumn->node.column.Id,
SQL_C_TIME, &(lpSqlNodeValue->value.Time),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(TIME_STRUCT));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_TIMESTAMP:
err = ISAMPutData(lpISAMTableDef, lpSqlNodeColumn->node.column.Id,
SQL_C_TIMESTAMP, &(lpSqlNodeValue->value.Timestamp),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(TIMESTAMP_STRUCT));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
default:
err = ERR_INTERNAL;
}
if (err == ISAM_TRUNCATION) {
finalErr = ERR_DATATRUNCATED;
err = NO_ISAM_ERR;
}
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
if (ERR_SUCCESS == ISAMDeleteRecord(lpISAMTableDef))
lpstmt->fISAMTxnStarted = TRUE;
return err;
}
idxSqlNodeColumns = lpSqlNodeColumns->node.columns.Next;
idxSqlNodeValues = lpSqlNodeValues->node.values.Next;
}
/* Write the updated row to the table. */
err = ISAMUpdateRecord(lpISAMTableDef);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
if (ERR_SUCCESS == ISAMDeleteRecord(lpISAMTableDef))
lpstmt->fISAMTxnStarted = TRUE;
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
/* Increment row count */
lpstmt->cRowCount++;
/* Leave if just inserting a single row */
if (lpSqlNodeSelect == NULL)
break;
}
}
break;
/* DELETE statement */
case NODE_TYPE_DELETE:
{
/* Get the table handle and predicate node. */
lpstmt->fDMLTxn = TRUE;
lpSqlNodeTable = ToNode (lpstmt->lpSqlStmt, lpSqlNode->node.delet.Table);
lpISAMTableDef = lpSqlNodeTable->node.table.Handle;
if (lpSqlNode->node.delet.Predicate == NO_SQLNODE)
lpSqlNodePredicate = NULL;
else
lpSqlNodePredicate = ToNode(lpstmt->lpSqlStmt,
lpSqlNode->node.delet.Predicate);
/* Rewind the table */
err = Rewind(lpstmt, lpSqlNodeTable, FALSE);
if (err != ERR_SUCCESS)
return err;
/* Delete each record that satisfies the WHERE clause. */
lpstmt->cRowCount = 0;
while (TRUE) {
/* Get next record */
err = NextRecord(lpstmt, lpSqlNodeTable,
lpSqlNodePredicate);
if (err == ERR_NODATAFOUND)
break;
else if (err != ERR_SUCCESS)
return err;
/* Delete record */
err = ISAMDeleteRecord(lpISAMTableDef);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
/* Increase count */
(lpstmt->cRowCount)++;
}
}
break;
/* UPDATE statement */
case NODE_TYPE_UPDATE:
{
/* Get the table handle, predicate node. */
lpstmt->fDMLTxn = TRUE;
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt, lpSqlNode->node.update.Table);
lpISAMTableDef = lpSqlNodeTable->node.table.Handle;
if (lpSqlNode->node.update.Predicate == NO_SQLNODE)
lpSqlNodePredicate = NULL;
else
lpSqlNodePredicate = ToNode(lpstmt->lpSqlStmt,
lpSqlNode->node.update.Predicate);
/* Rewind the table */
err = Rewind(lpstmt, lpSqlNodeTable, FALSE);
if (err != ERR_SUCCESS)
return err;
/* Update each record that satisfies the WHERE clause. */
lpstmt->cRowCount = 0;
while (TRUE) {
/* Get next record */
err = NextRecord(lpstmt, lpSqlNodeTable,
lpSqlNodePredicate);
if (err == ERR_NODATAFOUND)
break;
else if (err != ERR_SUCCESS)
return err;
/* For each set column... */
idxSqlNodeSets = lpSqlNode->node.update.Updatevalues;
while (idxSqlNodeSets != NO_SQLNODE) {
/* Get the column */
lpSqlNodeSets = ToNode(lpstmt->lpSqlStmt, idxSqlNodeSets);
lpSqlNodeColumn = ToNode(lpstmt->lpSqlStmt, lpSqlNodeSets->node.updatevalues.Column);
/* Get the value to set the column to */
lpSqlNodeValue = ToNode(lpstmt->lpSqlStmt, lpSqlNodeSets->node.updatevalues.Value);
err = EvaluateExpression(lpstmt, lpSqlNodeValue);
if (err != ERR_SUCCESS)
return err;
/* Put the data into the record */
switch (lpSqlNodeColumn->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
switch (lpSqlNodeValue->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
lpSqlNodeColumn->value.Double =
lpSqlNodeValue->value.Double;
break;
case TYPE_NUMERIC:
if (!(lpSqlNodeValue->sqlIsNull))
CharToDouble(lpSqlNodeValue->value.String,
s_lstrlen(lpSqlNodeValue->value.String), FALSE,
-1.7E308, 1.7E308,
&(lpSqlNodeColumn->value.Double));
else
lpSqlNodeColumn->value.Double = 0.0;
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
default:
return ERR_INTERNAL;
}
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_DOUBLE,
&(lpSqlNodeColumn->value.Double),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(double));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_NUMERIC:
lpSqlNodeColumn->value.String =ToString(lpstmt->lpSqlStmt,
lpSqlNodeColumn->node.column.Value);
switch (lpSqlNodeValue->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
if (!(lpSqlNodeValue->sqlIsNull)) {
if (DoubleToChar(lpSqlNodeValue->value.Double,
FALSE, lpSqlNodeColumn->value.String,
1 + 2 + lpSqlNodeColumn->sqlPrecision)) {
lpSqlNodeColumn->value.String[
1+2+lpSqlNodeColumn->sqlPrecision-1]='\0';
finalErr = ERR_DATATRUNCATED;
}
}
else
s_lstrcpy(lpSqlNodeColumn->value.String, "0");
break;
case TYPE_NUMERIC:
s_lstrcpy(lpSqlNodeColumn->value.String,
lpSqlNodeValue->value.String);
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
default:
return ERR_INTERNAL;
}
err = BCDNormalize(lpSqlNodeColumn->value.String,
s_lstrlen(lpSqlNodeColumn->value.String),
lpSqlNodeColumn->value.String,
1 + 2 + lpSqlNodeColumn->sqlPrecision,
lpSqlNodeColumn->sqlPrecision,
lpSqlNodeColumn->sqlScale);
if (err == ERR_DATATRUNCATED) {
finalErr = ERR_DATATRUNCATED;
err = ERR_SUCCESS;
}
if (err == ERR_SUCCESS) {
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_CHAR,
lpSqlNodeColumn->value.String,
lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
s_lstrlen(lpSqlNodeColumn->value.String));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
}
break;
case TYPE_CHAR:
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_CHAR,
lpSqlNodeValue->value.String,
lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
s_lstrlen(lpSqlNodeValue->value.String));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_BINARY:
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_BINARY,
BINARY_DATA(lpSqlNodeValue->value.Binary),
lpSqlNodeValue->sqlIsNull ? SQL_NULL_DATA :
BINARY_LENGTH(lpSqlNodeValue->value.Binary));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_DATE:
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_DATE,
&(lpSqlNodeValue->value.Date),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(DATE_STRUCT));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_TIME:
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_TIME,
&(lpSqlNodeValue->value.Time),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(TIME_STRUCT));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
case TYPE_TIMESTAMP:
err = ISAMPutData(lpISAMTableDef,
lpSqlNodeColumn->node.column.Id, SQL_C_TIMESTAMP,
&(lpSqlNodeValue->value.Timestamp),
lpSqlNodeValue->sqlIsNull ?
(SDWORD) SQL_NULL_DATA : sizeof(TIMESTAMP_STRUCT));
if ((err == NO_ISAM_ERR) || (err == ISAM_TRUNCATION))
lpstmt->fISAMTxnStarted = TRUE;
break;
default:
return ERR_INTERNAL;
}
if (err == ISAM_TRUNCATION) {
finalErr = ERR_DATATRUNCATED;
err = NO_ISAM_ERR;
}
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
idxSqlNodeSets = lpSqlNodeSets->node.updatevalues.Next;
}
/* Write the updated row to the table. */
err = ISAMUpdateRecord (lpISAMTableDef);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
/* Increase count */
(lpstmt->cRowCount)++;
}
}
break;
case NODE_TYPE_CREATEINDEX:
{
UWORD icol[MAX_COLUMNS_IN_INDEX];
BOOL fDescending[MAX_COLUMNS_IN_INDEX];
UWORD count;
/* Make sure this DDL statement is allowed now */
err = TxnCapableForDDL(lpstmt);
if (err == ERR_DDLIGNORED)
return ERR_DDLIGNORED;
else if (err == ERR_DDLCAUSEDACOMMIT)
finalErr = ERR_DDLCAUSEDACOMMIT;
else if (err != ERR_SUCCESS)
return err;
/* Get handle to table */
lpSqlNodeTable = ToNode(lpstmt->lpSqlStmt,
lpSqlNode->node.createindex.Table);
lpISAMTableDef = lpSqlNodeTable->node.table.Handle;
/* Get definition of the index */
idxSortcolumns = lpSqlNode->node.createindex.Columns;
count = 0;
while (idxSortcolumns != NO_SQLNODE) {
lpSqlNodeSortcolumns =
ToNode(lpstmt->lpSqlStmt, idxSortcolumns);
lpSqlNodeColumn = ToNode(lpstmt->lpSqlStmt,
lpSqlNodeSortcolumns->node.sortcolumns.Column);
icol[count] = lpSqlNodeColumn->node.column.Id;
fDescending[count] =
lpSqlNodeSortcolumns->node.sortcolumns.Descending;
count++;
idxSortcolumns = lpSqlNodeSortcolumns->node.sortcolumns.Next;
}
/* Create the index */
err = ISAMCreateIndex(lpISAMTableDef,
ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.createindex.Index),
lpSqlNode->node.createindex.Unique,
count, icol, fDescending);
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM,
(LPUSTR) lpstmt->szISAMError);
return err;
}
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
}
break;
case NODE_TYPE_DROPINDEX:
/* Make sure this DDL statement is allowed now */
err = TxnCapableForDDL(lpstmt);
if (err == ERR_DDLIGNORED)
return ERR_DDLIGNORED;
else if (err == ERR_DDLCAUSEDACOMMIT)
finalErr = ERR_DDLCAUSEDACOMMIT;
else if (err != ERR_SUCCESS)
return err;
/* Delete the index */
err = ISAMDeleteIndex(lpstmt->lpdbc->lpISAM,
ToString(lpstmt->lpSqlStmt,
lpSqlNode->node.dropindex.Index));
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR) lpstmt->szISAMError);
return err;
}
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
break;
case NODE_TYPE_PASSTHROUGH:
err = ISAMExecute(lpstmt->lpISAMStatement, &(lpstmt->cRowCount));
if (err != NO_ISAM_ERR) {
ISAMGetErrorMessage(lpstmt->lpdbc->lpISAM, (LPUSTR)lpstmt->szISAMError);
return err;
}
lpstmt->fISAMTxnStarted = TRUE;
break;
/* Internal error if these nodes are hanging off the root */
case NODE_TYPE_TABLES:
case NODE_TYPE_VALUES:
case NODE_TYPE_COLUMNS:
case NODE_TYPE_SORTCOLUMNS:
case NODE_TYPE_GROUPBYCOLUMNS:
case NODE_TYPE_UPDATEVALUES:
case NODE_TYPE_CREATECOLS:
case NODE_TYPE_BOOLEAN:
case NODE_TYPE_COMPARISON:
case NODE_TYPE_ALGEBRAIC:
case NODE_TYPE_SCALAR:
case NODE_TYPE_AGGREGATE:
case NODE_TYPE_TABLE:
case NODE_TYPE_COLUMN:
case NODE_TYPE_STRING:
case NODE_TYPE_NUMERIC:
case NODE_TYPE_PARAMETER:
case NODE_TYPE_USER:
case NODE_TYPE_NULL:
case NODE_TYPE_DATE:
case NODE_TYPE_TIME:
case NODE_TYPE_TIMESTAMP:
default:
return ERR_INTERNAL;
}
if (!fSelect && (lpstmt->lpdbc->lpISAM->fTxnCapable != SQL_TC_NONE) &&
lpstmt->lpdbc->fAutoCommitTxn) {
err = SQLTransact(SQL_NULL_HENV, (HDBC)lpstmt->lpdbc, SQL_COMMIT);
if ((err != SQL_SUCCESS) && (err != SQL_SUCCESS_WITH_INFO)) {
lpstmt->errcode = lpstmt->lpdbc->errcode;
s_lstrcpy(lpstmt->szISAMError, lpstmt->lpdbc->szISAMError);
return lpstmt->errcode;
}
}
return finalErr;
}
/***************************************************************************/