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

Generated by: LCOV version 1.13