Mini Update #2 -- final fixes for buffer lengths, null buffers, truncation

This commit is contained in:
Byron Nikolaidis 1999-01-05 00:32:21 +00:00
parent 1bbe55c79f
commit 8aad28da2d
5 changed files with 207 additions and 150 deletions

View File

@ -65,6 +65,8 @@ typedef enum {
#define CONN_OPTION_VALUE_CHANGED 213
#define CONN_VALUE_OUT_OF_RANGE 214
#define CONN_TRUNCATED 215
/* Conn_status defines */
#define CONN_IN_AUTOCOMMIT 0x01
#define CONN_IN_TRANSACTION 0x02

View File

@ -79,12 +79,14 @@ static char *func = "SQLDriverConnect";
ConnectionClass *conn = (ConnectionClass *) hdbc;
ConnInfo *ci;
#ifdef WIN32
RETCODE dialog_result;
RETCODE dialog_result, result;
#endif
char connStrIn[MAX_CONNECT_STRING];
char connStrOut[MAX_CONNECT_STRING];
int retval;
char password_required = FALSE;
int len = 0;
mylog("%s: entering...\n", func);
@ -166,22 +168,6 @@ dialog:
return SQL_NO_DATA_FOUND;
}
if(szConnStrOut) {
/* Return the completed string to the caller.
Only construct the connect string if a dialog was put up,
otherwise, just copy the connection input string to the output.
*/
makeConnectString(connStrOut, ci);
if(pcbConnStrOut) {
*pcbConnStrOut = strlen(connStrOut);
}
strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
}
mylog("szConnStrOut = '%s'\n", szConnStrOut);
qlog("conn=%u, SQLDriverConnect(out)='%s'\n", conn, szConnStrOut);
// do the actual connect
retval = CC_connect(conn, password_required);
@ -205,8 +191,41 @@ dialog:
return SQL_ERROR;
}
mylog("SQLDRiverConnect: returning success\n");
return SQL_SUCCESS;
/*********************************************/
/* Create the Output Connection String */
/*********************************************/
result = SQL_SUCCESS;
makeConnectString(connStrOut, ci);
len = strlen(connStrOut);
if(szConnStrOut) {
/* Return the completed string to the caller. The correct method is to
only construct the connect string if a dialog was put up, otherwise,
it should just copy the connection input string to the output.
However, it seems ok to just always construct an output string. There
are possible bad side effects on working applications (Access) by
implementing the correct behavior, anyway.
*/
strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);
if (len >= cbConnStrOutMax) {
result = SQL_SUCCESS_WITH_INFO;
conn->errornumber = CONN_TRUNCATED;
conn->errormsg = "The buffer was too small for the result.";
}
}
if(pcbConnStrOut)
*pcbConnStrOut = len;
mylog("szConnStrOut = '%s'\n", szConnStrOut);
qlog("conn=%u, SQLDriverConnect(out)='%s'\n", conn, szConnStrOut);
mylog("SQLDRiverConnect: returning %d\n", result);
return result;
}
#ifdef WIN32

View File

@ -242,6 +242,7 @@ int status;
strcpy(szSqlState, "01S02");
break;
case STMT_TRUNCATED:
case CONN_TRUNCATED:
strcpy(szSqlState, "01004");
// data truncated
break;

View File

@ -431,7 +431,8 @@ FARPROC addr;
// - - - - - - - - -
// Returns the SQL string as modified by the driver.
// Currently, just copy the input string without modification
// observing buffer limits and truncation.
RETCODE SQL_API SQLNativeSql(
HDBC hdbc,
UCHAR FAR *szSqlStrIn,
@ -441,12 +442,40 @@ RETCODE SQL_API SQLNativeSql(
SDWORD FAR *pcbSqlStr)
{
static char *func="SQLNativeSql";
int len = 0;
char *ptr;
ConnectionClass *conn = (ConnectionClass *) hdbc;
RETCODE result;
mylog( "%s: entering...\n", func);
mylog( "%s: entering...cbSqlStrIn=%d\n", func, cbSqlStrIn);
strncpy_null(szSqlStr, szSqlStrIn, cbSqlStrMax);
ptr = (cbSqlStrIn == 0) ? "" : make_string(szSqlStrIn, cbSqlStrIn, NULL);
if ( ! ptr) {
conn->errornumber = CONN_NO_MEMORY_ERROR;
conn->errormsg = "No memory available to store native sql string";
CC_log_error(func, "", conn);
return SQL_ERROR;
}
return SQL_SUCCESS;
result = SQL_SUCCESS;
len = strlen(ptr);
if (szSqlStr) {
strncpy_null(szSqlStr, ptr, cbSqlStrMax);
if (len >= cbSqlStrMax) {
result = SQL_SUCCESS_WITH_INFO;
conn->errornumber = STMT_TRUNCATED;
conn->errormsg = "The buffer was too small for the result.";
}
}
if (pcbSqlStr)
*pcbSqlStr = len;
free(ptr);
return result;
}
// - - - - - - - - -

View File

@ -175,13 +175,16 @@ RETCODE SQL_API SQLDescribeCol(
static char *func="SQLDescribeCol";
/* gets all the information about a specific column */
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *result;
QResultClass *res;
char *col_name = NULL;
Int4 fieldtype = 0;
int precision = 0;
ConnInfo *ci;
char parse_ok;
char buf[255];
int len = 0;
RETCODE result;
mylog("%s: entering...\n", func);
@ -239,10 +242,10 @@ char buf[255];
if ( ! parse_ok) {
SC_pre_execute(stmt);
result = SC_get_Result(stmt);
res = SC_get_Result(stmt);
mylog("**** SQLDescribeCol: result = %u, stmt->status = %d, !finished=%d, !premature=%d\n", result, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
if ( (NULL == result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) {
mylog("**** SQLDescribeCol: res = %u, stmt->status = %d, !finished=%d, !premature=%d\n", res, stmt->status, stmt->status != STMT_FINISHED, stmt->status != STMT_PREMATURE);
if ( (NULL == res) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) {
/* no query has been executed on this statement */
stmt->errornumber = STMT_SEQUENCE_ERROR;
stmt->errormsg = "No query has been assigned to this statement.";
@ -250,16 +253,16 @@ char buf[255];
return SQL_ERROR;
}
if (icol >= QR_NumResultCols(result)) {
if (icol >= QR_NumResultCols(res)) {
stmt->errornumber = STMT_INVALID_COLUMN_NUMBER_ERROR;
stmt->errormsg = "Invalid column number in DescribeCol.";
sprintf(buf, "Col#=%d, #Cols=%d", icol, QR_NumResultCols(result));
sprintf(buf, "Col#=%d, #Cols=%d", icol, QR_NumResultCols(res));
SC_log_error(func, buf, stmt);
return SQL_ERROR;
}
col_name = QR_get_fieldname(result, icol);
fieldtype = QR_get_field_type(result, icol);
col_name = QR_get_fieldname(res, icol);
fieldtype = QR_get_field_type(res, icol);
precision = pgtype_precision(stmt, fieldtype, icol, globals.unknown_sizes); // atoi(ci->unknown_sizes)
}
@ -268,28 +271,40 @@ char buf[255];
mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype);
mylog("describeCol: col %d precision = %d\n", icol, precision);
if (cbColNameMax >= 1) {
if (pcbColName) {
if (col_name)
*pcbColName = strlen(col_name);
else
*pcbColName = 0;
}
if (szColName) {
if (col_name)
strncpy_null(szColName, col_name, cbColNameMax);
else
szColName[0] = '\0';
}
result = SQL_SUCCESS;
/************************/
/* COLUMN NAME */
/************************/
len = strlen(col_name);
if (pcbColName)
*pcbColName = len;
if (szColName) {
strncpy_null(szColName, col_name, cbColNameMax);
if (len >= cbColNameMax) {
result = SQL_SUCCESS_WITH_INFO;
stmt->errornumber = STMT_TRUNCATED;
stmt->errormsg = "The buffer was too small for the result.";
}
}
/************************/
/* SQL TYPE */
/************************/
if (pfSqlType) {
*pfSqlType = pgtype_to_sqltype(stmt, fieldtype);
mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType);
}
/************************/
/* PRECISION */
/************************/
if (pcbColDef) {
if ( precision < 0)
@ -300,6 +315,9 @@ char buf[255];
mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef);
}
/************************/
/* SCALE */
/************************/
if (pibScale) {
Int2 scale;
scale = pgtype_scale(stmt, fieldtype);
@ -309,16 +327,16 @@ char buf[255];
mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale);
}
/************************/
/* NULLABILITY */
/************************/
if (pfNullable) {
if (parse_ok)
*pfNullable = stmt->fi[icol]->nullable;
else
*pfNullable = pgtype_nullable(stmt, fieldtype);
*pfNullable = (parse_ok) ? stmt->fi[icol]->nullable : pgtype_nullable(stmt, fieldtype);
mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable);
}
return SQL_SUCCESS;
return result;
}
// Returns result column descriptor information for a result set.
@ -334,12 +352,14 @@ RETCODE SQL_API SQLColAttributes(
{
static char *func = "SQLColAttributes";
StatementClass *stmt = (StatementClass *) hstmt;
char *value;
Int4 field_type = 0;
ConnInfo *ci;
int unknown_sizes;
int cols = 0;
char parse_ok;
RETCODE result;
char *p = NULL;
int len = 0, value = 0;
mylog("%s: entering...\n", func);
@ -434,17 +454,14 @@ char parse_ok;
switch(fDescType) {
case SQL_COLUMN_AUTO_INCREMENT:
if (pfDesc) {
*pfDesc = pgtype_auto_increment(stmt, field_type);
if (*pfDesc == -1) /* non-numeric becomes FALSE (ODBC Doc) */
*pfDesc = FALSE;
value = pgtype_auto_increment(stmt, field_type);
if (value == -1) /* non-numeric becomes FALSE (ODBC Doc) */
value = FALSE;
}
break;
case SQL_COLUMN_CASE_SENSITIVE:
if (pfDesc)
*pfDesc = pgtype_case_sensitive(stmt, field_type);
value = pgtype_case_sensitive(stmt, field_type);
break;
/* This special case is handled above.
@ -453,151 +470,127 @@ char parse_ok;
*/
case SQL_COLUMN_DISPLAY_SIZE:
if (pfDesc) {
if (parse_ok)
*pfDesc = stmt->fi[icol]->display_size;
else
*pfDesc = pgtype_display_size(stmt, field_type, icol, unknown_sizes);
}
value = (parse_ok) ? stmt->fi[icol]->display_size : pgtype_display_size(stmt, field_type, icol, unknown_sizes);
mylog("SQLColAttributes: col %d, display_size= %d\n", icol, *pfDesc);
mylog("SQLColAttributes: col %d, display_size= %d\n", icol, value);
break;
case SQL_COLUMN_LABEL:
if (parse_ok && stmt->fi[icol]->alias[0] != '\0') {
strncpy_null((char *)rgbDesc, stmt->fi[icol]->alias, cbDescMax);
if (pcbDesc)
*pcbDesc = strlen(stmt->fi[icol]->alias);
p = stmt->fi[icol]->alias;
mylog("SQLColAttr: COLUMN_LABEL = '%s'\n", p);
break;
mylog("SQLColAttr: COLUMN_LABEL = '%s'\n", rgbDesc);
} // otherwise same as column name
} // otherwise same as column name -- FALL THROUGH!!!
case SQL_COLUMN_NAME:
if (parse_ok)
value = stmt->fi[icol]->name;
else
value = QR_get_fieldname(stmt->result, icol);
p = (parse_ok) ? stmt->fi[icol]->name : QR_get_fieldname(stmt->result, icol);
strncpy_null((char *)rgbDesc, value, cbDescMax);
if (pcbDesc)
*pcbDesc = strlen(value);
mylog("SQLColAttr: COLUMN_NAME = '%s'\n", rgbDesc);
mylog("SQLColAttr: COLUMN_NAME = '%s'\n", p);
break;
case SQL_COLUMN_LENGTH:
if (pfDesc) {
if (parse_ok)
*pfDesc = stmt->fi[icol]->length;
else
*pfDesc = pgtype_length(stmt, field_type, icol, unknown_sizes);
}
mylog("SQLColAttributes: col %d, length = %d\n", icol, *pfDesc);
value = (parse_ok) ? stmt->fi[icol]->length : pgtype_length(stmt, field_type, icol, unknown_sizes);
mylog("SQLColAttributes: col %d, length = %d\n", icol, value);
break;
case SQL_COLUMN_MONEY:
if (pfDesc)
*pfDesc = pgtype_money(stmt, field_type);
value = pgtype_money(stmt, field_type);
break;
case SQL_COLUMN_NULLABLE:
if (pfDesc) {
if (parse_ok)
*pfDesc = stmt->fi[icol]->nullable;
else
*pfDesc = pgtype_nullable(stmt, field_type);
}
value = (parse_ok) ? stmt->fi[icol]->nullable : pgtype_nullable(stmt, field_type);
break;
case SQL_COLUMN_OWNER_NAME:
strncpy_null((char *)rgbDesc, "", cbDescMax);
if (pcbDesc)
*pcbDesc = 0;
p = "";
break;
case SQL_COLUMN_PRECISION:
if (pfDesc) {
if (parse_ok)
*pfDesc = stmt->fi[icol]->precision;
else
*pfDesc = pgtype_precision(stmt, field_type, icol, unknown_sizes);
}
mylog("SQLColAttributes: col %d, precision = %d\n", icol, *pfDesc);
value = (parse_ok) ? stmt->fi[icol]->precision : pgtype_precision(stmt, field_type, icol, unknown_sizes);
mylog("SQLColAttributes: col %d, precision = %d\n", icol, value);
break;
case SQL_COLUMN_QUALIFIER_NAME:
strncpy_null((char *)rgbDesc, "", cbDescMax);
if (pcbDesc)
*pcbDesc = 0;
p = "";
break;
case SQL_COLUMN_SCALE:
if (pfDesc)
*pfDesc = pgtype_scale(stmt, field_type);
value = pgtype_scale(stmt, field_type);
break;
case SQL_COLUMN_SEARCHABLE:
if (pfDesc)
*pfDesc = pgtype_searchable(stmt, field_type);
value = pgtype_searchable(stmt, field_type);
break;
case SQL_COLUMN_TABLE_NAME:
if (parse_ok && stmt->fi[icol]->ti) {
strncpy_null((char *)rgbDesc, stmt->fi[icol]->ti->name, cbDescMax);
if (pcbDesc)
*pcbDesc = strlen(stmt->fi[icol]->ti->name);
}
else {
strncpy_null((char *)rgbDesc, "", cbDescMax);
if (pcbDesc)
*pcbDesc = 0;
}
mylog("SQLColAttr: TABLE_NAME = '%s'\n", rgbDesc);
p = (parse_ok && stmt->fi[icol]->ti) ? stmt->fi[icol]->ti->name : "";
mylog("SQLColAttr: TABLE_NAME = '%s'\n", p);
break;
case SQL_COLUMN_TYPE:
if (pfDesc) {
*pfDesc = pgtype_to_sqltype(stmt, field_type);
}
value = pgtype_to_sqltype(stmt, field_type);
break;
case SQL_COLUMN_TYPE_NAME:
value = pgtype_to_name(stmt, field_type);
strncpy_null((char *)rgbDesc, value, cbDescMax);
if (pcbDesc)
*pcbDesc = strlen(value);
p = pgtype_to_name(stmt, field_type);
break;
case SQL_COLUMN_UNSIGNED:
if (pfDesc) {
*pfDesc = pgtype_unsigned(stmt, field_type);
if(*pfDesc == -1) /* non-numeric becomes TRUE (ODBC Doc) */
*pfDesc = TRUE;
}
value = pgtype_unsigned(stmt, field_type);
if(value == -1) /* non-numeric becomes TRUE (ODBC Doc) */
value = TRUE;
break;
case SQL_COLUMN_UPDATABLE:
if (pfDesc) {
/* Neither Access or Borland care about this.
/* Neither Access or Borland care about this.
if (field_type == PG_TYPE_OID)
*pfDesc = SQL_ATTR_READONLY;
else
*/
if (field_type == PG_TYPE_OID)
*pfDesc = SQL_ATTR_READONLY;
else
*/
*pfDesc = SQL_ATTR_WRITE;
mylog("SQLColAttr: UPDATEABLE = %d\n", *pfDesc);
}
value = SQL_ATTR_WRITE;
mylog("SQLColAttr: UPDATEABLE = %d\n", value);
break;
}
return SQL_SUCCESS;
result = SQL_SUCCESS;
if (p) { /* char/binary data */
len = strlen(p);
if (rgbDesc) {
strncpy_null((char *)rgbDesc, p, (size_t)cbDescMax);
if (len >= cbDescMax) {
result = SQL_SUCCESS_WITH_INFO;
stmt->errornumber = STMT_TRUNCATED;
stmt->errormsg = "The buffer was too small for the result.";
}
}
if (pcbDesc)
*pcbDesc = len;
}
else { /* numeric data */
if (pfDesc)
*pfDesc = value;
}
return result;
}
// Returns result data for a single column in the current row.
@ -1162,14 +1155,15 @@ mylog("SQLSetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d\n", hstmt, szCurs
}
len = (cbCursor == SQL_NTS) ? strlen(szCursor) : cbCursor;
mylog("cursor len = %d\n", len);
if (len <= 0 || len > sizeof(stmt->cursor_name) - 1) {
stmt->errornumber = STMT_INVALID_CURSOR_NAME;
stmt->errormsg = "Invalid Cursor Name";
SC_log_error(func, "", stmt);
return SQL_ERROR;
}
strncpy_null(stmt->cursor_name, szCursor, cbCursor);
strncpy_null(stmt->cursor_name, szCursor, len+1);
return SQL_SUCCESS;
}
@ -1183,6 +1177,8 @@ RETCODE SQL_API SQLGetCursorName(
{
static char *func="SQLGetCursorName";
StatementClass *stmt = (StatementClass *) hstmt;
int len = 0;
RETCODE result;
mylog("SQLGetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n", hstmt, szCursor, cbCursorMax, pcbCursor);
@ -1191,7 +1187,6 @@ mylog("SQLGetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n",
return SQL_INVALID_HANDLE;
}
if ( stmt->cursor_name[0] == '\0') {
stmt->errornumber = STMT_NO_CURSOR_NAME;
stmt->errormsg = "No Cursor name available";
@ -1199,12 +1194,23 @@ mylog("SQLGetCursorName: hstmt=%u, szCursor=%u, cbCursorMax=%d, pcbCursor=%u\n",
return SQL_ERROR;
}
strncpy_null(szCursor, stmt->cursor_name, cbCursorMax);
result = SQL_SUCCESS;
len = strlen(stmt->cursor_name);
if (szCursor) {
strncpy_null(szCursor, stmt->cursor_name, cbCursorMax);
if (len >= cbCursorMax) {
result = SQL_SUCCESS_WITH_INFO;
stmt->errornumber = STMT_TRUNCATED;
stmt->errormsg = "The buffer was too small for the result.";
}
}
if (pcbCursor)
*pcbCursor = strlen(szCursor);
*pcbCursor = len;
return SQL_SUCCESS;
return result;
}