Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5136 lines
180 KiB

/***************************************************************************/
/* SEMANTIC.C */
/* Copyright (C) 1995-96 SYWARE Inc., All rights reserved */
/***************************************************************************/
// Commenting #define out - causing compiler error - not sure if needed, compiles
// okay without it.
//#define WINVER 0x0400
#include "precomp.h"
#include "wbemidl.h"
#include <comdef.h>
//smart pointer
_COM_SMARTPTR_TYPEDEF(IWbemServices, IID_IWbemServices);
_COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, IID_IEnumWbemClassObject);
//_COM_SMARTPTR_TYPEDEF(IWbemContext, IID_IWbemContext );
_COM_SMARTPTR_TYPEDEF(IWbemLocator, IID_IWbemLocator);
#include "drdbdr.h"
/***************************************************************************/
RETCODE INTFUNC FindColumn(LPSTMT lpstmt,
LPSQLTREE lpSql,
BOOL fCaseSensitive,
LPSQLNODE lpSqlNodeColumn,
SQLNODEIDX idxTable,
STRINGIDX idxQualifier)
/* Sees if the table identified by idxTable contains the column identifeid */
/* lpSqNodeColumn. If it does, the semantic information for the column */
/* is filled in. Otherwise an error is returned. */
{
LPSQLNODE lpSqlNodeTable;
LPISAMTABLEDEF lpISAMTableDef;
LPSTR lpName;
UWORD index;
LPUSTR lpTableAlias;
LPUSTR lpColumnAlias;
LPUSTR lpTableName;
BOOL matchedAlias = FALSE;
BOOL fIsPassthroughTable = FALSE;
/* Table/Column name given? */
lpName = (LPSTR) ToString(lpSql, lpSqlNodeColumn->node.column.Column);
lpSqlNodeTable = ToNode(lpSql, idxTable);
if (lpSqlNodeColumn->node.column.Tablealias != NO_STRING) {
// this can be either a tablename or an tablename alias
/* Yes. Make sure it matches */
int found = FALSE;
if (lpSqlNodeTable->node.table.Alias != NO_STRING &&
lpSqlNodeColumn->node.column.Qualifier == NO_STRING)
{
//
//Comparing Aliases
//
lpTableAlias = ToString(lpSql, lpSqlNodeTable->node.table.Alias);
lpColumnAlias = ToString(lpSql, lpSqlNodeColumn->node.column.Tablealias);
if (fCaseSensitive) {
if (!s_lstrcmp(lpTableAlias, lpColumnAlias)) {
found = TRUE;
}
}
else {
if (!s_lstrcmpi(lpTableAlias, lpColumnAlias)) {
found = TRUE;
}
}
if (!found)
return ERR_COLUMNNOTFOUND;
}
//
//Not comparing Aliases
//
if (!found) // try matching the column qualifier + alias to the table qualifier + table name
{
lpTableAlias = ToString(lpSql, lpSqlNodeTable->node.table.Qualifier);
lpColumnAlias = ToString(lpSql, lpSqlNodeColumn->node.column.Tablealias);
char *pszNewQualifier = NULL;
if (lpSqlNodeColumn->node.column.Qualifier != NO_STRING)
{
LPSTR lpColumnQualifier = (LPSTR) ToString (lpSql, lpSqlNodeColumn->node.column.Qualifier);
if ( (strlen(lpColumnQualifier) >= 4) &&
(_strnicmp("root", lpColumnQualifier, 4) == 0))
{
// absolute qualifier (no need to change)
pszNewQualifier = new char [s_lstrlen (lpColumnAlias)+
s_lstrlen (lpColumnQualifier) + 3];
s_lstrcpy (pszNewQualifier, lpColumnQualifier);
s_lstrcat (pszNewQualifier, ".");
s_lstrcat (pszNewQualifier, lpColumnAlias);
}
else
{
// concatenate the current namespace with the qualifier
LPUSTR currQual = ISAMDatabase (lpSql->node.root.lpISAM);
pszNewQualifier = new char [s_lstrlen (lpColumnAlias)+
s_lstrlen (currQual) +
s_lstrlen (lpColumnQualifier) + 3 + 2];
s_lstrcpy (pszNewQualifier, currQual);
s_lstrcat (pszNewQualifier, "\\");
s_lstrcat (pszNewQualifier, lpColumnQualifier);
s_lstrcat (pszNewQualifier, ".");
s_lstrcat (pszNewQualifier, lpColumnAlias);
}
}
else
{
LPUSTR currQual = ISAMDatabase (lpSql->node.root.lpISAM);
pszNewQualifier = new char [s_lstrlen (lpColumnAlias)+
s_lstrlen (currQual)+ 2 + 1];
s_lstrcpy (pszNewQualifier, currQual);
s_lstrcat (pszNewQualifier, ".");
s_lstrcat (pszNewQualifier, lpColumnAlias);
}
// get the table name and concatenate with the table qualifier
// before the check
lpTableName = ToString(lpSql, lpSqlNodeTable->node.table.Name);
char *lpszFQTN = new char [s_lstrlen (lpTableName) +
s_lstrlen (lpTableAlias) + 2 + 1];
s_lstrcpy (lpszFQTN, lpTableAlias);
s_lstrcat (lpszFQTN, ".");
s_lstrcat (lpszFQTN, lpTableName);
if (fCaseSensitive) {
if (!lstrcmp(lpszFQTN, pszNewQualifier)) {
found = TRUE;
}
}
else {
if (!lstrcmpi(lpszFQTN, pszNewQualifier)) {
found = TRUE;
}
}
delete [] pszNewQualifier;
delete lpszFQTN;
}
else
{
matchedAlias = TRUE;
}
//Check if this is the passthrough SQL table
if (lpSqlNodeTable->node.table.Handle->fIsPassthroughSQL)
found = TRUE;
if (!found)
return ERR_COLUMNNOTFOUND;
}
/* Search the table definition for a column with a matching name. */
lpISAMTableDef = lpSqlNodeTable->node.table.Handle;
BOOL fPassthroughSQLWithAlias = FALSE;
LPSTR lpAlias = NULL;
if ( (lpSqlNodeColumn->node.column.Tablealias != NO_STRING) && lpSqlNodeTable->node.table.Handle->fIsPassthroughSQL )
{
lpAlias = (LPSTR) ToString(lpSql, lpSqlNodeColumn->node.column.Tablealias);
if ( lpAlias && lstrlen(lpAlias) )
fPassthroughSQLWithAlias = TRUE;
}
ClassColumnInfoBase* cInfoBase = lpISAMTableDef->pColumnInfo;
if ( !cInfoBase->IsValid() )
{
return ERR_COLUMNNOTFOUND;
}
//Sai
//The current column is lpName, if this is a system property
//and SYSPROPS=FALSE then return an error
if (lpISAMTableDef && lpISAMTableDef->lpISAM)
{
if ( ! lpISAMTableDef->lpISAM->fSysProps)
{
//we are not asking for system properties
//so a system property should not be in the SELECT list
if (_strnicmp("__", lpName, 2) == 0)
{
return ERR_COLUMNNOTFOUND;
}
}
}
UWORD cNumberOfCols = cInfoBase->GetNumberOfColumns();
char pColumnName [MAX_COLUMN_NAME_LENGTH+1];
char pColumnAlias [MAX_COLUMN_NAME_LENGTH+1];
pColumnAlias[0] = 0;
BOOL fMatch = FALSE;
for (index = 0; index < cNumberOfCols; index++)
{
fMatch = FALSE;
if ( FAILED(cInfoBase->GetColumnName(index, pColumnName, pColumnAlias)) )
{
return ERR_COLUMNNOTFOUND;
}
if (fCaseSensitive)
{
if (!s_lstrcmp(lpName, pColumnName))
{
fMatch = TRUE;
// break;
}
}
else
{
if (!s_lstrcmpi(lpName, pColumnName))
{
fMatch = TRUE;
// break;
}
}
//Extra check for passthrough SQL
if (fPassthroughSQLWithAlias && fMatch)
{
fMatch = FALSE;
if (fCaseSensitive)
{
if (!s_lstrcmp(lpAlias, pColumnAlias))
break;
}
else
{
if (!s_lstrcmpi(lpAlias, pColumnAlias))
break;
}
}
if (fMatch)
break;
}
#ifdef TESTING
if (idxQualifier != NO_STRING)
{
char* lpTestQual = ToString(lpSql, lpSqlNodeTable->table.Qualifier);
char* lpOrgQual = ToString(lpSql, idxQualifier);
if (lpTestQual && lpOrgQual && strcmp(lpTestQual, lpOrgQual))
return ERR_COLUMNNOTFOUND;
}
#endif
/* Error if not found */
if (index == cNumberOfCols)
{
s_lstrcpy(lpstmt->szError, lpName);
return ERR_COLUMNNOTFOUND;
}
/* Set the table and column information in the column node. */
lpSqlNodeColumn->node.column.Table = idxTable;
lpSqlNodeColumn->node.column.Id = (UWORD) index;
if (lpSqlNodeColumn->node.column.Tablealias == NO_STRING)
{
lpSqlNodeColumn->node.column.Tablealias = lpSqlNodeTable->node.table.Name;
}
// to keep this consistent I'm going to put a flag in to say if it matched
// a table name or an alias and put the qualifier in too
lpSqlNodeColumn->node.column.MatchedAlias = matchedAlias;
lpSqlNodeColumn->node.column.Qualifier = lpSqlNodeTable->node.table.Qualifier;
// go further and set the column table reference to the table index. In fact,
// this is the best way of doing this. Not sure why SYWARE didn't go this way
// originally. Probably as it ensured every table had an alias. It really
// encapsualtes all the above info.
lpSqlNodeColumn->node.column.TableIndex = idxTable;
/* Figure out type of data */
cInfoBase->GetSQLType(index, lpSqlNodeColumn->sqlSqlType);
switch (lpSqlNodeColumn->sqlSqlType) {
case SQL_DECIMAL:
case SQL_NUMERIC:
{
lpSqlNodeColumn->sqlDataType = TYPE_NUMERIC;
UDWORD uwPrec = 0;
cInfoBase->GetPrecision(index, uwPrec);
lpSqlNodeColumn->sqlPrecision = (SWORD)uwPrec;
cInfoBase->GetScale(index, lpSqlNodeColumn->sqlScale);
}
break;
case SQL_BIGINT:
{
lpSqlNodeColumn->sqlDataType = TYPE_NUMERIC;
UDWORD uwPrec = 0;
cInfoBase->GetPrecision(index, uwPrec);
lpSqlNodeColumn->sqlPrecision = (SWORD)uwPrec;
lpSqlNodeColumn->sqlScale = 0;
}
break;
case SQL_TINYINT:
lpSqlNodeColumn->sqlDataType = TYPE_INTEGER;
lpSqlNodeColumn->sqlPrecision = 3;
lpSqlNodeColumn->sqlScale = 0;
break;
case SQL_SMALLINT:
lpSqlNodeColumn->sqlDataType = TYPE_INTEGER;
lpSqlNodeColumn->sqlPrecision = 5;
lpSqlNodeColumn->sqlScale = 0;
break;
case SQL_INTEGER:
lpSqlNodeColumn->sqlDataType = TYPE_INTEGER;
lpSqlNodeColumn->sqlPrecision = 10;
lpSqlNodeColumn->sqlScale = 0;
break;
case SQL_BIT:
lpSqlNodeColumn->sqlDataType = TYPE_INTEGER;
lpSqlNodeColumn->sqlPrecision = 1;
lpSqlNodeColumn->sqlScale = 0;
break;
case SQL_REAL:
lpSqlNodeColumn->sqlDataType = TYPE_DOUBLE;
lpSqlNodeColumn->sqlPrecision = 7;
lpSqlNodeColumn->sqlScale = NO_SCALE;
break;
case SQL_FLOAT:
case SQL_DOUBLE:
lpSqlNodeColumn->sqlDataType = TYPE_DOUBLE;
lpSqlNodeColumn->sqlPrecision = 15;
lpSqlNodeColumn->sqlScale = NO_SCALE;
break;
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
{
lpSqlNodeColumn->sqlDataType = TYPE_CHAR;
UDWORD uwPrec = 0;
cInfoBase->GetPrecision(index, uwPrec);
lpSqlNodeColumn->sqlPrecision = (SWORD)uwPrec;
if (lpSqlNodeColumn->sqlPrecision > MAX_CHAR_LITERAL_LENGTH)
lpSqlNodeColumn->sqlPrecision = MAX_CHAR_LITERAL_LENGTH;
lpSqlNodeColumn->sqlScale = NO_SCALE;
}
break;
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
{
lpSqlNodeColumn->sqlDataType = TYPE_BINARY;
UDWORD uwPrec = 0;
cInfoBase->GetPrecision(index, uwPrec);
lpSqlNodeColumn->sqlPrecision = (SWORD)uwPrec;
lpSqlNodeColumn->sqlScale = NO_SCALE;
}
break;
case SQL_DATE:
lpSqlNodeColumn->sqlDataType = TYPE_DATE;
lpSqlNodeColumn->sqlPrecision = 10;
lpSqlNodeColumn->sqlScale = NO_SCALE;
break;
case SQL_TIME:
lpSqlNodeColumn->sqlDataType = TYPE_TIME;
lpSqlNodeColumn->sqlPrecision = 8;
lpSqlNodeColumn->sqlScale = NO_SCALE;
break;
case SQL_TIMESTAMP:
lpSqlNodeColumn->sqlDataType = TYPE_TIMESTAMP;
if (TIMESTAMP_SCALE > 0)
lpSqlNodeColumn->sqlPrecision = 20 + TIMESTAMP_SCALE;
else
lpSqlNodeColumn->sqlPrecision = 19;
lpSqlNodeColumn->sqlScale = TIMESTAMP_SCALE;
break;
default:
return ERR_NOTSUPPORTED;
}
return ERR_SUCCESS;
}
/***************************************************************************/
void INTFUNC ErrorOpCode(LPSTMT lpstmt,
UWORD opCode)
/* Puts opcode in szError (as a string) */
{
switch (opCode) {
case OP_NONE:
s_lstrcpy(lpstmt->szError, "<assignment>");
break;
case OP_EQ:
s_lstrcpy(lpstmt->szError, "=");
break;
case OP_NE:
s_lstrcpy(lpstmt->szError, "<>");
break;
case OP_LE:
s_lstrcpy(lpstmt->szError, "<=");
break;
case OP_LT:
s_lstrcpy(lpstmt->szError, "<");
break;
case OP_GE:
s_lstrcpy(lpstmt->szError, ">=");
break;
case OP_GT:
s_lstrcpy(lpstmt->szError, ">");
break;
case OP_IN:
s_lstrcpy(lpstmt->szError, "IN");
break;
case OP_NOTIN:
s_lstrcpy(lpstmt->szError, "NOT IN");
break;
case OP_LIKE:
s_lstrcpy(lpstmt->szError, "LIKE");
break;
case OP_NOTLIKE:
s_lstrcpy(lpstmt->szError, "NOT LIKE");
break;
case OP_NEG:
s_lstrcpy(lpstmt->szError, "-");
break;
case OP_PLUS:
s_lstrcpy(lpstmt->szError, "+");
break;
case OP_MINUS:
s_lstrcpy(lpstmt->szError, "-");
break;
case OP_TIMES:
s_lstrcpy(lpstmt->szError, "*");
break;
case OP_DIVIDEDBY:
s_lstrcpy(lpstmt->szError, "/");
break;
case OP_NOT:
s_lstrcpy(lpstmt->szError, "NOT");
break;
case OP_AND:
s_lstrcpy(lpstmt->szError, "AND");
break;
case OP_OR:
s_lstrcpy(lpstmt->szError, "OR");
break;
case OP_EXISTS:
s_lstrcpy(lpstmt->szError, "EXISTS");
break;
default:
s_lstrcpy(lpstmt->szError, "");
break;
}
}
/***************************************************************************/
void INTFUNC ErrorAggCode(LPSTMT lpstmt,
UWORD aggCode)
/* Puts aggreagate operator code in szError (as a string) */
{
switch(aggCode) {
case AGG_AVG:
s_lstrcpy(lpstmt->szError, "AVG");
break;
case AGG_COUNT:
s_lstrcpy(lpstmt->szError, "COUNT");
break;
case AGG_MAX:
s_lstrcpy(lpstmt->szError, "MAX");
break;
case AGG_MIN:
s_lstrcpy(lpstmt->szError, "MIN");
break;
case AGG_SUM:
s_lstrcpy(lpstmt->szError, "SUM");
break;
default:
s_lstrcpy(lpstmt->szError, "");
break;
}
}
/***************************************************************************/
RETCODE INTFUNC TypeCheck(LPSTMT lpstmt,
LPSQLTREE lpSql,
SQLNODEIDX idxLeft,
SQLNODEIDX idxRight,
UWORD opCode,
SWORD FAR *pfDataType,
SWORD FAR *pfSqlType,
SDWORD FAR *pPrecision,
SWORD FAR *pScale)
/* Checks to see if the types of the two children nodes are compatible. */
/* If the type of one of the children is unknown (because it was a */
/* parameter or the value NULL), it set to the type of the other child. */
{
LPSQLNODE lpSqlNodeLeft;
LPSQLNODE lpSqlNodeRight;
SWORD fDataTypeLeft;
SWORD fSqlTypeLeft;
SDWORD precisionLeft;
SWORD scaleLeft;
SWORD fDataTypeRight;
SWORD fSqlTypeRight;
SDWORD precisionRight;
SWORD scaleRight;
SWORD fDataType;
SWORD fSqlType;
SDWORD precision;
SWORD scale;
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
/* Get left type */
if (idxLeft == NO_SQLNODE)
return ERR_INTERNAL;
lpSqlNodeLeft = ToNode(lpSql, idxLeft);
fDataTypeLeft = lpSqlNodeLeft->sqlDataType;
fSqlTypeLeft = lpSqlNodeLeft->sqlSqlType;
precisionLeft = lpSqlNodeLeft->sqlPrecision;
scaleLeft = lpSqlNodeLeft->sqlScale;
/* Is there a right epxression? */
if (idxRight != NO_SQLNODE) {
/* Yes. Get right type. */
lpSqlNodeRight = ToNode(lpSql, idxRight);
fDataTypeRight = lpSqlNodeRight->sqlDataType;
fSqlTypeRight = lpSqlNodeRight->sqlSqlType;
precisionRight = lpSqlNodeRight->sqlPrecision;
scaleRight = lpSqlNodeRight->sqlScale;
}
else {
/* No. This must be an arithmetic negation operator. Use left */
/* type as the right type */
if (opCode != OP_NEG)
return ERR_INTERNAL;
if (fDataTypeLeft == TYPE_UNKNOWN)
return ERR_UNKNOWNTYPE;
fDataTypeRight = fDataTypeLeft;
fSqlTypeRight = fSqlTypeLeft;
precisionRight = precisionLeft;
scaleRight = scaleLeft;
}
/* Is left side unknown? */
if (fDataTypeLeft == TYPE_UNKNOWN) {
/* Yes. Error if right side is unknown also */
if (fDataTypeRight == TYPE_UNKNOWN)
return ERR_UNKNOWNTYPE;
/* If right side is string value, make sure opcode is legal */
if (fDataTypeRight == TYPE_CHAR) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
case OP_LIKE:
case OP_NOTLIKE:
break;
case OP_NEG:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_PLUS:
if (fSqlTypeRight == SQL_LONGVARCHAR) {
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
break;
case OP_MINUS:
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
/* If right side is date value, make sure opcode is legal */
else if (fDataTypeRight == TYPE_DATE) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
break;
case OP_LIKE:
case OP_NOTLIKE:
case OP_NEG:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_PLUS:
case OP_MINUS:
break;
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
/* Adding to a date? */
if ((fDataTypeRight == TYPE_DATE) && (opCode == OP_PLUS)) {
/* Yes. The left side must be integer */
lpSqlNodeLeft->sqlDataType = TYPE_INTEGER;
lpSqlNodeLeft->sqlSqlType = SQL_INTEGER;
lpSqlNodeLeft->sqlPrecision = 10;
lpSqlNodeLeft->sqlScale = 0;
}
else {
/* No. Use type from right as type for left */
/* Note: This disallows ? from being a date in (? - 3) */
/* Note: This disallows ? from being a date in (? + 3) */
lpSqlNodeLeft->sqlDataType = fDataTypeRight;
lpSqlNodeLeft->sqlSqlType = fSqlTypeRight;
lpSqlNodeLeft->sqlPrecision = precisionRight;
lpSqlNodeLeft->sqlScale = scaleRight;
/* If string concatenation, adjust type and precision */
if ((fDataTypeRight == TYPE_CHAR) && (opCode == OP_PLUS)) {
lpSqlNodeLeft->sqlSqlType = SQL_VARCHAR;
lpSqlNodeLeft->sqlPrecision = MAX_CHAR_LITERAL_LENGTH;
}
}
/* Adding to a date? */
if ((fDataTypeRight == TYPE_DATE) && (opCode == OP_PLUS)) {
/* Yes. The result type is a date */
if (pfDataType != NULL)
*pfDataType = lpSqlNodeRight->sqlDataType;
if (pfSqlType != NULL)
*pfSqlType = lpSqlNodeRight->sqlSqlType;
if (pPrecision != NULL)
*pPrecision = lpSqlNodeRight->sqlPrecision;
if (pScale != NULL)
*pScale = lpSqlNodeRight->sqlScale;
}
/* Calculating the differnce of two dates? */
else if ((lpSqlNodeLeft->sqlDataType == TYPE_DATE) &&
(opCode == OP_MINUS)) {
/* Yes. The result type is integer */
if (pfDataType != NULL)
*pfDataType = TYPE_INTEGER;
if (pfSqlType != NULL)
*pfSqlType = SQL_INTEGER;
if (pPrecision != NULL)
*pPrecision = 10;
if (pScale != NULL)
*pScale = 0;
}
else {
/* No. The result type is the same as the left side */
if (pfDataType != NULL)
*pfDataType = lpSqlNodeLeft->sqlDataType;
if (pfSqlType != NULL)
*pfSqlType = lpSqlNodeLeft->sqlSqlType;
if (pPrecision != NULL)
*pPrecision = lpSqlNodeLeft->sqlPrecision;
if (pScale != NULL)
*pScale = lpSqlNodeLeft->sqlScale;
}
}
/* Is right side unknown? */
else if (fDataTypeRight == TYPE_UNKNOWN) {
/* Yes. If left side is string value, make sure opcode is legal */
if (fDataTypeLeft == TYPE_CHAR) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
case OP_LIKE:
case OP_NOTLIKE:
break;
case OP_NEG:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_PLUS:
if (fSqlTypeLeft == SQL_LONGVARCHAR) {
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
break;
case OP_MINUS:
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
/* If left side is date value, make sure opcode is legal */
else if (fDataTypeLeft == TYPE_DATE) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
break;
case OP_LIKE:
case OP_NOTLIKE:
case OP_NEG:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_PLUS:
case OP_MINUS:
break;
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
/* Adding to a date? */
if ((fDataTypeLeft == TYPE_DATE) && (opCode == OP_PLUS)) {
/* Yes. The right side must be integer */
lpSqlNodeRight->sqlDataType = TYPE_INTEGER;
lpSqlNodeRight->sqlSqlType = SQL_INTEGER;
lpSqlNodeRight->sqlPrecision = 10;
lpSqlNodeRight->sqlScale = 0;
}
else {
/* No. Use type from left as type for right */
/* Note: This disallows ? from being a number in (<date> - ? ) */
/* Note: This disallows ? from being a date in (<number> + ? ) */
lpSqlNodeRight->sqlDataType = fDataTypeLeft;
lpSqlNodeRight->sqlSqlType = fSqlTypeLeft;
lpSqlNodeRight->sqlPrecision = precisionLeft;
lpSqlNodeRight->sqlScale = scaleLeft;
/* If string concatenation, adjust type and precision */
if ((fDataTypeLeft == TYPE_CHAR) && (opCode == OP_PLUS)) {
lpSqlNodeRight->sqlSqlType = SQL_VARCHAR;
lpSqlNodeRight->sqlPrecision = MAX_CHAR_LITERAL_LENGTH;
}
}
/* Adding to a date? */
if ((fDataTypeLeft == TYPE_DATE) && (opCode == OP_PLUS)) {
/* Yes. The result type is a date */
if (pfDataType != NULL)
*pfDataType = TYPE_DATE;
if (pfSqlType != NULL)
*pfSqlType = SQL_DATE;
if (pPrecision != NULL)
*pPrecision = 10;
if (pScale != NULL)
*pScale = 0;
}
/* Calculating the difference of two dates? */
else if ((fDataTypeLeft == TYPE_DATE) && (opCode == OP_MINUS)) {
/* Yes. The result type is integer */
if (pfDataType != NULL)
*pfDataType = TYPE_INTEGER;
if (pfSqlType != NULL)
*pfSqlType = SQL_INTEGER;
if (pPrecision != NULL)
*pPrecision = 10;
if (pScale != NULL)
*pScale = 0;
}
else {
/* No. The result type is the same as the right side */
if (pfDataType != NULL)
*pfDataType = lpSqlNodeRight->sqlDataType;
if (pfSqlType != NULL)
*pfSqlType = lpSqlNodeRight->sqlSqlType;
if (pPrecision != NULL)
*pPrecision = lpSqlNodeRight->sqlPrecision;
if (pScale != NULL)
*pScale = lpSqlNodeRight->sqlScale;
}
}
/* Do types match? */
else if ((fDataTypeLeft == fDataTypeRight) ||
((fDataTypeLeft == TYPE_DOUBLE) &&
(fDataTypeRight == TYPE_NUMERIC)) ||
((fDataTypeLeft == TYPE_DOUBLE) &&
(fDataTypeRight == TYPE_INTEGER)) ||
((fDataTypeLeft == TYPE_NUMERIC) &&
(fDataTypeRight == TYPE_DOUBLE)) ||
((fDataTypeLeft == TYPE_NUMERIC) &&
(fDataTypeRight == TYPE_INTEGER)) ||
((fDataTypeLeft == TYPE_INTEGER) &&
(fDataTypeRight == TYPE_DOUBLE)) ||
((fDataTypeLeft == TYPE_INTEGER) &&
(fDataTypeRight == TYPE_NUMERIC))) {
/* Yes. If left side is string value, make sure opcode is legal */
if (fDataTypeLeft == TYPE_CHAR) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
case OP_LIKE:
case OP_NOTLIKE:
break;
case OP_NEG:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_PLUS:
if ((fSqlTypeRight == SQL_LONGVARCHAR) ||
(fSqlTypeLeft == SQL_LONGVARCHAR)) {
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
break;
case OP_MINUS:
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
/* If left side is date value, make sure opcode is legal */
else if (fDataTypeLeft == TYPE_DATE) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
break;
case OP_LIKE:
case OP_NOTLIKE:
case OP_NEG:
case OP_PLUS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_MINUS:
break;
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
/* Figure out resultant type */
if ((fDataTypeLeft == TYPE_NUMERIC) && (fDataTypeRight == TYPE_DOUBLE))
fDataType = TYPE_DOUBLE;
else if ((fDataTypeLeft == TYPE_INTEGER) && (fDataTypeRight == TYPE_DOUBLE))
fDataType = TYPE_DOUBLE;
else if ((fDataTypeLeft == TYPE_INTEGER) && (fDataTypeRight == TYPE_NUMERIC))
fDataType = TYPE_NUMERIC;
else
fDataType = fDataTypeLeft;
if (pfDataType != NULL)
*pfDataType = fDataType;
/* Figure out resultant SQL type, precision, and scale */
switch (fSqlTypeLeft) {
case SQL_DOUBLE:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_FLOAT:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_REAL:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
if ((fSqlTypeRight == SQL_DECIMAL) ||
(fSqlTypeLeft == SQL_DECIMAL))
fSqlType = SQL_DECIMAL;
else if ((fSqlTypeRight == SQL_NUMERIC) ||
(fSqlTypeLeft == SQL_NUMERIC))
fSqlType = SQL_NUMERIC;
else if ((fSqlTypeRight == SQL_BIGINT) ||
(fSqlTypeLeft == SQL_BIGINT))
fSqlType = SQL_BIGINT;
else if ((fSqlTypeRight == SQL_INTEGER) ||
(fSqlTypeLeft == SQL_INTEGER))
fSqlType = SQL_INTEGER;
else if ((fSqlTypeRight == SQL_SMALLINT) ||
(fSqlTypeLeft == SQL_SMALLINT))
fSqlType = SQL_SMALLINT;
else if ((fSqlTypeRight == SQL_TINYINT) ||
(fSqlTypeLeft == SQL_TINYINT))
fSqlType = SQL_TINYINT;
else
fSqlType = SQL_BIT;
if (pfSqlType != NULL)
*pfSqlType = fSqlType;
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = scaleLeft;
break;
case OP_LIKE:
case OP_NOTLIKE:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_NEG:
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = scaleLeft;
break;
case OP_PLUS:
case OP_MINUS:
scale = MAX(scaleRight, scaleLeft);
switch (fSqlType) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
return ERR_INTERNAL;
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
precision = scale + MAX(precisionRight - scaleRight,
precisionLeft - scaleLeft) + 1;
break;
case SQL_INTEGER:
precision = 10;
break;
case SQL_SMALLINT:
precision = 5;
break;
case SQL_TINYINT:
precision = 3;
break;
case SQL_BIT:
precision = 1;
break;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
if (pPrecision != NULL)
*pPrecision = precision;
if (pScale != NULL)
*pScale = scale;
break;
case OP_TIMES:
case OP_DIVIDEDBY:
scale = scaleRight + scaleLeft;
switch (fSqlType) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
return ERR_INTERNAL;
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
precision = scale + (precisionRight - scaleRight) +
(precisionLeft - scaleLeft);
break;
case SQL_INTEGER:
precision = 10;
break;
case SQL_SMALLINT:
precision = 5;
break;
case SQL_TINYINT:
precision = 3;
break;
case SQL_BIT:
precision = 1;
break;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
if (pPrecision != NULL)
*pPrecision = precision;
if (pScale != NULL)
*pScale = scale;
break;
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
break;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_LONGVARCHAR:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
return ERR_INTERNAL;
case SQL_LONGVARCHAR:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_VARCHAR:
case SQL_CHAR:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL) {
if (precisionLeft > precisionRight)
*pPrecision = precisionLeft;
else
*pPrecision = precisionRight;
}
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_VARCHAR:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
return ERR_INTERNAL;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_CHAR:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
/* Adjust precision for string concatenation operator */
if ((opCode == OP_PLUS) && (pPrecision != NULL))
*pPrecision = MIN(precisionRight + precisionLeft,
MAX_CHAR_LITERAL_LENGTH);
break;
case SQL_CHAR:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
return ERR_INTERNAL;
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
/* Adjust precision for string concatenation operator */
if ((opCode == OP_PLUS) && (pPrecision != NULL))
*pPrecision = MIN(precisionRight + precisionLeft,
MAX_CHAR_LITERAL_LENGTH);
break;
case SQL_LONGVARBINARY:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
return ERR_INTERNAL;
case SQL_LONGVARBINARY:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_VARBINARY:
case SQL_BINARY:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_VARBINARY:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
return ERR_INTERNAL;
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_BINARY:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_BINARY:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
return ERR_INTERNAL;
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_DATE:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
return ERR_INTERNAL;
case SQL_DATE:
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = scaleLeft;
break;
case OP_LIKE:
case OP_NOTLIKE:
case OP_NEG:
case OP_PLUS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_MINUS:
if (pfDataType != NULL)
*pfDataType = TYPE_INTEGER;
if (pPrecision != NULL)
*pPrecision = 10;
if (pfSqlType != NULL)
*pfSqlType = SQL_INTEGER;
if (pScale != NULL)
*pScale = 0;
break;
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
break;
case SQL_TIME:
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_TIME:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
return ERR_INTERNAL;
case SQL_TIME:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = NO_SCALE;
break;
case SQL_TIMESTAMP:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
break;
case SQL_TIMESTAMP:
switch (fSqlTypeRight) {
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_REAL:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_BIGINT:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_BIT:
case SQL_LONGVARCHAR:
case SQL_VARCHAR:
case SQL_CHAR:
case SQL_LONGVARBINARY:
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_DATE:
case SQL_TIME:
return ERR_INTERNAL;
case SQL_TIMESTAMP:
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = TIMESTAMP_SCALE;
break;
default:
return ERR_NOTSUPPORTED;
}
break;
default:
return ERR_NOTSUPPORTED;
}
}
else if ((fDataTypeLeft == TYPE_DATE) &&
((fDataTypeRight == TYPE_DOUBLE) ||
(fDataTypeRight == TYPE_NUMERIC) ||
(fDataTypeRight == TYPE_INTEGER))) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
case OP_LIKE:
case OP_NOTLIKE:
case OP_NEG:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_PLUS:
case OP_MINUS:
if (pfDataType != NULL)
*pfDataType = fDataTypeLeft;
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeLeft;
if (pPrecision != NULL)
*pPrecision = precisionLeft;
if (pScale != NULL)
*pScale = scaleLeft;
break;
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
else if ((fDataTypeRight == TYPE_DATE) &&
((fDataTypeLeft == TYPE_DOUBLE) ||
(fDataTypeLeft == TYPE_NUMERIC) ||
(fDataTypeLeft == TYPE_INTEGER))) {
switch (opCode) {
case OP_NONE:
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_LT:
case OP_GE:
case OP_GT:
case OP_IN:
case OP_NOTIN:
case OP_LIKE:
case OP_NOTLIKE:
case OP_NEG:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
case OP_PLUS:
if (pfDataType != NULL)
*pfDataType = fDataTypeRight;
if (pfSqlType != NULL)
*pfSqlType = fSqlTypeRight;
if (pPrecision != NULL)
*pPrecision = precisionRight;
if (pScale != NULL)
*pScale = scaleRight;
break;
case OP_MINUS:
case OP_TIMES:
case OP_DIVIDEDBY:
case OP_NOT:
case OP_AND:
case OP_OR:
case OP_EXISTS:
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
}
else {
ErrorOpCode(lpstmt, opCode);
return ERR_INVALIDOPERAND;
}
return ERR_SUCCESS;
}
/***************************************************************************/
BOOL INTFUNC FindAggregate(LPSQLTREE lpSql, SQLNODEIDX idxNode)
/* Looks for the next aggregate function on a select list */
{
LPSQLNODE lpSqlNode;
if (idxNode == NO_SQLNODE)
return FALSE;
lpSqlNode = ToNode(lpSql, idxNode);
switch (lpSqlNode->sqlNodeType) {
case NODE_TYPE_NONE:
case NODE_TYPE_ROOT:
case NODE_TYPE_CREATE:
case NODE_TYPE_DROP:
return FALSE; /* Internal error */
case NODE_TYPE_SELECT:
return FALSE;
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:
return FALSE; /* Internal error */
case NODE_TYPE_VALUES:
while (TRUE) {
if (FindAggregate(lpSql, lpSqlNode->node.values.Value))
return TRUE;
if (lpSqlNode->node.values.Next == NO_SQLNODE)
return FALSE;
lpSqlNode = ToNode(lpSql, lpSqlNode->node.values.Next);
}
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:
return FALSE; /* Internal error */
case NODE_TYPE_ALGEBRAIC:
if (FindAggregate(lpSql, lpSqlNode->node.algebraic.Left))
return TRUE;
return (FindAggregate(lpSql, lpSqlNode->node.algebraic.Right));
case NODE_TYPE_SCALAR:
return (FindAggregate(lpSql, lpSqlNode->node.scalar.Arguments));
case NODE_TYPE_AGGREGATE:
return TRUE;
case NODE_TYPE_TABLE:
return FALSE; /* Internal error */
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:
return FALSE;
default:
return FALSE; /* Internal error */
}
}
/***************************************************************************/
RETCODE INTFUNC SelectCheck(LPSTMT lpstmt, LPSQLTREE FAR *lplpSql,
SQLNODEIDX idxNode, BOOL fCaseSensitive,
SQLNODEIDX idxEnclosingStatement)
/* Walks a SELECT parse tree, checks it for semantic correctness, and */
/* fills in the semantic information. */
{
LPSQLNODE lpSqlNode;
RETCODE err;
UWORD count;
UDWORD offset;
BOOL fIsGroupby;
if (idxNode == NO_SQLNODE)
return ERR_SUCCESS;
lpSqlNode = ToNode(*lplpSql, idxNode);
/* Save pointer to enclosing statement */
lpSqlNode->node.select.EnclosingStatement = idxEnclosingStatement;
/* Check the list of tables */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.select.Tables,
FALSE, fCaseSensitive, NO_SQLNODE, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the GROUP BY columns */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.select.Groupbycolumns,
FALSE, fCaseSensitive, NO_SQLNODE, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Is there a GROUP BY clause? */
count = 0;
offset = 1;
if (lpSqlNode->node.select.Groupbycolumns != NO_SQLNODE) {
UDWORD length;
SQLNODEIDX idxGroupbycolumns;
LPSQLNODE lpSqlNodeGroupbycolumns;
LPSQLNODE lpSqlNodeColumn;
/* Yes. Error if SELECT * */
if (lpSqlNode->node.select.Values == NO_SQLNODE)
return ERR_NOSELECTSTAR;
/* Figure out offset and length of each column when it */
/* is in the sort file */
idxGroupbycolumns = lpSqlNode->node.select.Groupbycolumns;
while (idxGroupbycolumns != NO_SQLNODE) {
/* Add this column to the count */
count++;
/* Error if too many columns */
if (count > MAX_COLUMNS_IN_GROUP_BY)
return ERR_GROUPBYTOOLARGE;
/* Save column offset */
lpSqlNodeGroupbycolumns = ToNode(*lplpSql, idxGroupbycolumns);
lpSqlNodeColumn = ToNode(*lplpSql,
lpSqlNodeGroupbycolumns->node.groupbycolumns.Column);
lpSqlNodeColumn->node.column.Offset = offset;
/* Get length of the column */
switch (lpSqlNodeColumn->sqlDataType) {
case TYPE_DOUBLE:
length = sizeof(double);
break;
case TYPE_NUMERIC:
length = 2 + lpSqlNodeColumn->sqlPrecision;
break;
case TYPE_INTEGER:
length = sizeof(double);
break;
case TYPE_CHAR:
length = lpSqlNodeColumn->sqlPrecision;
if (length > MAX_CHAR_LITERAL_LENGTH) {
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column));
return ERR_CANTGROUPBYONTHIS;
}
break;
case TYPE_BINARY:
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column));
return ERR_CANTGROUPBYONTHIS;
case TYPE_DATE:
length = 10;
break;
case TYPE_TIME:
length = 8;
break;
case TYPE_TIMESTAMP:
if (TIMESTAMP_SCALE > 0)
length = 20 + TIMESTAMP_SCALE;
else
length = 19;
break;
default:
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column));
return ERR_CANTGROUPBYONTHIS;
}
/* Put length of the column column description */
lpSqlNodeColumn->node.column.Length = length;
/* Go to next column */
offset += (length);
offset++; /* for the IS NULL flag */
idxGroupbycolumns = lpSqlNodeGroupbycolumns->node.groupbycolumns.Next;
}
/* Set flag */
fIsGroupby = TRUE;
}
else {
/* No. Are there any aggregates in the select list? */
if (!FindAggregate(*lplpSql, lpSqlNode->node.select.Values)) {
/* No. Error if there is a HAVING clause */
if (lpSqlNode->node.select.Having != NO_SQLNODE)
return ERR_NOGROUPBY;
/* Set flag */
fIsGroupby = FALSE;
}
else {
/* Yes. Set flags */
lpSqlNode->node.select.ImplicitGroupby = TRUE;
fIsGroupby = TRUE;
}
}
/* SELECT * ? */
if (lpSqlNode->node.select.Values == NO_SQLNODE) {
SQLNODEIDX idxTables;
LPSQLNODE lpSqlNodeTables;
SQLNODEIDX idxTable;
LPSQLNODE lpSqlNodeTable;
// STRINGIDX idxAlias;
LPISAMTABLEDEF lpTableHandle;
SQLNODEIDX idxValues;
LPSQLNODE lpSqlNodeValues;
SQLNODEIDX idxValuesPrev;
LPSQLNODE lpSqlNodeValuesPrev;
SQLNODEIDX idxColumn;
LPSQLNODE lpSqlNodeColumn;
SWORD idx;
/* Yes. Loop though all the tables in the table list */
idxValuesPrev = NO_SQLNODE;
idxTables = lpSqlNode->node.select.Tables;
while (idxTables != NO_SQLNODE) {
/* Get pointer to the next table */
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
idxTables = lpSqlNodeTables->node.tables.Next;
/* Get pointer to this table */
idxTable = lpSqlNodeTables->node.tables.Table;
lpSqlNodeTable = ToNode(*lplpSql, idxTable);
/* Loop through all the columns of this table */
lpTableHandle = lpSqlNodeTable->node.table.Handle;
ClassColumnInfoBase* cInfoBase = lpTableHandle->pColumnInfo;
LPISAM myISAM = lpTableHandle->lpISAM;
if ( !cInfoBase->IsValid() )
{
return ERR_COLUMNNOTFOUND;
}
//Store able alias before allocating memory
//in order to avoid bug
STRINGIDX idxTheAlias = lpSqlNodeTable->node.table.Alias;
STRINGIDX idxTheQual = lpSqlNodeTable->node.table.Qualifier;
UWORD cNumberOfCols = cInfoBase->GetNumberOfColumns();
char pColumnName [MAX_COLUMN_NAME_LENGTH+1];
//Sai added - fetch the column alias
//only filled in if using passthrough SQL, ignored otherwise
char pAliasName [MAX_COLUMN_NAME_LENGTH+1];
pAliasName[0] = 0;
for (idx = 0; idx < (SWORD) cNumberOfCols; idx++)
{
if ( FAILED(cInfoBase->GetColumnName(idx, pColumnName, pAliasName)) )
{
return ERR_COLUMNNOTFOUND;
}
//Ignore any OLEMS specific columns which we want to hide
if (myISAM && !(myISAM->fSysProps))
{
if (_strnicmp("__", pColumnName, 2) == 0)
{
continue;
}
}
//Ignore any 'lazy' columns
BOOL fIsLazy = FALSE;
if ( cInfoBase->IsLazy(idx, fIsLazy) )
{
if (fIsLazy)
{
continue;
}
}
//Check if this column type is support
//if not we skip this column
if (! ISAMGetColumnType(lpTableHandle, (UWORD) idx) )
{
continue;
}
/* Create a node for this column */
idxColumn = AllocateNode(lplpSql, NODE_TYPE_COLUMN);
if (idxColumn == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
//Get new pointers
lpSqlNodeColumn = ToNode(*lplpSql, idxColumn);
lpSqlNodeTable = ToNode(*lplpSql, idxTable);
lpSqlNodeColumn->node.column.Tablealias = idxTheAlias;
if (lpSqlNodeTable->node.table.Alias != NO_STRING)
{
lpSqlNodeColumn->node.column.MatchedAlias = TRUE;
}
else
{
lpSqlNodeColumn->node.column.MatchedAlias = FALSE;
}
lpSqlNodeColumn->node.column.TableIndex = idxTable;
lpSqlNodeColumn->node.column.Qualifier = idxTheQual;
lpSqlNodeColumn->node.column.Column = AllocateString(lplpSql,
(LPUSTR)pColumnName);
//New - for identical column names when using passthrough SQL
if ( pAliasName && lstrlen(pAliasName) )
{
lpSqlNodeColumn->node.column.Tablealias = AllocateString(lplpSql,
(LPUSTR)pAliasName);
}
//To avoid bug recalc lpSqlNodeColumn
lpSqlNodeColumn = ToNode(*lplpSql, idxColumn);
if (lpSqlNodeColumn->node.column.Column == NO_STRING)
return ERR_MEMALLOCFAIL;
lpSqlNodeColumn->node.table.Handle = NULL;
lpSqlNodeColumn->node.column.Id = -1;
lpSqlNodeColumn->node.column.Value = NO_STRING;
lpSqlNodeColumn->node.column.InSortRecord = FALSE;
lpSqlNodeColumn->node.column.Offset = 0;
lpSqlNodeColumn->node.column.Length = 0;
lpSqlNodeColumn->node.column.DistinctOffset = 0;
lpSqlNodeColumn->node.column.DistinctLength = 0;
lpSqlNodeColumn->node.column.EnclosingStatement = NO_SQLNODE;
/* Put it on the list */
idxValues = AllocateNode(lplpSql, NODE_TYPE_VALUES);
if (idxValues == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
lpSqlNodeValues = ToNode(*lplpSql, idxValues);
lpSqlNodeValues->node.values.Value = idxColumn;
lpSqlNodeValues->node.values.Alias = NO_STRING;
lpSqlNodeValues->node.values.Next = NO_SQLNODE;
if (idxValuesPrev == NO_SQLNODE) {
lpSqlNode = ToNode(*lplpSql, idxNode);
lpSqlNode->node.select.Values = idxValues;
}
else {
lpSqlNodeValuesPrev = ToNode(*lplpSql, idxValuesPrev);
lpSqlNodeValuesPrev->node.values.Next = idxValues;
}
idxValuesPrev = idxValues;
}
}
lpSqlNode = ToNode(*lplpSql, idxNode);
}
/* SELECT aliasname.* ? */
{
SQLNODEIDX idxValuesPrev;
SQLNODEIDX idxValues;
LPSQLNODE lpSqlNodeValues;
SQLNODEIDX idxTables;
LPSQLNODE lpSqlNodeTables;
SQLNODEIDX idxTable;
LPSQLNODE lpSqlNodeTable;
LPUSTR lpTableAlias;
LPUSTR lpValuesAlias;
LPSQLNODE lpSqlNodeValuesPrev;
LPISAMTABLEDEF lpTableHandle;
SQLNODEIDX idxColumn;
LPSQLNODE lpSqlNodeColumn;
SWORD idx;
STRINGIDX idxAlias;
SQLNODEIDX idxValuesNew;
/* Yes. Loop though all the nodes in the select list */
idxValuesPrev = NO_SQLNODE;
idxValues = lpSqlNode->node.select.Values;
while (idxValues != NO_SQLNODE) {
/* Get pointer to the values node */
lpSqlNodeValues = ToNode(*lplpSql, idxValues);
/* Is this a <table>.* node? */
if (lpSqlNodeValues->node.values.Value != NO_SQLNODE) {
/* No. Go to next entry */
idxValuesPrev = idxValues;
idxValues = lpSqlNodeValues->node.values.Next;
continue;
}
idxValues = lpSqlNodeValues->node.values.Next;
/* Find the table */
lpValuesAlias = ToString(*lplpSql,
lpSqlNodeValues->node.values.Alias);
idxTables = lpSqlNode->node.select.Tables;
//First pass : check alias's
while (idxTables != NO_SQLNODE) {
/* Get pointer to the table */
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
/* Get pointer to this table */
idxTable = lpSqlNodeTables->node.tables.Table;
lpSqlNodeTable = ToNode(*lplpSql, idxTable);
/* Get Alias of this table */
idxAlias = lpSqlNodeTable->node.table.Alias;
/* Leave loop if it matches */
lpTableAlias = ToString(*lplpSql, idxAlias);
if (fCaseSensitive) {
if (!s_lstrcmp(lpTableAlias, lpValuesAlias))
break;
}
else {
if (!s_lstrcmpi(lpTableAlias, lpValuesAlias))
break;
}
/* It does not match. Try next table */
idxTables = lpSqlNodeTables->node.tables.Next;
}
//second pass : table name
if (idxTables == NO_SQLNODE) {
idxTables = lpSqlNode->node.select.Tables;
while (idxTables != NO_SQLNODE) {
/* Get pointer to the table */
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
/* Get pointer to this table */
idxTable = lpSqlNodeTables->node.tables.Table;
lpSqlNodeTable = ToNode(*lplpSql, idxTable);
/* Get Alias of this table */
idxAlias = lpSqlNodeTable->node.table.Name;
/* Leave loop if it matches */
lpTableAlias = ToString(*lplpSql, idxAlias);
if (fCaseSensitive) {
if (!s_lstrcmp(lpTableAlias, lpValuesAlias))
{
lpSqlNodeTable->node.table.Alias = idxAlias;
break;
}
}
else {
if (!s_lstrcmpi(lpTableAlias, lpValuesAlias))
{
lpSqlNodeTable->node.table.Alias = idxAlias;
break;
}
}
/* It does not match. Try next table */
idxTables = lpSqlNodeTables->node.tables.Next;
}
}
/* Error if not tables match */
if (idxTables == NO_SQLNODE) {
s_lstrcpy(lpstmt->szError, lpValuesAlias);
return ERR_TABLENOTFOUND;
}
/* Remove the <table>.* node */
if (idxValuesPrev == NO_SQLNODE)
lpSqlNode->node.select.Values = idxValues;
else {
lpSqlNodeValuesPrev = ToNode(*lplpSql, idxValuesPrev);
lpSqlNodeValuesPrev->node.values.Next = idxValues;
}
/* Loop through all the columns of the table */
lpTableHandle = lpSqlNodeTable->node.table.Handle;
ClassColumnInfoBase* cInfoBase = lpTableHandle->pColumnInfo;
LPISAM myISAM = lpTableHandle->lpISAM;
if ( !cInfoBase->IsValid() )
{
return ERR_COLUMNNOTFOUND;
}
//Store able alias before allocating memory
//in order to avoid bug
STRINGIDX idxTheAlias = lpSqlNodeTable->node.table.Alias;
STRINGIDX idxTheQual = lpSqlNodeTable->node.table.Qualifier;
UWORD cNumberOfCols = cInfoBase->GetNumberOfColumns();
char pColumnName [MAX_COLUMN_NAME_LENGTH+1];
//Sai added - fetch the column alias
//only filled in if using passthrough SQL, ignored otherwise
char pAliasName [MAX_COLUMN_NAME_LENGTH+1];
pAliasName[0] = 0;
for (idx = 0; idx < (SWORD) cNumberOfCols; idx++) {
if ( FAILED(cInfoBase->GetColumnName(idx, pColumnName, pAliasName)) )
{
return ERR_COLUMNNOTFOUND;
}
//Ignore any OLEMS specific columns which we want to hide
if (myISAM && !(myISAM->fSysProps))
{
if (_strnicmp("__", pColumnName, 2) == 0)
{
continue;
}
}
//Ignore any 'lazy' columns
BOOL fIsLazy = FALSE;
if ( cInfoBase->IsLazy(idx, fIsLazy) )
{
if (fIsLazy)
{
continue;
}
}
//Check if this column type is support
//if not we skip this column
if (! ISAMGetColumnType(lpTableHandle, (UWORD) idx) )
{
continue;
}
/* Create a node for this column */
idxColumn = AllocateNode(lplpSql, NODE_TYPE_COLUMN);
if (idxColumn == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
//Get new pointers
lpSqlNodeColumn = ToNode(*lplpSql, idxColumn);
lpSqlNodeTable = ToNode(*lplpSql, idxTable);
lpSqlNodeColumn->node.column.Tablealias = idxAlias;
lpSqlNodeColumn->node.column.Column = AllocateString(lplpSql,
(LPUSTR)pColumnName);
if (lpSqlNodeColumn->node.column.Column == NO_STRING)
return ERR_MEMALLOCFAIL;
if (lpSqlNodeTable->node.table.Alias != NO_STRING)
{
lpSqlNodeColumn->node.column.MatchedAlias = TRUE;
}
else
{
lpSqlNodeColumn->node.column.MatchedAlias = FALSE;
}
//New - for identical column names when using passthrough SQL
if ( pAliasName && lstrlen(pAliasName) )
{
lpSqlNodeColumn->node.column.Tablealias = AllocateString(lplpSql,
(LPUSTR)pAliasName);
}
//To avoid bug recalc lpSqlNodeColumn
lpSqlNodeColumn = ToNode(*lplpSql, idxColumn);
lpSqlNodeColumn->node.column.TableIndex = idxTable;
lpSqlNodeColumn->node.column.Qualifier = NO_STRING; //idxTheQual;
lpSqlNodeColumn->node.table.Handle = NULL;
lpSqlNodeColumn->node.column.Table = NO_SQLNODE;
lpSqlNodeColumn->node.column.Id = -1;
lpSqlNodeColumn->node.column.Value = NO_STRING;
lpSqlNodeColumn->node.column.InSortRecord = FALSE;
lpSqlNodeColumn->node.column.Offset = 0;
lpSqlNodeColumn->node.column.Length = 0;
lpSqlNodeColumn->node.column.DistinctOffset = 0;
lpSqlNodeColumn->node.column.DistinctLength = 0;
lpSqlNodeColumn->node.column.EnclosingStatement = NO_SQLNODE;
/* Put it on the list */
idxValuesNew = AllocateNode(lplpSql, NODE_TYPE_VALUES);
if (idxValuesNew == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
lpSqlNodeValues = ToNode(*lplpSql, idxValuesNew);
lpSqlNodeValues->node.values.Value = idxColumn;
lpSqlNodeValues->node.values.Alias = NO_STRING;
lpSqlNodeValues->node.values.Next = idxValues;
if (idxValuesPrev == NO_SQLNODE) {
lpSqlNode = ToNode(*lplpSql, idxNode);
lpSqlNode->node.select.Values = idxValuesNew;
}
else {
lpSqlNodeValuesPrev = ToNode(*lplpSql, idxValuesPrev);
lpSqlNodeValuesPrev->node.values.Next = idxValuesNew;
}
idxValuesPrev = idxValuesNew;
}
}
lpSqlNode = ToNode(*lplpSql, idxNode);
}
/* Check the ORDER BY columns */
err = SemanticCheck(lpstmt, lplpSql,lpSqlNode->node.select.Sortcolumns,
fIsGroupby, fCaseSensitive, NO_SQLNODE, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check that each group by column is on sort list (and put it */
/* there if it is not already there so the sort directive will */
/* be constructed correctly)... */
{
SQLNODEIDX idxGroupbycolumns;
LPSQLNODE lpSqlNodeGroupbycolumns;
LPSQLNODE lpSqlNodeColumnGroupby;
SQLNODEIDX idxSortcolumns;
SQLNODEIDX idxSortcolumnsPrev;
LPSQLNODE lpSqlNodeSortcolumns;
LPSQLNODE lpSqlNodeColumnSort;
SQLNODEIDX idxColumn;
SQLNODEIDX idxTableGroupby;
// LPUSTR lpszTableGroupby;
LPUSTR lpszColumnGroupby;
SQLNODEIDX idxTableSort;
// LPUSTR lpszTableSort;
LPUSTR lpszColumnSort;
idxGroupbycolumns = lpSqlNode->node.select.Groupbycolumns;
while (idxGroupbycolumns != NO_SQLNODE) {
/* Get this group by column */
lpSqlNodeGroupbycolumns = ToNode(*lplpSql, idxGroupbycolumns);
lpSqlNodeColumnGroupby = ToNode(*lplpSql,
lpSqlNodeGroupbycolumns->node.groupbycolumns.Column);
/* Get column name and table name of the group by column */
idxTableGroupby = lpSqlNodeColumnGroupby->node.column.TableIndex;
lpszColumnGroupby = ToString(*lplpSql,
lpSqlNodeColumnGroupby->node.column.Column);
/* Look for this column on the sort list. For each */
/* column in the sort list... */
idxSortcolumns = lpSqlNode->node.select.Sortcolumns;
idxSortcolumnsPrev = NO_SQLNODE;
while (idxSortcolumns != NO_SQLNODE) {
/* Get next element on the sort list */
lpSqlNodeSortcolumns = ToNode(*lplpSql, idxSortcolumns);
lpSqlNodeColumnSort = ToNode(*lplpSql,
lpSqlNodeSortcolumns->node.sortcolumns.Column);
/* Is it a column reference? */
if (lpSqlNodeColumnSort->sqlNodeType == NODE_TYPE_COLUMN) {
/* Yes. Get column name and table name of sort column */
idxTableSort = lpSqlNodeColumnSort->node.column.TableIndex;
lpszColumnSort = ToString(*lplpSql,
lpSqlNodeColumnSort->node.column.Column);
/* Leave if this sort column is the group by column */
if (idxTableSort == idxTableGroupby)
{
if (fCaseSensitive) {
// if (!s_lstrcmp(lpszTableSort, lpszTableGroupby) &&
// !s_lstrcmp(lpszColumnSort, lpszColumnGroupby))
if ( !s_lstrcmp(lpszColumnSort, lpszColumnGroupby) )
break;
}
else {
// if (!s_lstrcmpi(lpszTableSort, lpszTableGroupby) &&
// !s_lstrcmpi(lpszColumnSort, lpszColumnGroupby))
if ( !s_lstrcmpi(lpszColumnSort, lpszColumnGroupby) )
break;
}
}
}
/* Get next sort column */
idxSortcolumnsPrev = idxSortcolumns;
idxSortcolumns = lpSqlNodeSortcolumns->node.sortcolumns.Next;
}
/* Was group by columnn found in the sort list? */
if (idxSortcolumns == NO_SQLNODE) {
/* No. A new entry will be needed. Create a node for */
/* the column */
idxColumn = AllocateNode(lplpSql, NODE_TYPE_COLUMN);
if (idxColumn == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
lpSqlNodeColumnSort = ToNode(*lplpSql, idxColumn);
/* Recalculate these pointers since the Alloc above */
/* may have moved them */
/* addeed th enext line */
lpSqlNodeGroupbycolumns = ToNode (*lplpSql, idxGroupbycolumns);
lpSqlNodeColumnGroupby = ToNode(*lplpSql,
lpSqlNodeGroupbycolumns->node.groupbycolumns.Column);
/* Fill in the node */
lpSqlNodeColumnSort->node.column.Tablealias =
lpSqlNodeColumnGroupby->node.column.Tablealias;
lpSqlNodeColumnSort->node.column.Column =
lpSqlNodeColumnGroupby->node.column.Column;
lpSqlNodeColumnSort->node.column.Qualifier =
lpSqlNodeColumnGroupby->node.column.Qualifier;
lpSqlNodeColumnSort->node.column.TableIndex =
lpSqlNodeColumnGroupby->node.column.TableIndex;
lpSqlNodeColumnSort->node.column.MatchedAlias =
lpSqlNodeColumnGroupby->node.column.MatchedAlias;
lpSqlNodeColumnSort->node.column.Table = NO_SQLNODE;
lpSqlNodeColumnSort->node.column.Id = -1;
lpSqlNodeColumnSort->node.column.Value = NO_STRING;
lpSqlNodeColumnSort->node.column.InSortRecord = FALSE;
lpSqlNodeColumnSort->node.column.Offset = 0;
lpSqlNodeColumnSort->node.column.Length = 0;
lpSqlNodeColumnSort->node.column.DistinctOffset = 0;
lpSqlNodeColumnSort->node.column.DistinctLength = 0;
lpSqlNodeColumnSort->node.column.EnclosingStatement = NO_SQLNODE;
/* Create sort list element */
idxSortcolumns = AllocateNode(lplpSql,
NODE_TYPE_SORTCOLUMNS);
if (idxSortcolumns == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
lpSqlNodeSortcolumns = ToNode(*lplpSql, idxSortcolumns);
lpSqlNodeSortcolumns->node.sortcolumns.Column = idxColumn;
lpSqlNodeSortcolumns->node.sortcolumns.Descending = FALSE;
lpSqlNodeSortcolumns->node.sortcolumns.Next = NO_SQLNODE;
/* Recalculate these pointers since the Alloc above */
/* may have moved them */
lpSqlNodeGroupbycolumns =
ToNode(*lplpSql, idxGroupbycolumns);
lpSqlNode = ToNode(*lplpSql, idxNode);
/* Put it on the sort list */
if (idxSortcolumnsPrev == NO_SQLNODE)
lpSqlNode->node.select.Sortcolumns = idxSortcolumns;
else {
lpSqlNodeSortcolumns =
ToNode(*lplpSql, idxSortcolumnsPrev);
lpSqlNodeSortcolumns->node.sortcolumns.Next =
idxSortcolumns;
}
/* Semantic check the newly created nodes */
err = SemanticCheck(lpstmt, lplpSql, idxSortcolumns,
fIsGroupby, fCaseSensitive, NO_SQLNODE, idxNode);
}
/* Look at next group by column */
idxGroupbycolumns =
lpSqlNodeGroupbycolumns->node.groupbycolumns.Next;
}
}
/* Check the select list */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.select.Values,
fIsGroupby, fCaseSensitive, NO_SQLNODE, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the WHERE clause */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.select.Predicate,
FALSE, fCaseSensitive, NO_SQLNODE, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the HAVING clause */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.select.Having,
fIsGroupby, fCaseSensitive, NO_SQLNODE, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Build the sorting directive and determine the overall key size. */
/* At the same time check to make sure that there are not too many */
/* columns in ORDER BY and that character or binary keys are not */
/* too big. */
if (lpSqlNode->node.select.Sortcolumns != NO_SQLNODE) {
SQLNODEIDX idxSortcolumns;
LPSQLNODE lpSqlNodeSortcolumns;
LPSQLNODE lpSqlNodeColumn;
UDWORD length;
SQLNODEIDX idxTables;
LPSQLNODE lpSqlNodeTables;
#define NUM_LEN 5
UCHAR szSortDirective[10 + NUM_LEN +
(MAX_COLUMNS_IN_ORDER_BY * (6 + (2 * NUM_LEN)))
+ 3 + MAX_PATHNAME_SIZE];
szSortDirective[0] = 0;
SQLNODEIDX idxAggregate;
LPSQLNODE lpSqlNodeAggregate;
/* For each sort column... */
s_lstrcpy(szSortDirective, "S(");
idxSortcolumns = lpSqlNode->node.select.Sortcolumns;
while (idxSortcolumns != NO_SQLNODE) {
/* Is this node on the group by list ? */
lpSqlNodeSortcolumns = ToNode(*lplpSql, idxSortcolumns);
lpSqlNodeColumn = ToNode(*lplpSql,
lpSqlNodeSortcolumns->node.sortcolumns.Column);
if ((lpSqlNode->node.select.Groupbycolumns == NO_SQLNODE) ||
(lpSqlNodeColumn->sqlNodeType != NODE_TYPE_COLUMN)) {
/* No. Add this sort column to the count */
count++;
/* Error if too many sort columns */
if (count > MAX_COLUMNS_IN_ORDER_BY)
return ERR_ORDERBYTOOLARGE;
/* Get length of the column. */
switch (lpSqlNodeColumn->sqlDataType) {
case TYPE_DOUBLE:
length = sizeof(double);
break;
case TYPE_NUMERIC:
length = 2 + lpSqlNodeColumn->sqlPrecision;
break;
case TYPE_INTEGER:
length = sizeof(double);
break;
case TYPE_CHAR:
length = lpSqlNodeColumn->sqlPrecision;
if (length > MAX_CHAR_LITERAL_LENGTH) {
if (lpSqlNodeColumn->sqlNodeType == NODE_TYPE_COLUMN)
s_lstrcpy(lpstmt->szError,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column));
else
s_lstrcpy(lpstmt->szError, "<expression>");
return ERR_CANTORDERBYONTHIS;
}
break;
case TYPE_BINARY:
length = lpSqlNodeColumn->sqlPrecision;
if (length > MAX_BINARY_LITERAL_LENGTH) {
if (lpSqlNodeColumn->sqlNodeType == NODE_TYPE_COLUMN)
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column));
else
s_lstrcpy(lpstmt->szError, "<expression>");
return ERR_CANTORDERBYONTHIS;
}
break;
case TYPE_DATE:
length = 10;
break;
case TYPE_TIME:
length = 8;
break;
case TYPE_TIMESTAMP:
if (TIMESTAMP_SCALE > 0)
length = 20 + TIMESTAMP_SCALE;
else
length = 19;
break;
default:
if (lpSqlNodeColumn->sqlNodeType == NODE_TYPE_COLUMN)
s_lstrcpy(lpstmt->szError,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column));
else
s_lstrcpy((char*)lpstmt->szError, "<expression>");
return ERR_CANTORDERBYONTHIS;
}
/* Put offset of the key column in the sort directive */
wsprintf((LPSTR) (szSortDirective + s_lstrlen((LPSTR)szSortDirective)),
"%lu,", offset);
/* Adjust offset */
offset += (length);
offset++; /* for the IS NULL flag */
}
else {
/* Yes. Get length */
length = lpSqlNodeColumn->node.column.Length;
/* Put offset of the key column in the sort directive */
wsprintf((LPSTR)(szSortDirective + s_lstrlen((LPSTR)szSortDirective)),
"%lu,", lpSqlNodeColumn->node.column.Offset);
}
/* Put length of the key column in the sort directive */
wsprintf((LPSTR)(szSortDirective + s_lstrlen((LPSTR)szSortDirective)),
"%lu,", length);
/* Put type of the key column in the sort directive */
switch (lpSqlNodeColumn->sqlDataType) {
case TYPE_DOUBLE:
s_lstrcat((LPSTR)szSortDirective, "E,");
break;
case TYPE_NUMERIC:
s_lstrcat((LPSTR)szSortDirective, "N,");
break;
case TYPE_INTEGER:
s_lstrcat((LPSTR)szSortDirective, "E,");
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
s_lstrcat((LPSTR)szSortDirective, "C,");
break;
default:
return ERR_INTERNAL;
}
/* Put direction of the key column in the sort directive */
if (lpSqlNodeSortcolumns->node.sortcolumns.Descending)
s_lstrcat((char*)szSortDirective, "D");
else
s_lstrcat((char*)szSortDirective, "A");
/* Go to next sort column */
idxSortcolumns = lpSqlNodeSortcolumns->node.sortcolumns.Next;
if (idxSortcolumns != NO_SQLNODE)
s_lstrcat((char*)szSortDirective, ",");
}
/* Save the sort key size */
lpSqlNode->node.select.SortKeysize = offset-1;
/* Is there a GROUP BY statement? */
if ((lpSqlNode->node.select.Groupbycolumns == NO_SQLNODE) &&
(!lpSqlNode->node.select.ImplicitGroupby)) {
/* No. Save offset of the bookmark */
lpSqlNode->node.select.SortBookmarks = offset;
/* For each table in table list, add bookmark size to offset */
idxTables = lpSqlNode->node.select.Tables;
while (idxTables != NO_SQLNODE) {
/* Update offset */
offset += (sizeof(ISAMBOOKMARK));
/* Get pointer to the next table */
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
idxTables = lpSqlNodeTables->node.tables.Next;
}
}
else {
/* Yes. Calculate the offset of each aggregate field */
idxAggregate = lpSqlNode->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Save offset of the aggregate */
lpSqlNodeAggregate = ToNode(*lplpSql, idxAggregate);
lpSqlNodeAggregate->node.aggregate.Offset = offset;
/* Update offset */
offset += (lpSqlNodeAggregate->node.aggregate.Length + 1);
/* Get pointer to the next aggregate */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
}
offset--;
s_lstrcat((char*)szSortDirective, ")");
/* Put record size into sort directive */
s_lstrcat((char*)szSortDirective, "F(FIX,");
wsprintf((LPSTR)(szSortDirective + s_lstrlen((char*)szSortDirective)),
"%lu", offset);
lstrcat((char*)szSortDirective, ")");
/* Put in work drive */
s_lstrcat(szSortDirective, "W(");
#ifdef WIN32
if (!GetTempPath(MAX_PATHNAME_SIZE+1, (LPSTR)
szSortDirective + s_lstrlen(szSortDirective)))
return ERR_SORT;
if (szSortDirective[s_lstrlen(szSortDirective)-1] != '\\')
s_lstrcat(szSortDirective, "\\");
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szSortDirective +
s_lstrlen(szSortDirective));
while (szSortDirective[s_lstrlen(szSortDirective)-1] != '\\')
szSortDirective[s_lstrlen(szSortDirective)-1] = '\0';
#endif
s_lstrcat(szSortDirective, ")");
/* Save the directive */
lpSqlNode->node.select.SortDirective = AllocateString(lplpSql,
(LPUSTR)szSortDirective);
if (lpSqlNode->node.select.SortDirective == NO_STRING)
return ERR_MEMALLOCFAIL;
/* Save the sort record size */
lpSqlNode->node.select.SortRecordsize = offset;
}
/* If there is no group by list originally but there is a group by */
/* list now, there was an aggregate in the select list. Calculate */
/* the offset of each aggregate field */
if (lpSqlNode->node.select.ImplicitGroupby) {
SQLNODEIDX idxAggregate;
LPSQLNODE lpSqlNodeAggregate;
idxAggregate = lpSqlNode->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
/* Save offset of the aggregate */
lpSqlNodeAggregate = ToNode(*lplpSql, idxAggregate);
lpSqlNodeAggregate->node.aggregate.Offset = offset;
/* Update offset */
offset += (lpSqlNodeAggregate->node.aggregate.Length + 1);
/* Get pointer to the next aggregate */
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
/* Adjust the offset */
offset--;
/* Save the sort record size */
lpSqlNode->node.select.SortRecordsize = offset;
}
/* Build the sorting directive for SELECT DISTINCT and determine the */
/* overall key size. At the same time check to make sure that there */
/* are not too many columns in ORDER BY and that character or binary */
/* keys are not too big. */
if (lpSqlNode->node.select.Distinct) {
SQLNODEIDX idxValues;
LPSQLNODE lpSqlNodeValues;
LPSQLNODE lpSqlNodeExpression;
UDWORD length;
#define NUM_LEN 5
UCHAR szSortDirective[19 + (4 * NUM_LEN) +
(MAX_COLUMNS_IN_ORDER_BY * (6 + (2 * NUM_LEN)))
+ 3 + MAX_PATHNAME_SIZE];
/* For each sort column... */
count = 0;
offset = NUM_LEN + 1;
s_lstrcpy(szSortDirective, "S(");
idxValues = lpSqlNode->node.select.Values;
while (idxValues != NO_SQLNODE) {
/* Is this node of interest? */
lpSqlNodeValues = ToNode(*lplpSql, idxValues);
lpSqlNodeExpression = ToNode(*lplpSql,
lpSqlNodeValues->node.values.Value);
switch (lpSqlNodeExpression->sqlNodeType) {
case NODE_TYPE_COLUMN:
case NODE_TYPE_AGGREGATE:
case NODE_TYPE_ALGEBRAIC:
case NODE_TYPE_SCALAR:
/* Yes. Add this sort column to the count */
count++;
/* Error if too many sort columns */
if (count > MAX_COLUMNS_IN_ORDER_BY)
return ERR_ORDERBYTOOLARGE;
/* Get length of the column. */
switch (lpSqlNodeExpression->sqlDataType) {
case TYPE_DOUBLE:
length = sizeof(double);
break;
case TYPE_NUMERIC:
length = 2 + lpSqlNodeExpression->sqlPrecision;
break;
case TYPE_INTEGER:
length = sizeof(double);
break;
case TYPE_CHAR:
length = lpSqlNodeExpression->sqlPrecision;
if (length > MAX_CHAR_LITERAL_LENGTH) {
if (lpSqlNodeExpression->sqlNodeType == NODE_TYPE_COLUMN)
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNodeExpression->node.column.Column));
else
s_lstrcpy((char*)lpstmt->szError, "<expression>");
return ERR_CANTORDERBYONTHIS;
}
break;
case TYPE_BINARY:
length = lpSqlNodeExpression->sqlPrecision;
if (length > MAX_BINARY_LITERAL_LENGTH) {
if (lpSqlNodeExpression->sqlNodeType == NODE_TYPE_COLUMN)
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNodeExpression->node.column.Column));
else
s_lstrcpy((char*)lpstmt->szError, "<expression>");
return ERR_CANTORDERBYONTHIS;
}
break;
case TYPE_DATE:
length = 10;
break;
case TYPE_TIME:
length = 8;
break;
case TYPE_TIMESTAMP:
if (TIMESTAMP_SCALE > 0)
length = 20 + TIMESTAMP_SCALE;
else
length = 19;
break;
default:
if (lpSqlNodeExpression->sqlNodeType == NODE_TYPE_COLUMN)
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNodeExpression->node.column.Column));
else
s_lstrcpy((char*)lpstmt->szError, "<expression>");
return ERR_CANTORDERBYONTHIS;
}
/* Put offset of the key column in the sort directive */
wsprintf((LPSTR)(szSortDirective + s_lstrlen((char*)szSortDirective)),
"%lu,", offset);
/* Save offset and length */
switch (lpSqlNodeExpression->sqlNodeType) {
case NODE_TYPE_COLUMN:
lpSqlNodeExpression->node.column.DistinctOffset = offset;
lpSqlNodeExpression->node.column.DistinctLength = length;
break;
case NODE_TYPE_AGGREGATE:
lpSqlNodeExpression->node.aggregate.DistinctOffset = offset;
lpSqlNodeExpression->node.aggregate.DistinctLength = length;
break;
case NODE_TYPE_ALGEBRAIC:
lpSqlNodeExpression->node.algebraic.DistinctOffset = offset;
lpSqlNodeExpression->node.algebraic.DistinctLength = length;
break;
case NODE_TYPE_SCALAR:
lpSqlNodeExpression->node.scalar.DistinctOffset = offset;
lpSqlNodeExpression->node.scalar.DistinctLength = length;
break;
default:
return ERR_INTERNAL;
}
/* Adjust offset */
offset += (length);
offset++; /* for the IS NULL flag */
/* Put length of the key column in the sort directive */
wsprintf((LPSTR)(szSortDirective + s_lstrlen((char*)szSortDirective)),
"%lu,", length);
/* Put type of the key column in the sort directive */
switch (lpSqlNodeExpression->sqlDataType) {
case TYPE_DOUBLE:
s_lstrcat(szSortDirective, "E,");
break;
case TYPE_NUMERIC:
s_lstrcat(szSortDirective, "N,");
break;
case TYPE_INTEGER:
s_lstrcat(szSortDirective, "E,");
break;
case TYPE_CHAR:
case TYPE_BINARY:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
s_lstrcat(szSortDirective, "C,");
break;
default:
return ERR_INTERNAL;
}
/* Put direction of the key column in the sort directive */
s_lstrcat(szSortDirective, "A");
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:
break;
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;
}
/* Go to next sort column */
idxValues = lpSqlNodeValues->node.values.Next;
if (idxValues != NO_SQLNODE)
s_lstrcat(szSortDirective, ",");
}
offset--;
/* If no fields in sort record, put a constant in */
if (offset == NUM_LEN) {
offset = 3;
s_lstrcat(szSortDirective, "1,3,C,A");
}
s_lstrcat(szSortDirective, ")");
/* Put duplicate removal into sort directive */
s_lstrcat(szSortDirective, "DUPO(B");
wsprintf((LPSTR) szSortDirective + s_lstrlen(szSortDirective),
"%lu", offset);
s_lstrcat(szSortDirective, ",");
wsprintf((LPSTR) szSortDirective + s_lstrlen(szSortDirective),
"%u", (WORD) NUM_LEN+1);
s_lstrcat(szSortDirective, ",");
wsprintf((LPSTR) szSortDirective + s_lstrlen(szSortDirective),
"%lu", offset - NUM_LEN);
s_lstrcat(szSortDirective, ")");
/* Put record size into sort directive */
s_lstrcat(szSortDirective, "F(FIX,");
wsprintf((LPSTR) szSortDirective + s_lstrlen(szSortDirective),
"%lu", offset);
s_lstrcat(szSortDirective, ")");
/* Put in work drive */
s_lstrcat(szSortDirective, "W(");
#ifdef WIN32
if (!GetTempPath(MAX_PATHNAME_SIZE+1, (LPSTR)
szSortDirective + s_lstrlen(szSortDirective)))
return ERR_SORT;
if (szSortDirective[s_lstrlen(szSortDirective)-1] != '\\')
s_lstrcat(szSortDirective, "\\");
#else
GetTempFileName(NULL, "LEM", 0, (LPSTR) szSortDirective +
+ s_lstrlen(szSortDirective));
while (szSortDirective[s_lstrlen(szSortDirective)-1] != '\\')
szSortDirective[s_lstrlen(szSortDirective)-1] = '\0';
#endif
s_lstrcat(szSortDirective, ")");
/* Save the directive */
lpSqlNode->node.select.DistinctDirective = AllocateString(lplpSql,
szSortDirective);
if (lpSqlNode->node.select.DistinctDirective == NO_STRING)
return ERR_MEMALLOCFAIL;
/* Save the sort record size */
lpSqlNode->node.select.DistinctRecordsize = offset;
}
/* Allocate space for the sortfile name if need be */
if ((lpSqlNode->node.select.Distinct) ||
(lpSqlNode->node.select.ImplicitGroupby) ||
(lpSqlNode->node.select.Groupbycolumns != NO_SQLNODE) ||
(lpSqlNode->node.select.Sortcolumns != NO_SQLNODE)) {
lpSqlNode->node.select.SortfileName = AllocateSpace(lplpSql,
MAX_PATHNAME_SIZE+1);
if (lpSqlNode->node.select.SortfileName == NO_STRING)
return ERR_MEMALLOCFAIL;
}
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC SemanticCheck(LPSTMT lpstmt, LPSQLTREE FAR *lplpSql,
SQLNODEIDX idxNode, BOOL fIsGroupby, BOOL fCaseSensitive,
SQLNODEIDX idxNodeTableOuterJoinFromTables,
SQLNODEIDX idxEnclosingStatement)
/* Walks a parse tree, checks it for semantic correctness, and fills in */
/* the semantic information. */
{
LPSQLNODE lpSqlNode;
RETCODE err;
LPUSTR ptr;
if (idxNode == NO_SQLNODE)
return ERR_SUCCESS;
lpSqlNode = ToNode(*lplpSql, idxNode);
err = ERR_SUCCESS;
switch (lpSqlNode->sqlNodeType) {
case NODE_TYPE_NONE:
break;
case NODE_TYPE_ROOT:
/* Check the statement */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.root.sql,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
break;
case NODE_TYPE_CREATE:
/* Make sure table name is not too long */
ptr = ToString(*lplpSql, lpSqlNode->node.create.Table);
if (s_lstrlen(ptr) > ISAMMaxTableNameLength(lpstmt->lpdbc->lpISAM)) {
s_lstrcpy(lpstmt->szError, ptr);
return ERR_INVALIDTABLENAME;
}
/* Check the new column definitions */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.create.Columns,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
break;
case NODE_TYPE_DROP:
/* Make sure table name is not too long */
ptr = ToString(*lplpSql, lpSqlNode->node.drop.Table);
if (s_lstrlen(ptr) > ISAMMaxTableNameLength(lpstmt->lpdbc->lpISAM)) {
s_lstrcpy(lpstmt->szError, ptr);
return ERR_INVALIDTABLENAME;
}
break;
case NODE_TYPE_SELECT:
err = SelectCheck(lpstmt, lplpSql, idxNode, fCaseSensitive,
idxEnclosingStatement);
break;
case NODE_TYPE_INSERT:
{
/* Check the table */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.insert.Table,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Is there a column list? */
if (lpSqlNode->node.insert.Columns == NO_SQLNODE) {
LPSQLNODE lpSqlNodeTable;
STRINGIDX idxAlias;
LPISAMTABLEDEF lpTableHandle;
SQLNODEIDX idxColumns;
LPSQLNODE lpSqlNodeColumns;
SQLNODEIDX idxColumnsPrev;
LPSQLNODE lpSqlNodeColumnsPrev;
SQLNODEIDX idxColumn;
LPSQLNODE lpSqlNodeColumn;
SWORD idx;
/* No. Get node Alias of this table */
lpSqlNodeTable = ToNode(*lplpSql, lpSqlNode->node.insert.Table);
idxAlias = lpSqlNodeTable->node.table.Alias;
/* Loop through all the columns of this table */
lpTableHandle = lpSqlNodeTable->node.table.Handle;
idxColumnsPrev = NO_SQLNODE;
ClassColumnInfoBase* cInfoBase = lpTableHandle->pColumnInfo;
if ( !cInfoBase->IsValid() )
{
return ERR_COLUMNNOTFOUND;
}
UWORD cNumberOfCols = cInfoBase->GetNumberOfColumns();
char pColumnName [MAX_COLUMN_NAME_LENGTH+1];
for (idx = 0; idx < (SWORD) cNumberOfCols; idx++)
{
if ( FAILED(cInfoBase->GetColumnName(idx, pColumnName)) )
{
return ERR_COLUMNNOTFOUND;
}
/* Create a node for this column */
idxColumn = AllocateNode(lplpSql, NODE_TYPE_COLUMN);
if (idxColumn == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
lpSqlNodeColumn = ToNode(*lplpSql, idxColumn);
lpSqlNodeColumn->node.column.Tablealias = idxAlias;
lpSqlNodeColumn->node.column.Column = AllocateString(lplpSql,
(LPUSTR)pColumnName);
if (lpSqlNodeColumn->node.column.Column == NO_STRING)
return ERR_MEMALLOCFAIL;
lpSqlNodeColumn->node.column.Table =
lpSqlNode->node.insert.Table;
lpSqlNodeColumn->node.column.Id = idx;
lpSqlNodeColumn->node.column.Value = NO_STRING;
lpSqlNodeColumn->node.column.InSortRecord = FALSE;
lpSqlNodeColumn->node.column.Offset = 0;
lpSqlNodeColumn->node.column.Length = 0;
lpSqlNodeColumn->node.column.DistinctOffset = 0;
lpSqlNodeColumn->node.column.DistinctLength = 0;
lpSqlNodeColumn->node.column.EnclosingStatement = NO_SQLNODE;
/* Put it on the list */
idxColumns = AllocateNode(lplpSql, NODE_TYPE_COLUMNS);
if (idxColumns == NO_SQLNODE)
return ERR_MEMALLOCFAIL;
lpSqlNodeColumns = ToNode(*lplpSql, idxColumns);
lpSqlNodeColumns->node.columns.Column = idxColumn;
lpSqlNodeColumns->node.columns.Next = NO_SQLNODE;
if (idxColumnsPrev == NO_SQLNODE) {
lpSqlNode = ToNode(*lplpSql, idxNode);
lpSqlNode->node.insert.Columns = idxColumns;
}
else {
lpSqlNodeColumnsPrev = ToNode(*lplpSql, idxColumnsPrev);
lpSqlNodeColumnsPrev->node.columns.Next = idxColumns;
}
idxColumnsPrev = idxColumns;
lpSqlNode = ToNode(*lplpSql, idxNode);
}
lpSqlNode = ToNode(*lplpSql, idxNode);
}
/* Check the column list */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.insert.Columns,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the value list */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.insert.Values,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Look at each value */
{
SQLNODEIDX idxValues;
LPSQLNODE lpSqlNodeValues;
LPSQLNODE lpSqlNodeValue;
SQLNODEIDX idxColumns;
LPSQLNODE lpSqlNodeColumns;
LPSQLNODE lpSqlNodeSelect;
/* Get list of insert values */
lpSqlNodeSelect = ToNode(*lplpSql, lpSqlNode->node.insert.Values);
if (lpSqlNodeSelect->sqlNodeType == NODE_TYPE_SELECT)
idxValues = lpSqlNodeSelect->node.select.Values;
else
idxValues = lpSqlNode->node.insert.Values;
/* For each value... */
idxColumns = lpSqlNode->node.insert.Columns;
while (idxValues != NO_SQLNODE) {
/* Error if no more columns */
if (idxColumns == NO_SQLNODE)
return ERR_UNEQUALINSCOLS;
/* Get the value */
lpSqlNodeValues = ToNode(*lplpSql, idxValues);
lpSqlNodeValue = ToNode(*lplpSql, lpSqlNodeValues->node.values.Value);
/* Get the column the value is for */
lpSqlNodeColumns = ToNode(*lplpSql, idxColumns);
/* Sub-select? */
if (lpSqlNodeSelect->sqlNodeType != NODE_TYPE_SELECT) {
/* No. Make sure the value is NUMERIC, STRING, */
/* PARAMETER, USER, NULL, DATE, TIME, or TIMESTAMP */
switch (lpSqlNodeValue->sqlNodeType) {
case NODE_TYPE_ALGEBRAIC:
case NODE_TYPE_SCALAR:
case NODE_TYPE_AGGREGATE:
case NODE_TYPE_COLUMN:
return ERR_INVALIDINSVAL;
case NODE_TYPE_PARAMETER:
case NODE_TYPE_NULL:
case NODE_TYPE_NUMERIC:
case NODE_TYPE_STRING:
case NODE_TYPE_USER:
case NODE_TYPE_DATE:
case NODE_TYPE_TIME:
case NODE_TYPE_TIMESTAMP:
break;
default:
return ERR_INTERNAL;
}
}
/* Make sure value is of the proper type */
err = TypeCheck(lpstmt, *lplpSql,
lpSqlNodeColumns->node.columns.Column,
lpSqlNodeValues->node.values.Value, OP_NONE,
NULL, NULL, NULL, NULL);
if (err != ERR_SUCCESS)
return err;
/* Look at next element */
idxValues = lpSqlNodeValues->node.values.Next;
idxColumns = lpSqlNodeColumns->node.columns.Next;
}
/* Error if extra columns */
if (idxColumns != NO_SQLNODE)
return ERR_UNEQUALINSCOLS;
}
}
break;
case NODE_TYPE_DELETE:
/* Check the table */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.delet.Table,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the predicate */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.delet.Predicate,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
break;
case NODE_TYPE_UPDATE:
/* Check the table */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.update.Table,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the update values */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.update.Updatevalues,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the predicate */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.update.Predicate,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
break;
case NODE_TYPE_CREATEINDEX:
{
SQLNODEIDX idxSortcolumns;
LPSQLNODE lpSqlNodeSortcolumns;
UWORD count;
/* Make sure index name is not too long */
ptr = ToString(*lplpSql, lpSqlNode->node.createindex.Index);
if (s_lstrlen(ptr) > MAX_INDEX_NAME_LENGTH) {
s_lstrcpy(lpstmt->szError, ptr);
return ERR_INVALIDINDEXNAME;
}
/* Check the table */
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNode->node.createindex.Table,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Check the list of columns */
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNode->node.createindex.Columns,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables, idxNode);
if (err != ERR_SUCCESS)
return err;
/* Make sure there aren't too many columns */
idxSortcolumns = lpSqlNode->node.createindex.Columns;
count = 0;
while (idxSortcolumns != NO_SQLNODE) {
lpSqlNodeSortcolumns =
ToNode(lpstmt->lpSqlStmt, idxSortcolumns);
count++;
idxSortcolumns = lpSqlNodeSortcolumns->node.sortcolumns.Next;
}
if (count > MAX_COLUMNS_IN_INDEX) {
return ERR_TOOMANYINDEXCOLS;
}
}
break;
case NODE_TYPE_DROPINDEX:
/* Make sure index name is not too long */
ptr = ToString(*lplpSql, lpSqlNode->node.dropindex.Index);
if (s_lstrlen(ptr) > MAX_INDEX_NAME_LENGTH) {
s_lstrcpy(lpstmt->szError, ptr);
return ERR_INVALIDINDEXNAME;
}
break;
case NODE_TYPE_PASSTHROUGH:
s_lstrcpy((LPSTR)lpstmt->szError, "CREATE, DROP, SELECT, INSERT, UPDATE, or DELETE");
return ERR_EXPECTEDOTHER;
case NODE_TYPE_TABLES:
/* Check the table */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.tables.Table,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check the rest of the list */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.tables.Next,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Error if any correlation name reused */
{
LPUSTR lpstrAlias;
SQLNODEIDX idxTables;
LPSQLNODE lpSqlNodeTables;
LPSQLNODE lpSqlNodeTable;
/* Get the alias for this table */
lpSqlNodeTable = ToNode(*lplpSql, lpSqlNode->node.tables.Table);
if (lpSqlNodeTable->node.table.Alias != NO_STRING)
{
lpstrAlias = ToString(*lplpSql, lpSqlNodeTable->node.table.Alias);
/* For each table on the rest of the list */
idxTables = lpSqlNode->node.tables.Next;
while (idxTables != NO_SQLNODE) {
/* Get pointer to table node */
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
lpSqlNodeTable = ToNode(*lplpSql, lpSqlNodeTables->node.tables.Table);
/* Error if its name is the same */
if (lpSqlNodeTable->node.table.Alias != NO_STRING)
{
if (fCaseSensitive) {
if (!s_lstrcmp(lpstrAlias,
ToString(*lplpSql, lpSqlNodeTable->node.table.Alias))) {
s_lstrcpy((char*)lpstmt->szError, lpstrAlias);
return ERR_ALIASINUSE;
}
}
else {
if (!s_lstrcmpi(lpstrAlias,
ToString(*lplpSql, lpSqlNodeTable->node.table.Alias))) {
s_lstrcpy((char*)lpstmt->szError, lpstrAlias);
return ERR_ALIASINUSE;
}
}
}
/* Go to next element */
idxTables = lpSqlNodeTables->node.tables.Next;
}
}
{
LPSQLNODE lpSqlNodeTable;
/* Check the outer join predicate (if any) */
lpSqlNodeTable = ToNode(*lplpSql, lpSqlNode->node.tables.Table);
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNodeTable->node.table.OuterJoinPredicate,
FALSE, fCaseSensitive,
lpSqlNodeTable->node.table.OuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
}
}
break;
case NODE_TYPE_VALUES:
while (TRUE) {
/* Check this value */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.values.Value,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check the rest of the list */
if (lpSqlNode->node.values.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(*lplpSql, lpSqlNode->node.values.Next);
}
break;
case NODE_TYPE_COLUMNS:
while (TRUE) {
/* Check this column */
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNode->node.columns.Column,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check the rest of the list */
if (lpSqlNode->node.columns.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(*lplpSql, lpSqlNode->node.columns.Next);
}
lpSqlNode = ToNode(*lplpSql, idxNode);
/* Error if any column on list more than once */
{
LPUSTR lpstrName;
SQLNODEIDX idxColumns;
LPSQLNODE lpSqlNodeColumns;
LPSQLNODE lpSqlNodeColumn;
/* Get the name for this column */
lpSqlNodeColumn = ToNode(*lplpSql, lpSqlNode->node.columns.Column);
lpstrName = ToString(*lplpSql, lpSqlNodeColumn->node.column.Column);
/* For each column on the rest of the list */
idxColumns = lpSqlNode->node.columns.Next;
while (idxColumns != NO_SQLNODE) {
/* Get pointer to table node */
lpSqlNodeColumns = ToNode(*lplpSql, idxColumns);
lpSqlNodeColumn = ToNode(*lplpSql, lpSqlNodeColumns->node.columns.Column);
/* Error if its name is the same */
if (fCaseSensitive) {
if (!s_lstrcmp(lpstrName,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column))) {
s_lstrcpy(lpstmt->szError, lpstrName);
return ERR_COLUMNONLIST;
}
}
else {
if (!s_lstrcmpi(lpstrName,
ToString(*lplpSql, lpSqlNodeColumn->node.column.Column))) {
s_lstrcpy(lpstmt->szError, lpstrName);
return ERR_COLUMNONLIST;
}
}
/* Go to next element */
idxColumns = lpSqlNodeColumns->node.columns.Next;
}
}
break;
case NODE_TYPE_SORTCOLUMNS:
while (TRUE) {
LPSQLNODE lpSqlNodeSort;
LPSQLNODE lpSqlNodeStmt;
SQLNODEIDX idxValues;
SWORD count;
LPSQLNODE lpSqlNodeValues;
LPSQLNODE lpSqlNodeColumn;
/* Check this column */
err = SemanticCheck(lpstmt,
lplpSql,lpSqlNode->node.sortcolumns.Column,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Was an ordinal position in the select list given as sort? */
lpSqlNodeSort = ToNode(*lplpSql, lpSqlNode->node.sortcolumns.Column);
if (lpSqlNodeSort->sqlNodeType == NODE_TYPE_NUMERIC) {
/* No. Get the select list */
lpSqlNodeStmt = ToNode(*lplpSql, idxEnclosingStatement);
if (lpSqlNodeStmt->sqlNodeType != NODE_TYPE_SELECT)
return ERR_INTERNAL;
/* Find the element in the select list */
idxValues = lpSqlNodeStmt->node.select.Values;
count = 1;
while (TRUE) {
if (idxValues == NO_SQLNODE)
return ERR_ORDINALTOOLARGE;
lpSqlNodeValues = ToNode(*lplpSql, idxValues);
if (count == (SWORD) lpSqlNodeSort->node.numeric.Value)
break;
idxValues = lpSqlNodeValues->node.values.Next;
count++;
}
lpSqlNodeColumn = ToNode(*lplpSql,
lpSqlNodeValues->node.values.Value);
/* Error if a column reference was not given */
if (lpSqlNodeColumn->sqlNodeType != NODE_TYPE_COLUMN)
return ERR_ORDERBYCOLUMNONLY;
/* Convert the sort node to a column reference */
lpSqlNodeSort->sqlNodeType = NODE_TYPE_COLUMN;
lpSqlNodeSort->sqlDataType = TYPE_UNKNOWN;
lpSqlNodeSort->sqlSqlType = SQL_TYPE_NULL;
lpSqlNodeSort->sqlPrecision = 0;
lpSqlNodeSort->sqlScale = NO_SCALE;
lpSqlNodeSort->value.String = NULL;
lpSqlNodeSort->value.Double = 0.0;
lpSqlNodeSort->value.Date.year = 0;
lpSqlNodeSort->value.Date.month = 0;
lpSqlNodeSort->value.Date.day = 0;
lpSqlNodeSort->value.Time.hour = 0;
lpSqlNodeSort->value.Time.minute = 0;
lpSqlNodeSort->value.Time.second = 0;
lpSqlNodeSort->value.Timestamp.year = 0;
lpSqlNodeSort->value.Timestamp.month = 0;
lpSqlNodeSort->value.Timestamp.day = 0;
lpSqlNodeSort->value.Timestamp.hour = 0;
lpSqlNodeSort->value.Timestamp.minute = 0;
lpSqlNodeSort->value.Timestamp.second = 0;
lpSqlNodeSort->value.Timestamp.fraction = 0;
lpSqlNodeSort->value.Binary = NULL;
lpSqlNodeSort->sqlIsNull = TRUE;
lpSqlNodeSort->node.column.Tablealias = lpSqlNodeColumn->node.column.Tablealias;
lpSqlNodeSort->node.column.Qualifier = lpSqlNodeColumn->node.column.Qualifier;
lpSqlNodeSort->node.column.MatchedAlias = lpSqlNodeColumn->node.column.MatchedAlias;
lpSqlNodeSort->node.column.Column = lpSqlNodeColumn->node.column.Column;
lpSqlNodeSort->node.column.TableIndex = lpSqlNodeColumn->node.column.TableIndex;
// lpSqlNodeSort->node.table.Handle = NULL;
lpSqlNodeSort->node.column.Id = -1;
lpSqlNodeSort->node.column.Value = NO_STRING;
lpSqlNodeSort->node.column.InSortRecord = FALSE;
lpSqlNodeSort->node.column.Offset = 0;
lpSqlNodeSort->node.column.Length = 0;
lpSqlNodeSort->node.column.DistinctOffset = 0;
lpSqlNodeSort->node.column.DistinctLength = 0;
lpSqlNodeSort->node.column.EnclosingStatement = NO_SQLNODE;
/* Semantic check the newly created node */
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNode->node.sortcolumns.Column,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
}
/* Check the rest of the list */
if (lpSqlNode->node.sortcolumns.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(*lplpSql, lpSqlNode->node.sortcolumns.Next);
}
break;
case NODE_TYPE_GROUPBYCOLUMNS:
while (TRUE) {
/* Check this column */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.groupbycolumns.Column,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check the rest of the list */
if (lpSqlNode->node.groupbycolumns.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(*lplpSql, lpSqlNode->node.groupbycolumns.Next);
}
break;
case NODE_TYPE_UPDATEVALUES:
while (TRUE) {
/* Check this column */
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNode->node.updatevalues.Column, fIsGroupby,
fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check the value being assigned to the column */
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNode->node.updatevalues.Value, fIsGroupby,
fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Error if value has incompatible type */
err = TypeCheck(lpstmt, *lplpSql, lpSqlNode->node.updatevalues.Column,
lpSqlNode->node.updatevalues.Value, OP_NONE, NULL, NULL,
NULL, NULL);
if (err != ERR_SUCCESS)
return err;
/* Check the rest of the list */
if (lpSqlNode->node.updatevalues.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(*lplpSql, lpSqlNode->node.updatevalues.Next);
}
break;
case NODE_TYPE_CREATECOLS:
while (TRUE) {
UWORD count;
UWORD idx;
/* Make sure column name is not too long */
ptr = ToString(*lplpSql, lpSqlNode->node.createcols.Name);
if (s_lstrlen(ptr)>ISAMMaxColumnNameLength(lpstmt->lpdbc->lpISAM)) {
s_lstrcpy(lpstmt->szError, ptr);
return ERR_INVALIDCOLNAME;
}
/* Find data type */
ptr = ToString(*lplpSql, lpSqlNode->node.createcols.Type);
for (idx = 0; idx < lpstmt->lpdbc->lpISAM->cSQLTypes; idx++) {
if (lpstmt->lpdbc->lpISAM->SQLTypes[idx].supported &&
!s_lstrcmpi(lpstmt->lpdbc->lpISAM->SQLTypes[idx].name, ptr))
break;
}
if (idx >= lpstmt->lpdbc->lpISAM->cSQLTypes) {
s_lstrcpy(lpstmt->szError, ptr);
return ERR_NOSUCHTYPE;
}
lpSqlNode->node.createcols.iSqlType = idx;
/* Count the number of create parameters */
count = 0;
ptr = lpstmt->lpdbc->lpISAM->SQLTypes[idx].params;
if (ptr != NULL) {
count = 1;
for (; *ptr; ptr++) {
if (*ptr == ',')
count++;
}
}
/* Error if wrong number of parameters */
if (count != lpSqlNode->node.createcols.Params) {
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNode->node.createcols.Type));
return ERR_BADPARAMCOUNT;
}
/* Check next one on list */
if (lpSqlNode->node.createcols.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(*lplpSql, lpSqlNode->node.createcols.Next);
}
break;
case NODE_TYPE_BOOLEAN:
while (TRUE) {
/* Check left child */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.boolean.Left,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* The result is always a boolean */
lpSqlNode->sqlDataType = TYPE_INTEGER;
lpSqlNode->sqlSqlType = SQL_BIT;
lpSqlNode->sqlPrecision = 1;
lpSqlNode->sqlScale = 0;
/* Leave loop if no right child */
if (lpSqlNode->node.boolean.Right == NO_SQLNODE)
break;
/* Is right child a NODE_TYPE_BOOLEAN node? */
if (ToNode(*lplpSql, lpSqlNode->node.boolean.Right)->sqlNodeType !=
NODE_TYPE_BOOLEAN) {
/* No. Semantic check that and leave the loop */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.boolean.Right,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
break;
}
/* Semantic check the right node on next iteration of the loop */
lpSqlNode = ToNode(*lplpSql, lpSqlNode->node.boolean.Right);
}
break;
case NODE_TYPE_COMPARISON:
/* Check left child */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.comparison.Left,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check right child */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.comparison.Right,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Is this an IN or NOT IN comparison against a sub-select? */
if (((lpSqlNode->node.comparison.Operator == OP_IN) ||
(lpSqlNode->node.comparison.Operator == OP_NOTIN)) &&
(ToNode(*lplpSql, lpSqlNode->node.comparison.Right)->sqlNodeType
== NODE_TYPE_SELECT)) {
/* Yes. Convert it to a regular comparison */
if (lpSqlNode->node.comparison.Operator == OP_IN) {
lpSqlNode->node.comparison.Operator = OP_EQ;
lpSqlNode->node.comparison.SelectModifier = SELECT_ANY;
}
else if (lpSqlNode->node.comparison.Operator == OP_NOTIN) {
lpSqlNode->node.comparison.Operator = OP_NE;
lpSqlNode->node.comparison.SelectModifier = SELECT_ALL;
}
}
/* Is this an EXISTS operation ? */
if (lpSqlNode->node.comparison.Operator == OP_EXISTS) {
/* Yes. Nothing else to do */
;
}
/* Is this an IN or NOT IN comparison? */
else if ((lpSqlNode->node.comparison.Operator != OP_IN) &&
(lpSqlNode->node.comparison.Operator != OP_NOTIN)) {
/* No. Is the right child NODE_TYPE_SELECT? */
switch (lpSqlNode->node.comparison.SelectModifier) {
case SELECT_NOTSELECT:
break;
case SELECT_ALL:
case SELECT_ANY:
case SELECT_ONE:
{
LPSQLNODE lpSqlNodeSelect;
LPSQLNODE lpSqlNodeValues;
LPSQLNODE lpSqlNodeValue;
/* Yes. Get the select list */
lpSqlNodeSelect = ToNode(*lplpSql,
lpSqlNode->node.comparison.Right);
lpSqlNodeValues = ToNode(*lplpSql,
lpSqlNodeSelect->node.select.Values);
/* If more than one value on the list, error */
if (lpSqlNodeValues->node.values.Next != NO_SQLNODE)
return ERR_MULTICOLUMNSELECT;
/* If long value, error */
lpSqlNodeValue = ToNode(*lplpSql,
lpSqlNodeValues->node.values.Value);
if ((lpSqlNodeValue->sqlSqlType == SQL_LONGVARCHAR) ||
(lpSqlNodeValue->sqlSqlType == SQL_LONGVARBINARY)) {
ErrorOpCode(lpstmt,
lpSqlNode->node.comparison.Operator);
return ERR_INVALIDOPERAND;
}
/* Set the type of the value returned by the sub-query */
lpSqlNodeSelect->sqlDataType = lpSqlNodeValue->sqlDataType;
lpSqlNodeSelect->sqlSqlType = lpSqlNodeValue->sqlSqlType;
lpSqlNodeSelect->sqlPrecision = lpSqlNodeValue->sqlPrecision;
lpSqlNodeSelect->sqlScale = lpSqlNodeValue->sqlScale;
}
break;
case SELECT_EXISTS:
default:
return ERR_INTERNAL;
}
/* Error if incompatible types */
err = TypeCheck(lpstmt, *lplpSql, lpSqlNode->node.comparison.Left,
lpSqlNode->node.comparison.Right,
lpSqlNode->node.comparison.Operator,
&(lpSqlNode->sqlDataType), &(lpSqlNode->sqlSqlType),
&(lpSqlNode->sqlPrecision), &(lpSqlNode->sqlScale));
if (err != ERR_SUCCESS)
return err;
/* Error if "LIKE" or "NOT LIKE" used for non-char data */
if ((lpSqlNode->sqlDataType != TYPE_CHAR) &&
((lpSqlNode->node.comparison.Operator == OP_LIKE) ||
(lpSqlNode->node.comparison.Operator == OP_NOTLIKE))) {
ErrorOpCode(lpstmt, lpSqlNode->node.comparison.Operator);
return ERR_INVALIDOPERAND;
}
/* Error if binary data */
if (lpSqlNode->sqlDataType == TYPE_BINARY) {
if (((lpSqlNode->node.comparison.Operator != OP_EQ) &&
(lpSqlNode->node.comparison.Operator != OP_NE)) ||
(lpSqlNode->sqlPrecision > MAX_BINARY_LITERAL_LENGTH)) {
ErrorOpCode(lpstmt, lpSqlNode->node.comparison.Operator);
return ERR_INVALIDOPERAND;
}
}
}
else {
/* Yes. Look at each value */
SQLNODEIDX idxValues;
LPSQLNODE lpSqlNodeValues;
LPSQLNODE lpSqlNodeValue;
/* For each value... */
idxValues = lpSqlNode->node.comparison.Right;
while (idxValues != NO_SQLNODE) {
/* Get the value */
lpSqlNodeValues = ToNode(*lplpSql, idxValues);
lpSqlNodeValue = ToNode(*lplpSql, lpSqlNodeValues->node.values.Value);
/* Make sure the value is NUMERIC, STRING, */
/* PARAMETER, USER, DATE, TIME, or TIMESTAMP */
switch (lpSqlNodeValue->sqlNodeType) {
case NODE_TYPE_ALGEBRAIC:
case NODE_TYPE_SCALAR:
case NODE_TYPE_AGGREGATE:
case NODE_TYPE_COLUMN:
return ERR_INVALIDINVAL;
case NODE_TYPE_PARAMETER:
case NODE_TYPE_NUMERIC:
case NODE_TYPE_STRING:
case NODE_TYPE_USER:
case NODE_TYPE_DATE:
case NODE_TYPE_TIME:
case NODE_TYPE_TIMESTAMP:
/* Make sure value is of the proper type */
err = TypeCheck(lpstmt, *lplpSql,
lpSqlNode->node.comparison.Left,
lpSqlNodeValues->node.values.Value,
lpSqlNode->node.comparison.Operator,
&(lpSqlNode->sqlDataType),
&(lpSqlNode->sqlSqlType),
&(lpSqlNode->sqlPrecision),
&(lpSqlNode->sqlScale));
if (err != ERR_SUCCESS)
return err;
break;
case NODE_TYPE_NULL:
return ERR_INVALIDINVAL;
default:
return ERR_INTERNAL;
}
/* Look at next element */
idxValues = lpSqlNodeValues->node.values.Next;
}
}
/* The result is always a boolean */
lpSqlNode->sqlDataType = TYPE_INTEGER;
lpSqlNode->sqlSqlType = SQL_BIT;
lpSqlNode->sqlPrecision = 1;
lpSqlNode->sqlScale = 0;
break;
case NODE_TYPE_ALGEBRAIC:
/* Save pointer to enclosing statement */
lpSqlNode->node.algebraic.EnclosingStatement = idxEnclosingStatement;
{
LPSQLNODE lpSqlNodeLeft;
LPUSTR lpszToken;
UCHAR szTempToken[MAX_TOKEN_SIZE + 1];
/* Check left child */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.algebraic.Left,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check right child */
err = SemanticCheck(lpstmt, lplpSql, lpSqlNode->node.algebraic.Right,
fIsGroupby, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Check data type compatibility */
err = TypeCheck(lpstmt, *lplpSql, lpSqlNode->node.algebraic.Left,
lpSqlNode->node.algebraic.Right,
lpSqlNode->node.algebraic.Operator,
&(lpSqlNode->sqlDataType), &(lpSqlNode->sqlSqlType),
&(lpSqlNode->sqlPrecision), &(lpSqlNode->sqlScale));
if (err != ERR_SUCCESS)
return err;
/* Allocate space for the column value and make sure the */
/* result is numeric, date, or string */
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_INTEGER:
break;
case TYPE_NUMERIC:
lpSqlNode->node.algebraic.Value = AllocateSpace(lplpSql,
(SWORD) (1 + 2 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.algebraic.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
if (lpSqlNode->node.algebraic.Operator == OP_TIMES) {
lpSqlNode->node.algebraic.WorkBuffer1 = AllocateSpace(lplpSql,
(SWORD) (1 + 2 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.algebraic.WorkBuffer1 == NO_STRING)
return ERR_MEMALLOCFAIL;
}
else if (lpSqlNode->node.algebraic.Operator == OP_DIVIDEDBY) {
lpSqlNode->node.algebraic.WorkBuffer1 = AllocateSpace(lplpSql,
(SWORD) (1 + 2 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.algebraic.WorkBuffer1 == NO_STRING)
return ERR_MEMALLOCFAIL;
lpSqlNode->node.algebraic.WorkBuffer2 = AllocateSpace(lplpSql,
(SWORD) (1 + 2 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.algebraic.WorkBuffer2 == NO_STRING)
return ERR_MEMALLOCFAIL;
lpSqlNode->node.algebraic.WorkBuffer3 = AllocateSpace(lplpSql,
(SWORD) (1 + 2 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.algebraic.WorkBuffer3 == NO_STRING)
return ERR_MEMALLOCFAIL;
}
break;
case TYPE_CHAR:
lpSqlNode->node.algebraic.Value = AllocateSpace(lplpSql,
(SWORD) (1 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.algebraic.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_BINARY:
ErrorOpCode(lpstmt, lpSqlNode->node.algebraic.Operator);
return ERR_INVALIDOPERAND;
case TYPE_DATE:
break;
case TYPE_TIME:
case TYPE_TIMESTAMP:
ErrorOpCode(lpstmt, lpSqlNode->node.algebraic.Operator);
return ERR_INVALIDOPERAND;
default:
return ERR_NOTSUPPORTED;
}
/* If this is just negation of a numeric value, collapse the */
/* two nodes into one */
lpSqlNodeLeft = ToNode(*lplpSql, lpSqlNode->node.algebraic.Left);
if ((lpSqlNode->node.algebraic.Operator == OP_NEG) &&
(lpSqlNodeLeft->sqlNodeType == NODE_TYPE_NUMERIC)) {
*lpSqlNode = *lpSqlNodeLeft;
lpSqlNode->node.numeric.Value = -(lpSqlNode->node.numeric.Value);
lpszToken = ToString(*lplpSql, lpSqlNode->node.numeric.Numeric);
if (*lpszToken != '-') {
s_lstrcpy((char*)szTempToken, lpszToken);
s_lstrcpy(lpszToken, "-");
s_lstrcat(lpszToken, (char*)szTempToken);
BCDNormalize(lpszToken, s_lstrlen(lpszToken),
lpszToken, s_lstrlen(lpszToken) + 1,
lpSqlNode->sqlPrecision,
lpSqlNode->sqlScale);
}
else {
s_lstrcpy((char*)szTempToken, lpszToken);
s_lstrcpy(lpszToken, (char*) (szTempToken+1));
}
}
}
break;
case NODE_TYPE_SCALAR:
/* Save pointer to enclosing statement */
lpSqlNode->node.scalar.EnclosingStatement = idxEnclosingStatement;
/* Check the node */
err = ScalarCheck(lpstmt, lplpSql, idxNode, fIsGroupby,
fCaseSensitive, idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Allocate space as need be */
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
break;
case TYPE_NUMERIC:
lpSqlNode->node.scalar.Value = AllocateSpace(lplpSql,
(SWORD) (1 + 2 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.scalar.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_INTEGER:
break;
case TYPE_CHAR:
lpSqlNode->node.scalar.Value = AllocateSpace(lplpSql,
(SWORD) (1 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.scalar.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_BINARY:
lpSqlNode->node.scalar.Value = AllocateSpace(lplpSql,
(SWORD) (sizeof(SDWORD) + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.scalar.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_DATE:
break;
case TYPE_TIME:
break;
case TYPE_TIMESTAMP:
break;
default:
return ERR_NOTSUPPORTED;
}
break;
case NODE_TYPE_AGGREGATE:
/* Save pointer to enclosing statement */
lpSqlNode->node.aggregate.EnclosingStatement = idxEnclosingStatement;
{
LPSQLNODE lpSqlNodeExpression;
LPSQLNODE lpSqlNodeSelect;
LPSQLNODE lpSqlNodeAggregate;
SQLNODEIDX idxAggregate;
/* Error if no group by */
if (!fIsGroupby) {
ErrorAggCode(lpstmt, lpSqlNode->node.aggregate.Operator);
return ERR_AGGNOTALLOWED;
}
/* Check expression */
err = SemanticCheck(lpstmt, lplpSql,
lpSqlNode->node.aggregate.Expression,
FALSE, fCaseSensitive,
idxNodeTableOuterJoinFromTables,
idxEnclosingStatement);
if (err != ERR_SUCCESS)
return err;
/* Figure out type of result */
if (lpSqlNode->node.aggregate.Operator != AGG_COUNT)
lpSqlNodeExpression =
ToNode(*lplpSql, lpSqlNode->node.aggregate.Expression);
switch(lpSqlNode->node.aggregate.Operator) {
case AGG_AVG:
switch (lpSqlNodeExpression->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_NUMERIC:
case TYPE_INTEGER:
lpSqlNode->sqlDataType = TYPE_DOUBLE;
lpSqlNode->sqlSqlType = SQL_DOUBLE;
lpSqlNode->sqlPrecision = 15;
lpSqlNode->sqlScale = NO_SCALE;
break;
case TYPE_CHAR:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
case TYPE_BINARY:
ErrorAggCode(lpstmt, lpSqlNode->node.aggregate.Operator);
return ERR_INVALIDOPERAND;
default:
return ERR_NOTSUPPORTED;
}
break;
case AGG_COUNT:
lpSqlNode->sqlDataType = TYPE_INTEGER;
lpSqlNode->sqlSqlType = SQL_INTEGER;
lpSqlNode->sqlPrecision = 10;
lpSqlNode->sqlScale = 0;
break;
case AGG_MAX:
case AGG_MIN:
switch (lpSqlNodeExpression->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_NUMERIC:
case TYPE_INTEGER:
case TYPE_CHAR:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
lpSqlNode->sqlDataType = lpSqlNodeExpression->sqlDataType;
lpSqlNode->sqlSqlType = lpSqlNodeExpression->sqlSqlType;
lpSqlNode->sqlPrecision = lpSqlNodeExpression->sqlPrecision;
lpSqlNode->sqlScale = lpSqlNodeExpression->sqlScale;
break;
case TYPE_BINARY:
ErrorAggCode(lpstmt, lpSqlNode->node.aggregate.Operator);
return ERR_INVALIDOPERAND;
default:
return ERR_NOTSUPPORTED;
}
break;
case AGG_SUM:
switch (lpSqlNodeExpression->sqlDataType) {
case TYPE_DOUBLE:
case TYPE_NUMERIC:
case TYPE_INTEGER:
lpSqlNode->sqlDataType = lpSqlNodeExpression->sqlDataType;
lpSqlNode->sqlSqlType = lpSqlNodeExpression->sqlSqlType;
lpSqlNode->sqlPrecision = lpSqlNodeExpression->sqlPrecision;
lpSqlNode->sqlScale = lpSqlNodeExpression->sqlScale;
break;
case TYPE_CHAR:
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
case TYPE_BINARY:
ErrorAggCode(lpstmt, lpSqlNode->node.aggregate.Operator);
return ERR_INVALIDOPERAND;
default:
return ERR_NOTSUPPORTED;
}
break;
default:
return ERR_INTERNAL;
}
/* Allocate space for the aggregate value */
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
lpSqlNode->node.aggregate.Length = sizeof(double);
break;
case TYPE_NUMERIC:
switch (lpSqlNode->sqlSqlType) {
case SQL_NUMERIC:
case SQL_DECIMAL:
lpSqlNode->node.aggregate.Length =
lpSqlNodeExpression->sqlPrecision + 2;
break;
case SQL_BIGINT:
lpSqlNode->node.aggregate.Length =
lpSqlNodeExpression->sqlPrecision + 1;
break;
case SQL_TINYINT:
case SQL_SMALLINT:
case SQL_INTEGER:
case SQL_BIT:
case SQL_REAL:
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
default:
return ERR_INTERNAL;
}
lpSqlNode->node.aggregate.Value =
AllocateSpace(lplpSql, (SWORD)
(lpSqlNode->node.aggregate.Length + 1));
if (lpSqlNode->node.aggregate.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_INTEGER:
lpSqlNode->node.aggregate.Length = sizeof(double);
break;
case TYPE_CHAR:
lpSqlNode->node.aggregate.Length =
lpSqlNodeExpression->sqlPrecision;
lpSqlNode->node.aggregate.Value =
AllocateSpace(lplpSql, (SWORD)
(lpSqlNode->node.aggregate.Length + 1));
if (lpSqlNode->node.aggregate.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_DATE:
lpSqlNode->node.aggregate.Length = 10;
break;
case TYPE_TIME:
lpSqlNode->node.aggregate.Length = 8;
break;
case TYPE_TIMESTAMP:
if (TIMESTAMP_SCALE > 0)
lpSqlNode->node.aggregate.Length = 20 + TIMESTAMP_SCALE;
else
lpSqlNode->node.aggregate.Length = 19;
break;
case TYPE_BINARY:
return ERR_INTERNAL;
default:
return ERR_NOTSUPPORTED;
}
/* Get SELECT statement node */
lpSqlNodeSelect = ToNode(*lplpSql, idxEnclosingStatement);
if (lpSqlNodeSelect->sqlNodeType != NODE_TYPE_SELECT)
return ERR_INTERNAL;
/* Add to list of AGG functions in the select node */
lpSqlNodeAggregate = NULL;
idxAggregate = lpSqlNodeSelect->node.select.Aggregates;
while (idxAggregate != NO_SQLNODE) {
lpSqlNodeAggregate = ToNode(*lplpSql, idxAggregate);
idxAggregate = lpSqlNodeAggregate->node.aggregate.Next;
}
if (lpSqlNodeAggregate != NULL)
lpSqlNodeAggregate->node.aggregate.Next = idxNode;
else
lpSqlNodeSelect->node.select.Aggregates = idxNode;
}
break;
case NODE_TYPE_TABLE:
{
LPSQLNODE lpSqlNodeRoot;
LPSQLNODE lpSqlNodeStmt;
BOOL fReadOnly;
char tableNameBuff [MAX_TABLE_NAME_LENGTH + 1];
/* Make sure table name is not too long */
ptr = ToString(*lplpSql, lpSqlNode->node.table.Name);
if (s_lstrlen(ptr) > ISAMMaxTableNameLength(lpstmt->lpdbc->lpISAM)){
s_lstrcpy(lpstmt->szError, ptr);
return ERR_INVALIDTABLENAME;
}
else
{
//Copy table name
tableNameBuff[0] = 0;
s_lstrcpy (tableNameBuff, ptr);
}
/* Figure out if write access is needed */
lpSqlNodeStmt = ToNode(*lplpSql, idxEnclosingStatement);
switch (lpSqlNodeStmt->sqlNodeType) {
case NODE_TYPE_SELECT:
fReadOnly = TRUE;
break;
case NODE_TYPE_INSERT:
fReadOnly = FALSE;
break;
case NODE_TYPE_UPDATE:
fReadOnly = FALSE;
break;
case NODE_TYPE_DELETE:
fReadOnly = FALSE;
break;
case NODE_TYPE_CREATEINDEX:
fReadOnly = FALSE;
break;
case NODE_TYPE_DROPINDEX:
fReadOnly = FALSE;
break;
default:
return ERR_INTERNAL;
}
/* resolve qualifier */
if (lpSqlNode->node.table.Qualifier != NO_STRING)
{
LPSTR pQual = (LPSTR) ToString(*lplpSql, lpSqlNode->node.table.Qualifier);
if (lstrlen(pQual) > ISAMMaxTableNameLength(lpstmt->lpdbc->lpISAM)) {
s_lstrcpy((char*)lpstmt->szError, ptr);
return ERR_INVALIDTABLENAME;
}
if ( (lstrlen(pQual) >= 4) && (_strnicmp("root", pQual, 4) == 0) )
{
// absolute qualifier [starts with 'root'] (no need to change)
}
else
{
// concatenate the current namespace with the qualifier
LPUSTR currQual = ISAMDatabase (lpstmt->lpdbc->lpISAM);
char * pszNewQualifier = new char [strlen (pQual)+
s_lstrlen (currQual)+2+1];
s_lstrcpy (pszNewQualifier, currQual);
s_lstrcat (pszNewQualifier, "\\");
s_lstrcat (pszNewQualifier, pQual);
lpSqlNode->node.table.Qualifier = AllocateString (lplpSql, (LPUSTR)pszNewQualifier);
delete [] pszNewQualifier;
}
}
else
{
// the current namespace is the qualifier
LPUSTR currQual = ISAMDatabase (lpstmt->lpdbc->lpISAM);
lpSqlNode->node.table.Qualifier = AllocateString (lplpSql, (LPUSTR)currQual);
}
#ifdef TESTING
//Create extra test class with dummy values for testing
// IMosProvider* pDummyProv = ISAMGetGatewayServer(lpstmt->lpdbc->lpISAM);
// CreateClassAndInstance(pDummyProv);
#endif
/* Open the table */
LPUSTR pQual = ToString(*lplpSql, lpSqlNode->node.table.Qualifier);
lpSqlNodeRoot = ToNode(*lplpSql, ROOT_SQLNODE);
//If this the special Passthrough SQL table ?
char* virTbl = WBEMDR32_VIRTUAL_TABLE2;
if (s_lstrcmp(tableNameBuff, virTbl) == 0)
{
//Yes this is the Passthrough SQL table
err = ISAMOpenTable(lpSqlNodeRoot->node.root.lpISAM,
(LPUSTR) pQual, (SWORD) s_lstrlen (pQual),
(LPUSTR) tableNameBuff, fReadOnly,
&(lpSqlNode->node.table.Handle),
lpstmt);
}
else
{
//No normal table
err = ISAMOpenTable(lpSqlNodeRoot->node.root.lpISAM,
(LPUSTR) pQual, (SWORD) s_lstrlen (pQual),
(LPUSTR) tableNameBuff, fReadOnly,
&(lpSqlNode->node.table.Handle));
}
if (err != NO_ISAM_ERR) {
lpSqlNode->node.table.Handle = NULL;
ISAMGetErrorMessage(lpSqlNodeRoot->node.root.lpISAM,
(LPUSTR)lpstmt->szISAMError);
return err;
}
if (lpstmt->lpdbc->lpISAM->fSchemaInfoTransactioned)
lpstmt->fISAMTxnStarted = TRUE;
err = ERR_SUCCESS;
}
break;
case NODE_TYPE_COLUMN:
/* Save pointer to enclosing statement */
lpSqlNode->node.column.EnclosingStatement = idxEnclosingStatement;
//Sai Wong table column info
/* Is this column node in an outer join predicate? */
if (idxNodeTableOuterJoinFromTables == NO_SQLNODE) {
/* No. Resolve it against the table lists */
LPSQLNODE lpSqlNodeStmt;
LPSQLNODE lpSqlNodeTables;
SQLNODEIDX idxTables;
SQLNODEIDX idxStatement;
STRINGIDX idxOriginalAlias;
STRINGIDX idxAlias;
BOOL fFoundMatch;
STRINGIDX idxQualifier, idxOriginalQualifier;
/* No. Search up all the enclosing statements for the column */
idxStatement = idxEnclosingStatement;
while (idxStatement != NO_SQLNODE) {
/* Get node of the statement */
lpSqlNodeStmt = ToNode(*lplpSql, idxStatement);
/* Resolve column */
switch (lpSqlNodeStmt->sqlNodeType) {
case NODE_TYPE_SELECT:
/* Save the table alias and qualifier specified */
idxAlias = lpSqlNode->node.column.Tablealias;
idxOriginalAlias = lpSqlNode->node.column.Tablealias;
idxQualifier = idxOriginalQualifier = lpSqlNode->node.column.Qualifier;
/* Look through the list of tables */
fFoundMatch = FALSE;
err = ERR_COLUMNNOTFOUND;
for (idxTables = lpSqlNodeStmt->node.select.Tables;
idxTables != NO_SQLNODE;
idxTables = lpSqlNodeTables->node.tables.Next) {
/* Is the column in this table? */
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
err = FindColumn(lpstmt, *lplpSql, fCaseSensitive,
lpSqlNode, lpSqlNodeTables->node.tables.Table, idxQualifier);
if (err == ERR_SUCCESS)
{
/* Yes. Error if column also in another table */
if (fFoundMatch) {
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNode->node.column.Column));
return ERR_COLUMNFOUND;
}
fFoundMatch = TRUE;
/* If a table alias was specified for column, */
/* there is no need to check the other tables */
/* I'm going to remove this check as there is the */
/* possibility of a clash between an alias-qualified*/
/* name and a namespace qualified name. This clash */
/* is not picked up during the semantic check of the*/
/* table list */
//if (idxOriginalAlias != NO_STRING)
// break;
/* Save the alias of the table found */
idxAlias = lpSqlNode->node.column.Tablealias;
idxQualifier = lpSqlNode->node.column.Qualifier;
/* Restore the original alias and keep looking */
//Added by Sai Wong
lpSqlNode->node.column.Tablealias = idxOriginalAlias; //NO_STRING;
lpSqlNode->node.column.Qualifier = idxOriginalQualifier;
}
else if (err != ERR_COLUMNNOTFOUND)
return err;
}
/* Restore the alias found */
lpSqlNode->node.column.Tablealias = idxAlias;
lpSqlNode->node.column.Qualifier = idxQualifier;
/* Was the column found in this statement? */
if (fFoundMatch)
err = ERR_SUCCESS;
else
err = ERR_COLUMNNOTFOUND;
break;
case NODE_TYPE_INSERT:
if (idxStatement == idxEnclosingStatement)
err = FindColumn(lpstmt, *lplpSql, fCaseSensitive,
lpSqlNode, lpSqlNodeStmt->node.insert.Table,
NO_STRING);
else
err = ERR_COLUMNNOTFOUND;
break;
case NODE_TYPE_UPDATE:
err = FindColumn(lpstmt, *lplpSql, fCaseSensitive, lpSqlNode,
lpSqlNodeStmt->node.update.Table, NO_STRING);
break;
case NODE_TYPE_DELETE:
err = FindColumn(lpstmt, *lplpSql, fCaseSensitive, lpSqlNode,
lpSqlNodeStmt->node.delet.Table, NO_STRING);
break;
case NODE_TYPE_CREATEINDEX:
err = FindColumn(lpstmt, *lplpSql, fCaseSensitive, lpSqlNode,
lpSqlNodeStmt->node.createindex.Table, NO_STRING);
break;
default:
return ERR_INTERNAL;
}
if ((err != ERR_SUCCESS) && (err != ERR_COLUMNNOTFOUND))
return err;
/* If the column was found in this statement, use it */
if (err == ERR_SUCCESS)
break;
/* Try looking in the enclosing statement (if any) */
if (lpSqlNodeStmt->sqlNodeType != NODE_TYPE_SELECT)
break;
idxStatement = lpSqlNodeStmt->node.select.EnclosingStatement;
}
/* If column not found, error */
if (err == ERR_COLUMNNOTFOUND) {
s_lstrcpy(lpstmt->szError,
ToString(*lplpSql, lpSqlNode->node.column.Column));
return ERR_COLUMNNOTFOUND;
}
}
else {
/* Yes. Resolve it against the table lists */
STRINGIDX idxAlias;
STRINGIDX idxOriginalAlias;
BOOL fFoundMatch;
SQLNODEIDX idxTables;
LPSQLNODE lpSqlNodeTables;
SQLNODEIDX idxTable;
LPSQLNODE lpSqlNodeTable;
STRINGIDX idxQualifier, idxOriginalQualifier;
/* Save the table alias specified */
idxAlias = lpSqlNode->node.column.Tablealias;
idxOriginalAlias = lpSqlNode->node.column.Tablealias;
idxQualifier = idxOriginalQualifier = lpSqlNode->node.column.Qualifier;
/* Is the column in a table in the outer join expression? */
idxTables = idxNodeTableOuterJoinFromTables;
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
idxTable = lpSqlNodeTables->node.tables.Table;
fFoundMatch = FALSE;
while (TRUE) {
/* Is it in this table? */
err = FindColumn(lpstmt, *lplpSql, fCaseSensitive,
lpSqlNode, idxTable, lpSqlNodeTables->node.column.Qualifier);
if (err == ERR_SUCCESS) {
/* Yes. Error if it matches another table too */
if (fFoundMatch) {
s_lstrcpy(lpstmt->szError,
ToString(*lplpSql, lpSqlNode->node.column.Column));
return ERR_COLUMNFOUND;
}
/* Set flag */
fFoundMatch = TRUE;
/* Save the alias of the table found */
idxAlias = lpSqlNode->node.column.Tablealias;
idxQualifier = lpSqlNode->node.column.Qualifier;
/* Restore the original alias if need be */
//Added by Sai Wong
// if (idxOriginalAlias == NO_STRING)
lpSqlNode->node.column.Tablealias = idxOriginalAlias; //NO_STRING;
lpSqlNode->node.column.Qualifier = idxOriginalQualifier;
}
else if (err != ERR_COLUMNNOTFOUND)
return err;
/* Look in next table on list */
idxTables = lpSqlNodeTables->node.tables.Next;
if (idxTables == NO_SQLNODE)
break;
lpSqlNodeTables = ToNode(*lplpSql, idxTables);
idxTable = lpSqlNodeTables->node.tables.Table;
lpSqlNodeTable = ToNode(*lplpSql, idxTable);
/* If this table is not in the outer-join, stop looking */
if (lpSqlNodeTable->node.table.OuterJoinFromTables ==
NO_SQLNODE)
break;
}
/* Error if column was not found */
if (!fFoundMatch) {
s_lstrcpy(lpstmt->szError,
ToString(*lplpSql, lpSqlNode->node.column.Column));
return ERR_COLUMNNOTFOUND;
}
/* Restore the alias found */
lpSqlNode->node.column.Tablealias = idxAlias;
lpSqlNode->node.column.Qualifier = idxQualifier;
err = ERR_SUCCESS;
}
/* Does the column have to be a group by column? */
if (fIsGroupby) {
LPUSTR lpszColumn;
LPUSTR lpszTable;
LPSQLNODE lpSqlNodeStmt;
SQLNODEIDX idxGroupbycolumns;
LPSQLNODE lpSqlNodeGroupbycolumns;
LPSQLNODE lpSqlNodeColumnGroupby;
LPUSTR lpszColumnGroupby;
LPUSTR lpszTableGroupby;
BOOL fMatch;
/* Yes. Get the name of the column and table */
lpszColumn = ToString(*lplpSql, lpSqlNode->node.column.Column);
lpszTable = ToString(*lplpSql, lpSqlNode->node.column.Tablealias);
/* Get list of group by columns */
lpSqlNodeStmt = ToNode(*lplpSql, idxEnclosingStatement);
if (lpSqlNodeStmt->sqlNodeType != NODE_TYPE_SELECT)
return ERR_INTERNAL;
idxGroupbycolumns = lpSqlNodeStmt->node.select.Groupbycolumns;
/* Error if implicit group by */
if (lpSqlNodeStmt->node.select.ImplicitGroupby) {
s_lstrcpy(lpstmt->szError,
ToString(*lplpSql, lpSqlNode->node.column.Column));
return ERR_COLUMNNOTFOUND;
}
/* Find the column in the group by lists */
while (TRUE) {
/* Get this group by column */
lpSqlNodeGroupbycolumns = ToNode(*lplpSql, idxGroupbycolumns);
if (lpSqlNodeGroupbycolumns->node.groupbycolumns.Column !=
NO_SQLNODE) {
lpSqlNodeColumnGroupby = ToNode(*lplpSql,
lpSqlNodeGroupbycolumns->node.groupbycolumns.Column);
/* Get column name and table name of the group by column */
lpszTableGroupby = ToString(*lplpSql,
lpSqlNodeColumnGroupby->node.column.Tablealias);
lpszColumnGroupby = ToString(*lplpSql,
lpSqlNodeColumnGroupby->node.column.Column);
/* Do the column name match? */
fMatch = FALSE;
if (fCaseSensitive) {
if (!s_lstrcmp(lpszColumnGroupby, lpszColumn) &&
!s_lstrcmp(lpszTableGroupby, lpszTable))
fMatch = TRUE;
}
else {
if (!s_lstrcmpi(lpszColumnGroupby, lpszColumn) &&
!s_lstrcmpi(lpszTableGroupby, lpszTable))
fMatch = TRUE;
}
}
else
fMatch = FALSE;
/* Does this column match a group by column? */
if (fMatch) {
/* Yes. Fill in semantic information for the column */
lpSqlNode->node.column.InSortRecord = TRUE;
lpSqlNode->node.column.Offset =
lpSqlNodeColumnGroupby->node.column.Offset;
lpSqlNode->node.column.Length =
lpSqlNodeColumnGroupby->node.column.Length;
lpSqlNode->node.column.DistinctOffset =
lpSqlNodeColumnGroupby->node.column.DistinctOffset;
lpSqlNode->node.column.DistinctLength =
lpSqlNodeColumnGroupby->node.column.DistinctLength;
break;
}
/* Not found yet. Check next column */
idxGroupbycolumns =
lpSqlNodeGroupbycolumns->node.groupbycolumns.Next;
/* Error if column not found */
if (idxGroupbycolumns == NO_SQLNODE) {
s_lstrcpy((char*)lpstmt->szError,
ToString(*lplpSql, lpSqlNode->node.column.Column));
return ERR_COLUMNNOTFOUND;
}
}
}
/* Allocate space for the column value */
switch (lpSqlNode->sqlDataType) {
case TYPE_DOUBLE:
break;
case TYPE_NUMERIC:
lpSqlNode->node.column.Value = AllocateSpace(lplpSql,
(SWORD) (1 + 2 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.column.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_INTEGER:
break;
case TYPE_CHAR:
lpSqlNode->node.column.Value = AllocateSpace(lplpSql,
(SWORD) (1 + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.column.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_BINARY:
lpSqlNode->node.column.Value = AllocateSpace(lplpSql,
(SWORD) (sizeof(SDWORD) + lpSqlNode->sqlPrecision));
if (lpSqlNode->node.column.Value == NO_STRING)
return ERR_MEMALLOCFAIL;
break;
case TYPE_DATE:
break;
case TYPE_TIME:
break;
case TYPE_TIMESTAMP:
break;
default:
return ERR_NOTSUPPORTED;
}
break;
case NODE_TYPE_STRING:
lpSqlNode->sqlDataType = TYPE_CHAR;
lpSqlNode->sqlSqlType = SQL_VARCHAR;
ptr = ToString(*lplpSql, lpSqlNode->node.string.Value);
lpSqlNode->sqlPrecision = s_lstrlen(ptr);
lpSqlNode->sqlScale = NO_SCALE;
break;
case NODE_TYPE_NUMERIC:
if (lpSqlNode->sqlDataType == TYPE_UNKNOWN) {
lpSqlNode->sqlDataType = TYPE_DOUBLE;
lpSqlNode->sqlSqlType = SQL_DOUBLE;
lpSqlNode->sqlPrecision = 15;
lpSqlNode->sqlScale = NO_SCALE;
}
break;
case NODE_TYPE_PARAMETER:
lpSqlNode->sqlDataType = TYPE_UNKNOWN;
lpSqlNode->sqlSqlType = SQL_TYPE_NULL;
lpSqlNode->sqlPrecision = 0;
lpSqlNode->sqlScale = NO_SCALE;
break;
case NODE_TYPE_USER:
lpSqlNode->sqlDataType = TYPE_CHAR;
lpSqlNode->sqlSqlType = SQL_VARCHAR;
lpSqlNode->sqlPrecision = s_lstrlen(
ISAMUser(ToNode(*lplpSql, ROOT_SQLNODE)->node.root.lpISAM));
lpSqlNode->sqlScale = NO_SCALE;
break;
case NODE_TYPE_NULL:
lpSqlNode->sqlDataType = TYPE_UNKNOWN;
lpSqlNode->sqlSqlType = SQL_TYPE_NULL;
lpSqlNode->sqlPrecision = 0;
lpSqlNode->sqlScale = NO_SCALE;
break;
case NODE_TYPE_DATE:
lpSqlNode->sqlDataType = TYPE_DATE;
if (lpSqlNode->sqlSqlType == SQL_TYPE_NULL) {
lpSqlNode->sqlSqlType = SQL_DATE;
lpSqlNode->sqlPrecision = 10;
lpSqlNode->sqlScale = NO_SCALE;
}
break;
case NODE_TYPE_TIME:
lpSqlNode->sqlDataType = TYPE_TIME;
if (lpSqlNode->sqlSqlType == SQL_TYPE_NULL) {
lpSqlNode->sqlSqlType = SQL_TIME;
lpSqlNode->sqlPrecision = 8;
lpSqlNode->sqlScale = NO_SCALE;
}
break;
case NODE_TYPE_TIMESTAMP:
lpSqlNode->sqlDataType = TYPE_TIMESTAMP;
if (lpSqlNode->sqlSqlType == SQL_TYPE_NULL) {
lpSqlNode->sqlSqlType = SQL_TIMESTAMP;
if (TIMESTAMP_SCALE != 0)
lpSqlNode->sqlPrecision = 20 + TIMESTAMP_SCALE;
else
lpSqlNode->sqlPrecision = 19;
lpSqlNode->sqlScale = TIMESTAMP_SCALE;
}
break;
default:
return ERR_INTERNAL;
}
return err;
}
/***************************************************************************/
void INTFUNC FreeTreeSemantic(LPSQLTREE lpSql, SQLNODEIDX idxNode)
/* Deallocates semantic information in a parse tree */
{
LPSQLNODE lpSqlNode;
SQLNODEIDX idxParameter;
SQLNODEIDX idxParameterNext;
if (idxNode == NO_SQLNODE)
return;
lpSqlNode = ToNode(lpSql, idxNode);
switch (lpSqlNode->sqlNodeType) {
case NODE_TYPE_NONE:
break;
case NODE_TYPE_ROOT:
FreeTreeSemantic(lpSql, lpSqlNode->node.root.sql);
if (lpSqlNode->node.root.passthroughParams) {
idxParameter = lpSqlNode->node.root.parameters;
while (idxParameter != NO_SQLNODE) {
lpSqlNode = ToNode(lpSql, idxParameter);
idxParameterNext = lpSqlNode->node.parameter.Next;
FreeTreeSemantic(lpSql, idxParameter);
idxParameter = idxParameterNext;
}
}
break;
case NODE_TYPE_CREATE:
FreeTreeSemantic(lpSql, lpSqlNode->node.create.Columns);
break;
case NODE_TYPE_DROP:
break;
case NODE_TYPE_SELECT:
FreeTreeSemantic(lpSql, lpSqlNode->node.select.Values);
FreeTreeSemantic(lpSql, lpSqlNode->node.select.Tables);
FreeTreeSemantic(lpSql, lpSqlNode->node.select.Predicate);
FreeTreeSemantic(lpSql, lpSqlNode->node.select.Groupbycolumns);
FreeTreeSemantic(lpSql, lpSqlNode->node.select.Sortcolumns);
if (lpSqlNode->node.select.Sortfile != HFILE_ERROR) {
LPUSTR lpszSortfile;
_lclose(lpSqlNode->node.select.Sortfile);
lpSqlNode->node.select.Sortfile = HFILE_ERROR;
lpszSortfile = ToString(lpSql,
lpSqlNode->node.select.SortfileName);
DeleteFile((LPCSTR) lpszSortfile);
s_lstrcpy(lpszSortfile, "");
}
break;
case NODE_TYPE_INSERT:
FreeTreeSemantic(lpSql, lpSqlNode->node.insert.Table);
FreeTreeSemantic(lpSql, lpSqlNode->node.insert.Columns);
FreeTreeSemantic(lpSql, lpSqlNode->node.insert.Values);
break;
case NODE_TYPE_DELETE:
FreeTreeSemantic(lpSql, lpSqlNode->node.delet.Table);
FreeTreeSemantic(lpSql, lpSqlNode->node.delet.Predicate);
break;
case NODE_TYPE_UPDATE:
FreeTreeSemantic(lpSql, lpSqlNode->node.update.Table);
FreeTreeSemantic(lpSql, lpSqlNode->node.update.Updatevalues);
FreeTreeSemantic(lpSql, lpSqlNode->node.update.Predicate);
break;
case NODE_TYPE_CREATEINDEX:
FreeTreeSemantic(lpSql, lpSqlNode->node.createindex.Table);
FreeTreeSemantic(lpSql, lpSqlNode->node.createindex.Columns);
break;
case NODE_TYPE_DROPINDEX:
break;
case NODE_TYPE_PASSTHROUGH:
break;
case NODE_TYPE_TABLES:
FreeTreeSemantic(lpSql, lpSqlNode->node.tables.Table);
FreeTreeSemantic(lpSql, lpSqlNode->node.tables.Next);
break;
case NODE_TYPE_VALUES:
while (TRUE) {
FreeTreeSemantic(lpSql, lpSqlNode->node.values.Value);
if (lpSqlNode->node.values.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(lpSql, lpSqlNode->node.values.Next);
}
break;
case NODE_TYPE_COLUMNS:
while (TRUE) {
FreeTreeSemantic(lpSql, lpSqlNode->node.columns.Column);
if (lpSqlNode->node.columns.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(lpSql, lpSqlNode->node.columns.Next);
}
break;
case NODE_TYPE_SORTCOLUMNS:
while (TRUE) {
FreeTreeSemantic(lpSql, lpSqlNode->node.sortcolumns.Column);
if (lpSqlNode->node.sortcolumns.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(lpSql, lpSqlNode->node.sortcolumns.Next);
}
break;
case NODE_TYPE_GROUPBYCOLUMNS:
while (TRUE) {
FreeTreeSemantic(lpSql, lpSqlNode->node.groupbycolumns.Column);
if (lpSqlNode->node.groupbycolumns.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(lpSql, lpSqlNode->node.groupbycolumns.Next);
}
break;
case NODE_TYPE_UPDATEVALUES:
while (TRUE) {
FreeTreeSemantic(lpSql, lpSqlNode->node.updatevalues.Column);
FreeTreeSemantic(lpSql, lpSqlNode->node.updatevalues.Value);
if (lpSqlNode->node.updatevalues.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(lpSql, lpSqlNode->node.updatevalues.Next);
}
break;
case NODE_TYPE_CREATECOLS:
while (TRUE) {
if (lpSqlNode->node.createcols.Next == NO_SQLNODE)
break;
lpSqlNode = ToNode(lpSql, lpSqlNode->node.createcols.Next);
}
break;
case NODE_TYPE_BOOLEAN:
FreeTreeSemantic(lpSql, lpSqlNode->node.boolean.Left);
FreeTreeSemantic(lpSql, lpSqlNode->node.boolean.Right);
break;
case NODE_TYPE_COMPARISON:
FreeTreeSemantic(lpSql, lpSqlNode->node.comparison.Left);
FreeTreeSemantic(lpSql, lpSqlNode->node.comparison.Right);
break;
case NODE_TYPE_ALGEBRAIC:
FreeTreeSemantic(lpSql, lpSqlNode->node.algebraic.Left);
FreeTreeSemantic(lpSql, lpSqlNode->node.algebraic.Right);
break;
case NODE_TYPE_SCALAR:
FreeTreeSemantic(lpSql, lpSqlNode->node.scalar.Arguments);
break;
case NODE_TYPE_AGGREGATE:
FreeTreeSemantic(lpSql, lpSqlNode->node.aggregate.Expression);
break;
case NODE_TYPE_TABLE:
if (lpSqlNode->node.table.Handle != NULL) {
ISAMCloseTable(lpSqlNode->node.table.Handle);
lpSqlNode->node.table.Handle = NULL;
}
FreeTreeSemantic(lpSql, lpSqlNode->node.table.OuterJoinPredicate);
break;
case NODE_TYPE_COLUMN:
break;
case NODE_TYPE_STRING:
break;
case NODE_TYPE_NUMERIC:
break;
case NODE_TYPE_PARAMETER:
break;
case NODE_TYPE_USER:
break;
case NODE_TYPE_NULL:
break;
case NODE_TYPE_DATE:
break;
case NODE_TYPE_TIME:
break;
case NODE_TYPE_TIMESTAMP:
break;
default:
break;
}
}
/***************************************************************************/