Added what I think is full support for Null column values in the tables, partially based on submissions by Roger Gammans

Added a parameters to wxDbTable::Open() to indicate whether Open() should check for table privileges or not.
wxDbTable::ClearMemberVar() added to set a single column to an initialized value
::ClearMemberVar() and ::ClearMemberVars() can now optionally set a column to be NULL via ::SetColNull()
::SetColNull() added as the primary function name for setting a column to be a NULL value, and ::SetNull() is deprecated
::SetColNull() now has a param to select whether a columns value is NULL or not.
::SetColNull() will now clear the column value in memory when setting the column to be NULL.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@8767 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
George Tasker
2000-11-22 00:18:45 +00:00
parent 3988b155d7
commit f02d4a64a1
2 changed files with 181 additions and 82 deletions

View File

@@ -184,7 +184,7 @@ public:
const char *qryTblName = 0, bool qryOnly = !wxDB_QUERY_ONLY, const char *tblPath=""); const char *qryTblName = 0, bool qryOnly = !wxDB_QUERY_ONLY, const char *tblPath="");
virtual ~wxDbTable(); virtual ~wxDbTable();
bool Open(void); bool Open(bool checkPrivileges=FALSE);
bool CreateTable(bool attemptDrop=TRUE); bool CreateTable(bool attemptDrop=TRUE);
bool DropTable(void); bool DropTable(void);
bool CreateIndex(const char * idxName, bool unique, int noIdxCols, wxDbIdxDef *pIdxDefs, bool attemptDrop=TRUE); bool CreateIndex(const char * idxName, bool unique, int noIdxCols, wxDbIdxDef *pIdxDefs, bool attemptDrop=TRUE);
@@ -266,7 +266,8 @@ public:
#endif #endif
bool CanSelectForUpdate(void); bool CanSelectForUpdate(void);
bool CanUpdByROWID(void); bool CanUpdByROWID(void);
void ClearMemberVars(void); void ClearMemberVar(int colNo, bool setToNull=FALSE);
void ClearMemberVars(bool setToNull=FALSE);
bool SetQueryTimeout(UDWORD nSeconds); bool SetQueryTimeout(UDWORD nSeconds);
wxDbColDef *GetColDefs() { return colDefs; } wxDbColDef *GetColDefs() { return colDefs; }
@@ -289,9 +290,13 @@ public:
int DB_STATUS(void) { return(pDb->DB_STATUS); } int DB_STATUS(void) { return(pDb->DB_STATUS); }
bool IsColNull(int colNo); bool IsColNull(int colNo);
bool SetNull(int colNo); bool SetColNull(int colNo, bool set=TRUE);
bool SetNull(const char *colName); bool SetColNull(const char *colName, bool set=TRUE);
#if wxODBC_BACKWARD_COMPATABILITY
// The following member functions are deprecated. You should use the SetColNull()
bool SetNull(int colNo, bool set=TRUE) { return (SetNull(colNo,set)); }
bool SetNull(const char *colName, bool set=TRUE) { return (SetNull(colName,set)); }
#endif
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
ULONG GetTableID() { return tableID; } ULONG GetTableID() { return tableID; }
#endif #endif

View File

@@ -134,6 +134,8 @@ wxDbTable::wxDbTable(wxDb *pwxDb, const char *tblName, const int nCols,
wxStrcpy(tableName, tblName); // Table Name wxStrcpy(tableName, tblName); // Table Name
if (tblPath) if (tblPath)
wxStrcpy(tablePath, tblPath); // Table Path - used for dBase files wxStrcpy(tablePath, tblPath); // Table Path - used for dBase files
else
tablePath[0] = 0;
if (qryTblName) // Name of the table/view to query if (qryTblName) // Name of the table/view to query
wxStrcpy(queryTableName, qryTblName); wxStrcpy(queryTableName, qryTblName);
@@ -366,12 +368,18 @@ bool wxDbTable::bindInsertParams(void)
fSqlType = pDb->GetTypeInfVarchar().FsqlType; fSqlType = pDb->GetTypeInfVarchar().FsqlType;
precision = colDefs[i].SzDataObj; precision = colDefs[i].SzDataObj;
scale = 0; scale = 0;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = SQL_NTS; colDefs[i].CbValue = SQL_NTS;
break; break;
case DB_DATA_TYPE_INTEGER: case DB_DATA_TYPE_INTEGER:
fSqlType = pDb->GetTypeInfInteger().FsqlType; fSqlType = pDb->GetTypeInfInteger().FsqlType;
precision = pDb->GetTypeInfInteger().Precision; precision = pDb->GetTypeInfInteger().Precision;
scale = 0; scale = 0;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = 0; colDefs[i].CbValue = 0;
break; break;
case DB_DATA_TYPE_FLOAT: case DB_DATA_TYPE_FLOAT:
@@ -383,21 +391,28 @@ bool wxDbTable::bindInsertParams(void)
// I check for this here and set the scale = precision. // I check for this here and set the scale = precision.
//if (scale < 0) //if (scale < 0)
// scale = (short) precision; // scale = (short) precision;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = 0; colDefs[i].CbValue = 0;
break; break;
case DB_DATA_TYPE_DATE: case DB_DATA_TYPE_DATE:
fSqlType = pDb->GetTypeInfDate().FsqlType; fSqlType = pDb->GetTypeInfDate().FsqlType;
precision = pDb->GetTypeInfDate().Precision; precision = pDb->GetTypeInfDate().Precision;
scale = 0; scale = 0;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = 0; colDefs[i].CbValue = 0;
break; break;
} }
// Null values // Null values
if (colDefs[i].Null) //RG-NULL
{ //RG-NULL if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA; //RG-NULL {
colDefs[i].Null = FALSE; //RG-NULL colDefs[i].CbValue = SQL_NULL_DATA;
} //RG-NULL colDefs[i].Null = FALSE;
//RG-NULL }
if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype,
fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj,
@@ -436,12 +451,18 @@ bool wxDbTable::bindUpdateParams(void)
fSqlType = pDb->GetTypeInfVarchar().FsqlType; fSqlType = pDb->GetTypeInfVarchar().FsqlType;
precision = colDefs[i].SzDataObj; precision = colDefs[i].SzDataObj;
scale = 0; scale = 0;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = SQL_NTS; colDefs[i].CbValue = SQL_NTS;
break; break;
case DB_DATA_TYPE_INTEGER: case DB_DATA_TYPE_INTEGER:
fSqlType = pDb->GetTypeInfInteger().FsqlType; fSqlType = pDb->GetTypeInfInteger().FsqlType;
precision = pDb->GetTypeInfInteger().Precision; precision = pDb->GetTypeInfInteger().Precision;
scale = 0; scale = 0;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = 0; colDefs[i].CbValue = 0;
break; break;
case DB_DATA_TYPE_FLOAT: case DB_DATA_TYPE_FLOAT:
@@ -453,12 +474,18 @@ bool wxDbTable::bindUpdateParams(void)
// I check for this here and set the scale = precision. // I check for this here and set the scale = precision.
//if (scale < 0) //if (scale < 0)
// scale = (short) precision; // scale = (short) precision;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = 0; colDefs[i].CbValue = 0;
break; break;
case DB_DATA_TYPE_DATE: case DB_DATA_TYPE_DATE:
fSqlType = pDb->GetTypeInfDate().FsqlType; fSqlType = pDb->GetTypeInfDate().FsqlType;
precision = pDb->GetTypeInfDate().Precision; precision = pDb->GetTypeInfDate().Precision;
scale = 0; scale = 0;
if (colDefs[i].Null)
colDefs[i].CbValue = SQL_NULL_DATA;
else
colDefs[i].CbValue = 0; colDefs[i].CbValue = 0;
break; break;
} }
@@ -480,14 +507,15 @@ bool wxDbTable::bindUpdateParams(void)
/********** wxDbTable::bindCols() **********/ /********** wxDbTable::bindCols() **********/
bool wxDbTable::bindCols(HSTMT cursor) bool wxDbTable::bindCols(HSTMT cursor)
{ {
static SDWORD cb; //RG-NULL static SDWORD cb;
// Bind each column of the table to a memory address for fetching data // Bind each column of the table to a memory address for fetching data
int i; int i;
for (i = 0; i < noCols; i++) for (i = 0; i < noCols; i++)
{ {
if (SQLBindCol(cursor, i+1, colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, if (SQLBindCol(cursor, i+1, colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj,
colDefs[i].SzDataObj, &cb) != SQL_SUCCESS) //RG-NULL colDefs[i].SzDataObj, &cb) != SQL_SUCCESS)
colDefs[i].SzDataObj, &colDefs[i].CbValue ) != SQL_SUCCESS)
{ {
return (pDb->DispAllErrors(henv, hdbc, cursor)); return (pDb->DispAllErrors(henv, hdbc, cursor));
} }
@@ -518,6 +546,14 @@ bool wxDbTable::getRec(UWORD fetchType)
else else
return(pDb->DispAllErrors(henv, hdbc, hstmt)); return(pDb->DispAllErrors(henv, hdbc, hstmt));
} }
else
{
// Set the Null member variable to indicate the Null state
// of each column just read in.
int i;
for (i = 0; i < noCols; i++)
colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
}
} }
else else
{ {
@@ -530,6 +566,14 @@ bool wxDbTable::getRec(UWORD fetchType)
else else
return(pDb->DispAllErrors(henv, hdbc, hstmt)); return(pDb->DispAllErrors(henv, hdbc, hstmt));
} }
else
{
// Set the Null member variable to indicate the Null state
// of each column just read in.
int i;
for (i = 0; i < noCols; i++)
colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
}
} }
// Completed successfully // Completed successfully
@@ -569,7 +613,6 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const char *
{ {
char sqlStmt[DB_MAX_STATEMENT_LEN]; char sqlStmt[DB_MAX_STATEMENT_LEN];
// Set the selectForUpdate member variable
if (forUpdate) if (forUpdate)
// The user may wish to select for update, but the DBMS may not be capable // The user may wish to select for update, but the DBMS may not be capable
selectForUpdate = CanSelectForUpdate(); selectForUpdate = CanSelectForUpdate();
@@ -618,27 +661,50 @@ bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const char *
/********** wxDbTable::Open() **********/ /********** wxDbTable::Open() **********/
bool wxDbTable::Open(void) bool wxDbTable::Open(bool checkPrivileges)
{ {
if (!pDb) if (!pDb)
return FALSE; return FALSE;
int i; int i;
wxString sqlStmt; wxString sqlStmt;
// Verify that the table exists in the database
if (!pDb->TableExists(tableName,pDb->GetUsername(),tablePath))
{
wxString s; wxString s;
s = "";
// Verify that the table exists in the database
if (!pDb->TableExists(tableName,/*pDb->GetUsername()*/NULL,tablePath))
{
s = "Table/view does not exist in the database";
if ( *(pDb->dbInf.accessibleTables) == 'Y')
s += ", or you have no permissions.\n";
else
s += ".\n";
}
else if (checkPrivileges)
{
// Verify the user has rights to access the table.
// Shortcut boolean evaluation to optimize out call to
// TablePrivileges
//
// Unfortunately this optimization doesn't seem to be
// reliable!
if (// *(pDb->dbInf.accessibleTables) == 'N' &&
!pDb->TablePrivileges(tableName,"SELECT",NULL,pDb->GetUsername(),tablePath))
s = "Current logged in user does not have sufficient privileges to access this table.\n";
}
if (!s.IsEmpty())
{
wxString p;
if (wxStrcmp(tablePath,"")) if (wxStrcmp(tablePath,""))
s.sprintf(wxT("Error opening '%s/%s'.\n"),tablePath,tableName); p.sprintf("Error opening '%s/%s'.\n",tablePath,tableName);
else else
s.sprintf(wxT("Error opening '%s'.\n"), tableName); p.sprintf("Error opening '%s'.\n", tableName);
if (!pDb->TableExists(tableName,NULL,tablePath))
s += wxT("Table/view does not exist in the database.\n"); p += s;
else pDb->LogError(p.GetData());
s += wxT("Current logged in user does not have sufficient privileges to access this table.\n");
pDb->LogError(s.c_str());
return(FALSE); return(FALSE);
} }
@@ -1672,7 +1738,7 @@ void wxDbTable::BuildWhereClause(char *pWhereClause, int typeOfWhere,
{ {
// Determine if this column should be included in the WHERE clause // Determine if this column should be included in the WHERE clause
if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[i].KeyField) || if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[i].KeyField) ||
(typeOfWhere == DB_WHERE_MATCHING && (! IsColNull(i)))) (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(i))))
{ {
// Skip over timestamp columns // Skip over timestamp columns
if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP) if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP)
@@ -1726,6 +1792,10 @@ void wxDbTable::BuildWhereClause(char *pWhereClause, int typeOfWhere,
/********** wxDbTable::IsColNull() **********/ /********** wxDbTable::IsColNull() **********/
bool wxDbTable::IsColNull(int colNo) bool wxDbTable::IsColNull(int colNo)
{ {
/*
This logic is just not right. It would indicate TRUE
if a numeric field were set to a value of 0.
switch(colDefs[colNo].SqlCtype) switch(colDefs[colNo].SqlCtype)
{ {
case SQL_C_CHAR: case SQL_C_CHAR:
@@ -1752,6 +1822,8 @@ bool wxDbTable::IsColNull(int colNo)
default: default:
return(TRUE); return(TRUE);
} }
*/
return (colDefs[colNo].Null);
} // wxDbTable::IsColNull() } // wxDbTable::IsColNull()
@@ -1798,39 +1870,38 @@ bool wxDbTable::IsCursorClosedOnCommit(void)
} // wxDbTable::IsCursorClosedOnCommit() } // wxDbTable::IsCursorClosedOnCommit()
/********** wxDbTable::ClearMemberVars() **********/
void wxDbTable::ClearMemberVars(void) /********** wxDbTable::ClearMemberVar() **********/
void wxDbTable::ClearMemberVar(int colNo, bool setToNull)
{ {
// Loop through the columns setting each member variable to zero assert(colNo < noCols);
int i;
for (i = 0; i < noCols; i++) switch(colDefs[colNo].SqlCtype)
{
switch(colDefs[i].SqlCtype)
{ {
case SQL_C_CHAR: case SQL_C_CHAR:
((UCHAR FAR *) colDefs[i].PtrDataObj)[0] = 0; ((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] = 0;
break; break;
case SQL_C_SSHORT: case SQL_C_SSHORT:
*((SWORD *) colDefs[i].PtrDataObj) = 0; *((SWORD *) colDefs[colNo].PtrDataObj) = 0;
break; break;
case SQL_C_USHORT: case SQL_C_USHORT:
*((UWORD*) colDefs[i].PtrDataObj) = 0; *((UWORD*) colDefs[colNo].PtrDataObj) = 0;
break; break;
case SQL_C_SLONG: case SQL_C_SLONG:
*((SDWORD *) colDefs[i].PtrDataObj) = 0; *((SDWORD *) colDefs[colNo].PtrDataObj) = 0;
break; break;
case SQL_C_ULONG: case SQL_C_ULONG:
*((UDWORD *) colDefs[i].PtrDataObj) = 0; *((UDWORD *) colDefs[colNo].PtrDataObj) = 0;
break; break;
case SQL_C_FLOAT: case SQL_C_FLOAT:
*((SFLOAT *) colDefs[i].PtrDataObj) = 0.0f; *((SFLOAT *) colDefs[colNo].PtrDataObj) = 0.0f;
break; break;
case SQL_C_DOUBLE: case SQL_C_DOUBLE:
*((SDOUBLE *) colDefs[i].PtrDataObj) = 0.0f; *((SDOUBLE *) colDefs[colNo].PtrDataObj) = 0.0f;
break; break;
case SQL_C_TIMESTAMP: case SQL_C_TIMESTAMP:
TIMESTAMP_STRUCT *pDt; TIMESTAMP_STRUCT *pDt;
pDt = (TIMESTAMP_STRUCT *) colDefs[i].PtrDataObj; pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj;
pDt->year = 0; pDt->year = 0;
pDt->month = 0; pDt->month = 0;
pDt->day = 0; pDt->day = 0;
@@ -1840,7 +1911,20 @@ void wxDbTable::ClearMemberVars(void)
pDt->fraction = 0; pDt->fraction = 0;
break; break;
} }
}
if (setToNull)
SetColNull(colNo);
} // wxDbTable::ClearMemberVar()
/********** wxDbTable::ClearMemberVars() **********/
void wxDbTable::ClearMemberVars(bool setToNull)
{
int i;
// Loop through the columns setting each member variable to zero
for (i=0; i < noCols; i++)
ClearMemberVar(i,setToNull);
} // wxDbTable::ClearMemberVars() } // wxDbTable::ClearMemberVars()
@@ -2118,19 +2202,24 @@ bool wxDbTable::Refresh(void)
} // wxDbTable::Refresh() } // wxDbTable::Refresh()
/********** wxDbTable::SetNull(int colNo) **********/ /********** wxDbTable::SetColNull(int colNo, bool set) **********/
bool wxDbTable::SetNull(int colNo) bool wxDbTable::SetColNull(int colNo, bool set)
{ {
if (colNo < noCols) if (colNo < noCols)
return(colDefs[colNo].Null = TRUE); {
colDefs[colNo].Null = set;
if (set) // Blank out the values in the member variable
ClearMemberVar(colNo,FALSE); // Must call with FALSE, or infinite recursion will happen
return(TRUE);
}
else else
return(FALSE); return(FALSE);
} // wxDbTable::SetNull(int colNo) } // wxDbTable::SetColNull(int colNo)
/********** wxDbTable::SetNull(char *colName) **********/ /********** wxDbTable::SetColNull(char *colName, bool set) **********/
bool wxDbTable::SetNull(const char *colName) bool wxDbTable::SetColNull(const char *colName, bool set)
{ {
int i; int i;
for (i = 0; i < noCols; i++) for (i = 0; i < noCols; i++)
@@ -2140,11 +2229,16 @@ bool wxDbTable::SetNull(const char *colName)
} }
if (i < noCols) if (i < noCols)
return(colDefs[i].Null = TRUE); {
colDefs[i].Null = set;
if (set) // Blank out the values in the member variable
ClearMemberVar(i,FALSE); // Must call with FALSE, or infinite recursion will happen
return(TRUE);
}
else else
return(FALSE); return(FALSE);
} // wxDbTable::SetNull(char *colName) } // wxDbTable::SetColNull(char *colName)
/********** wxDbTable::GetNewCursor() **********/ /********** wxDbTable::GetNewCursor() **********/