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