]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[core] Fix ODBC column size performance issue
authorsurendrasignalwire <surendra.tiwari@siganlwire.com>
Wed, 10 Jun 2020 16:09:01 +0000 (20:09 +0400)
committerAndrey Volk <andywolk@gmail.com>
Tue, 16 Mar 2021 17:41:32 +0000 (20:41 +0300)
src/switch_odbc.c

index 31161ee1589f2211b57255534324385c98cc0a2c..9ea062d9970bbf6cf8261e436e7ad83b47b3da08 100644 (file)
@@ -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);