From: Byron Nikolaidis Date: Tue, 5 Jan 1999 00:32:21 +0000 (+0000) Subject: Mini Update #2 -- final fixes for buffer lengths, null buffers, truncation X-Git-Tag: REL6_5~839 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8aad28da2d0a89b8827125c519e5f52c2748a116;p=postgresql Mini Update #2 -- final fixes for buffer lengths, null buffers, truncation --- diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h index c076bc2926..d07fd60362 100644 --- a/src/interfaces/odbc/connection.h +++ b/src/interfaces/odbc/connection.h @@ -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 diff --git a/src/interfaces/odbc/drvconn.c b/src/interfaces/odbc/drvconn.c index 7959ed998c..cfb514c7fc 100644 --- a/src/interfaces/odbc/drvconn.c +++ b/src/interfaces/odbc/drvconn.c @@ -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 diff --git a/src/interfaces/odbc/environ.c b/src/interfaces/odbc/environ.c index bf99135133..1fa005b4c4 100644 --- a/src/interfaces/odbc/environ.c +++ b/src/interfaces/odbc/environ.c @@ -242,6 +242,7 @@ int status; strcpy(szSqlState, "01S02"); break; case STMT_TRUNCATED: + case CONN_TRUNCATED: strcpy(szSqlState, "01004"); // data truncated break; diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c index 59cfa450a1..87b6a31162 100644 --- a/src/interfaces/odbc/execute.c +++ b/src/interfaces/odbc/execute.c @@ -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); + + 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; + } + + 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; - strncpy_null(szSqlStr, szSqlStrIn, cbSqlStrMax); + free(ptr); - return SQL_SUCCESS; + return result; } // - - - - - - - - - diff --git a/src/interfaces/odbc/results.c b/src/interfaces/odbc/results.c index 7595fd5e3b..7b2a0dc049 100644 --- a/src/interfaces/odbc/results.c +++ b/src/interfaces/odbc/results.c @@ -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); - - strncpy_null((char *)rgbDesc, value, cbDescMax); - - if (pcbDesc) - *pcbDesc = strlen(value); + p = (parse_ok) ? stmt->fi[icol]->name : QR_get_fieldname(stmt->result, icol); - 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; }