From 7e2c9393dcdbf1620c39650cce6e0d21a7c1bf44 Mon Sep 17 00:00:00 2001 From: surendrasignalwire Date: Wed, 10 Jun 2020 20:09:01 +0400 Subject: [PATCH] [core] Fix ODBC column size performance issue --- src/switch_odbc.c | 57 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/switch_odbc.c b/src/switch_odbc.c index 31161ee158..9ea062d997 100644 --- a/src/switch_odbc.c +++ b/src/switch_odbc.c @@ -605,17 +605,66 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(c for (x = 1; x <= c; x++) { SQLSMALLINT NameLength = 0, DataType = 0, DecimalDigits = 0, Nullable = 0; SQLULEN ColumnSize = 0; + SQLLEN numRecs = 0; + SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH]; + SQLINTEGER NativeError; + SQLSMALLINT diagCount, MsgLen; names[y] = malloc(name_len); switch_assert(names[y]); memset(names[y], 0, name_len); SQLDescribeCol(stmt, x, (SQLCHAR *) names[y], (SQLSMALLINT) name_len, &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable); - if (!ColumnSize) { + if (ColumnSize <= 16383 || ColumnSize == 2147483647) { SQLCHAR val[16384] = { 0 }; + SQLLEN StrLen_or_IndPtr; + SQLRETURN rc; ColumnSize = 16384; - SQLGetData(stmt, x, SQL_C_CHAR, val, ColumnSize, NULL); - vals[y] = strdup((char *)val); + + /* check diag record and see if we can get real size + * https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/using-sqlgetdiagrec-and-sqlgetdiagfield?view=sql-server-ver15 + * szSqlState = "01004" and StrLen_or_IndPtr=15794 + */ + rc = SQLGetData(stmt, x, SQL_C_CHAR, val, ColumnSize, &StrLen_or_IndPtr); + + if (rc == SQL_SUCCESS_WITH_INFO) { + int truncated = 0; + diagCount = 1; + + SQLGetDiagField(SQL_HANDLE_STMT, stmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0); + + while (diagCount <= numRecs) { + SQLGetDiagRec(SQL_HANDLE_STMT, stmt, diagCount, SqlState, &NativeError,Msg, sizeof(Msg), &MsgLen); + if (!strcmp((char*)SqlState,"01004")){ + truncated = 1; + break; + } + + diagCount++; + } + + if (truncated) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql data truncated - %s\n",SqlState); + if (StrLen_or_IndPtr && StrLen_or_IndPtr <= 268435456) { + ColumnSize = StrLen_or_IndPtr + 1; + vals[y] = malloc(ColumnSize); + switch_assert(vals[y]); + memset(vals[y], 0, ColumnSize); + SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *) vals[y], ColumnSize, NULL); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed"); + vals[y] = NULL; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed"); + vals[y] = NULL; + } + } else if (rc == SQL_SUCCESS){ + vals[y] = strdup((char *)val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed"); + vals[y] = NULL; + } } else { ColumnSize++; @@ -633,7 +682,7 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(c for (x = 0; x < y; x++) { free(names[x]); - free(vals[x]); + switch_safe_free(vals[x]); } free(names); free(vals);