aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interfaces/odbc/connection.h2
-rw-r--r--src/interfaces/odbc/drvconn.c57
-rw-r--r--src/interfaces/odbc/environ.c1
-rw-r--r--src/interfaces/odbc/execute.c37
-rw-r--r--src/interfaces/odbc/results.c260
5 files changed, 207 insertions, 150 deletions
diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h
index c076bc2926e..d07fd60362a 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 7959ed998cc..cfb514c7fc5 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 bf99135133c..1fa005b4c46 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 59cfa450a10..87b6a31162f 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 7595fd5e3ba..7b2a0dc0497 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;
}