LCOV - code coverage report
Current view: top level - src/odbc/unittests - array.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 82 102 80.4 %
Date: 2025-01-18 12:13:41 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : #include <assert.h>
       3             : 
       4             : /* Test using array binding */
       5             : 
       6             : static SQLTCHAR *test_query = NULL;
       7             : static int multiply = 90;
       8             : static int failure = 0;
       9             : 
      10             : #define XMALLOC_N(t, n) (t*) ODBC_GET(n*sizeof(t))
      11             : 
      12             : static void
      13          62 : query_test(int prepare, SQLRETURN expected, const char *expected_status)
      14             : {
      15             : #define DESC_LEN 51
      16             : #define ARRAY_SIZE 10
      17             : 
      18          62 :         SQLUINTEGER *ids = XMALLOC_N(SQLUINTEGER,ARRAY_SIZE);
      19             :         typedef SQLCHAR desc_t[DESC_LEN];
      20          62 :         desc_t *descs = XMALLOC_N(desc_t, ARRAY_SIZE);
      21          62 :         SQLLEN *id_lens = XMALLOC_N(SQLLEN,ARRAY_SIZE), *desc_lens = XMALLOC_N(SQLLEN,ARRAY_SIZE);
      22          62 :         SQLUSMALLINT i, *statuses = XMALLOC_N(SQLUSMALLINT,ARRAY_SIZE);
      23          62 :         unsigned *num_errors = XMALLOC_N(unsigned, ARRAY_SIZE);
      24             :         SQLULEN processed;
      25             :         RETCODE ret;
      26             :         char status[20];
      27          62 :         SQLTCHAR *err = (SQLTCHAR *) ODBC_GET(sizeof(odbc_err)*sizeof(SQLTCHAR));
      28          62 :         SQLTCHAR *state = (SQLTCHAR *) ODBC_GET(sizeof(odbc_sqlstate)*sizeof(SQLTCHAR));
      29             : 
      30          62 :         assert(odbc_stmt != SQL_NULL_HSTMT);
      31          62 :         odbc_reset_statement();
      32             : 
      33          62 :         odbc_command("create table #tmp1 (id tinyint, value char(20))");
      34             : 
      35          62 :         SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);
      36          62 :         SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAMSET_SIZE, (void *) ARRAY_SIZE, 0);
      37          62 :         SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAM_STATUS_PTR, statuses, 0);
      38          62 :         SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &processed, 0);
      39          62 :         SQLBindParameter(odbc_stmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0, ids, 0, id_lens);
      40          62 :         SQLBindParameter(odbc_stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, DESC_LEN - 1, 0, descs, DESC_LEN, desc_lens);
      41             : 
      42          62 :         processed = ARRAY_SIZE + 1;
      43         682 :         for (i = 0; i < ARRAY_SIZE; i++) {
      44         620 :                 statuses[i] = SQL_PARAM_DIAG_UNAVAILABLE;
      45         620 :                 ids[i] = (i + 1) * multiply;
      46         620 :                 sprintf((char *) descs[i], "data %d \xf4", i * 7);
      47         620 :                 id_lens[i] = 0;
      48         620 :                 desc_lens[i] = SQL_NTS;
      49         620 :                 num_errors[i] = 0;
      50             :         }
      51          62 :         multiply = 90;
      52             : 
      53          62 :         if (!prepare) {
      54          32 :                 ret = SQLExecDirect(odbc_stmt, test_query, SQL_NTS);
      55             :         } else {
      56          30 :                 SQLPrepare(odbc_stmt, test_query, SQL_NTS);
      57          30 :                 ret = SQLExecute(odbc_stmt);
      58             :         }
      59             : 
      60          62 :         if (processed > ARRAY_SIZE) {
      61             :                 char buf[256];
      62             : 
      63           0 :                 sprintf(buf, "Invalid processed number: %d", (int) processed);
      64           0 :                 ODBC_REPORT_ERROR(buf);
      65             :         }
      66             : 
      67         732 :         for (i = 1; CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, i, state, NULL, err, sizeof(odbc_err), NULL, "SINo") != SQL_NO_DATA; ++i) {
      68             :                 SQLINTEGER row;
      69             : 
      70         732 :                 strcpy(odbc_err, C(err));
      71         732 :                 strcpy(odbc_sqlstate, C(state));
      72         732 :                 CHKGetDiagField(SQL_HANDLE_STMT, odbc_stmt, i, SQL_DIAG_ROW_NUMBER, &row, sizeof(row), NULL, "S");
      73             : 
      74         732 :                 if (row == SQL_ROW_NUMBER_UNKNOWN) continue;
      75         732 :                 if (row < 1 || row > ARRAY_SIZE) {
      76           0 :                         fprintf(stderr, "invalid row %d returned reading error number %d\n", (int) row, i);
      77           0 :                         exit(1);
      78             :                 }
      79         732 :                 ++num_errors[row-1];
      80         732 :                 printf("for row %2d returned '%s' %s\n", (int) row, odbc_sqlstate, odbc_err);
      81             :         }
      82             : 
      83         620 :         for (i = 0; i < processed; ++i) {
      84         620 :                 int has_diag = 0;
      85             : 
      86         620 :                 switch (statuses[i]) {
      87             :                 case SQL_PARAM_SUCCESS_WITH_INFO:
      88           0 :                         has_diag = 1;
      89             :                 case SQL_PARAM_SUCCESS:
      90         254 :                         status[i] = 'V';
      91             :                         break;
      92             : 
      93         366 :                 case SQL_PARAM_ERROR:
      94         366 :                         has_diag = 1;
      95         366 :                         status[i] = '!';
      96             :                         break;
      97             : 
      98           0 :                 case SQL_PARAM_UNUSED:
      99           0 :                         status[i] = ' ';
     100             :                         break;
     101             : 
     102           0 :                 case SQL_PARAM_DIAG_UNAVAILABLE:
     103           0 :                         status[i] = '?';
     104             :                         break;
     105           0 :                 default:
     106           0 :                         fprintf(stderr, "Invalid status returned %d\n", statuses[i]);
     107           0 :                         exit(1);
     108             :                 }
     109             : 
     110             :                 if (has_diag) {
     111         366 :                         if (!num_errors[i]) {
     112           0 :                                 fprintf(stderr, "Diagnostics not returned for status %d\n", i);
     113           0 :                                 failure = 1;
     114             :                         }
     115             :                 } else {
     116         254 :                         if (num_errors[i]) {
     117           0 :                                 fprintf(stderr, "Diagnostics returned for status %d\n", i);
     118           0 :                                 failure = 1;
     119             :                         }
     120             :                 }
     121             :         }
     122          62 :         status[i] = 0;
     123             : 
     124          62 :         if (ret != expected || strcmp(expected_status, status) != 0) {
     125           0 :                 fprintf(stderr, "Invalid result: got %d \"%s\" expected %d \"%s\" processed %d\n",
     126             :                         ret, status, expected, expected_status, (int) processed);
     127           0 :                 if (ret != SQL_SUCCESS)
     128           0 :                         odbc_read_error();
     129           0 :                 failure = 1;
     130             :         }
     131             : 
     132          62 :         odbc_reset_statement();
     133             : 
     134          62 :         odbc_command_with_result(odbc_stmt, "drop table #tmp1");
     135          62 : }
     136             : 
     137             : int
     138           8 : main(int argc, char *argv[])
     139             : {
     140           8 :         odbc_use_version3 = 1;
     141           8 :         odbc_conn_additional_params = "ClientCharset=ISO-8859-1;";
     142           8 :         odbc_connect();
     143             : 
     144           8 :         if (odbc_db_is_microsoft()) {
     145             :                 /* all successes */
     146           6 :                 test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?, ?)");
     147           6 :                 multiply = 1;
     148           6 :                 query_test(0, SQL_SUCCESS, "VVVVVVVVVV");
     149           6 :                 multiply = 1;
     150           6 :                 query_test(1, SQL_SUCCESS, "VVVVVVVVVV");
     151             : 
     152             :                 /* all errors */
     153           6 :                 test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?, ?)");
     154           6 :                 multiply = 257;
     155           6 :                 query_test(0, SQL_ERROR, "!!!!!!!!!!");
     156           6 :                 multiply = 257;
     157           6 :                 query_test(1, SQL_SUCCESS_WITH_INFO, "!!!!!!!!!!");
     158             : 
     159           6 :                 test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?, ?)");
     160           6 :                 query_test(0, SQL_ERROR, "VV!!!!!!!!");
     161           6 :                 query_test(1, SQL_SUCCESS_WITH_INFO, "VV!!!!!!!!");
     162             : 
     163           6 :                 test_query = T("INSERT INTO #tmp1 (id, value) VALUES (900-?, ?)");
     164           6 :                 query_test(0, SQL_SUCCESS_WITH_INFO, "!!!!!!!VVV");
     165           6 :                 query_test(1, SQL_SUCCESS_WITH_INFO, "!!!!!!!VVV");
     166             : 
     167           6 :                 test_query = T("INSERT INTO #tmp1 (id) VALUES (?) UPDATE #tmp1 SET value = ?");
     168           6 :                 query_test(0, SQL_SUCCESS_WITH_INFO, "VVVV!V!V!V");
     169           6 :                 query_test(1, SQL_SUCCESS_WITH_INFO, "VV!!!!!!!!");
     170             : 
     171             : #ifdef ENABLE_DEVELOPING
     172             :                 /* with result, see how SQLMoreResult work */
     173             :                 test_query = T("INSERT INTO #tmp1 (id) VALUES (?) SELECT * FROM #tmp1 UPDATE #tmp1 SET value = ?");
     174             :                 /* IMHO our driver is better here -- freddy77 */
     175             :                 query_test(0, SQL_SUCCESS, odbc_driver_is_freetds() ? "VVVVV!V!V!" : "VVVVVV!VVV");
     176             :                 query_test(1, SQL_SUCCESS, "VVVVVVVVVV");
     177             : #endif
     178             :         } else {
     179             :                 /* Sybase test for conversions before executing */
     180           2 :                 test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?/8, ?)");
     181           2 :                 query_test(0, SQL_SUCCESS, "VVVVVVVVVV");
     182             :         }
     183             : 
     184             :         /* TODO record binding, array fetch, sqlputdata */
     185             : 
     186           8 :         odbc_disconnect();
     187             : 
     188           8 :         printf(failure ? "Failed :(\n" : "Success!\n");
     189           8 :         return failure;
     190             : }
     191             : 

Generated by: LCOV version 1.13