/***************************************************************************/ /* 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 //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 #include /***************************************************************************/ #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; } /***************************************************************************/