LCOV - code coverage report
Current view: top level - src/ctlib/unittests - row_count.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 58 84 69.0 %
Date: 2025-05-08 08:17:26 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Tests rows count
       3             :  *
       4             :  * These are the results using Sybase CT-Library. This test check that ct_results returns the same results.
       5             :  *
       6             :  *
       7             :  *                      "insert into #tmp1 values(1) "
       8             :  *                      "insert into #tmp1 values(2) "
       9             :  *                      "insert into #tmp1 values(3) "
      10             :  *                      "select * from #tmp1 "
      11             :  *
      12             :  * Open Client Message:
      13             :  * number 16843050 layer 1 origin 1 severity 1 number 42
      14             :  * msgstring: ct_res_info(ROWCOUNT): user api layer: external error: This routine cannot be called after ct_results() returns a result type of CS_ROW_RESULT.
      15             :  * osstring: (null)
      16             :  * ct_results returned CS_ROW_RESULT type and -1 rows
      17             :  * All done processing rows.
      18             :  * ct_results returned CS_CMD_DONE type and 3 rows
      19             :  *
      20             :  * Open Client Message:
      21             :  * number 16843051 layer 1 origin 1 severity 1 number 43
      22             :  * msgstring: ct_res_info(ROWCOUNT): user api layer: external error: This routine cannot be called after ct_results() returns a result type of CS_STATUS_RESULT.
      23             :  * osstring: (null)
      24             :  * ct_results returned CS_STATUS_RESULT type and -1 rows
      25             :  * All done processing rows.
      26             :  * ct_results returned CS_CMD_SUCCEED type and -1 rows
      27             :  * ct_results returned CS_CMD_DONE type and -1 rows
      28             :  *
      29             :  *
      30             :  *                      "insert into #tmp1 values(1) "
      31             :  *                      "insert into #tmp1 values(2) "
      32             :  *                      "insert into #tmp1 values(3) "
      33             :  *                      "select * from #tmp1 "
      34             :  *                      "insert into #tmp1 values(4) "
      35             :  *                      "delete from #tmp1 where i <= 2 "
      36             :  *
      37             :  * Open Client Message:
      38             :  * number 16843050 layer 1 origin 1 severity 1 number 42
      39             :  * msgstring: ct_res_info(ROWCOUNT): user api layer: external error: This routine cannot be called after ct_results() returns a result type of CS_ROW_RESULT.
      40             :  * osstring: (null)
      41             :  * ct_results returned CS_ROW_RESULT type and -1 rows
      42             :  * All done processing rows.
      43             :  * ct_results returned CS_CMD_DONE type and 3 rows
      44             :  *
      45             :  * Open Client Message:
      46             :  * number 16843051 layer 1 origin 1 severity 1 number 43
      47             :  * msgstring: ct_res_info(ROWCOUNT): user api layer: external error: This routine cannot be called after ct_results() returns a result type of CS_STATUS_RESULT.
      48             :  * osstring: (null)
      49             :  * ct_results returned CS_STATUS_RESULT type and -1 rows
      50             :  * All done processing rows.
      51             :  * ct_results returned CS_CMD_SUCCEED type and 2 rows
      52             :  * ct_results returned CS_CMD_DONE type and 2 rows
      53             :  */
      54             : 
      55             : #include "common.h"
      56             : 
      57             : #include <freetds/replacements.h>
      58             : 
      59             : static CS_CONTEXT *ctx;
      60             : static CS_CONNECTION *conn;
      61             : static CS_COMMAND *cmd;
      62             : 
      63             : static CS_INT ex_display_results(CS_COMMAND * cmd, char *results);
      64             : 
      65             : static int test(int final_rows, int no_rows);
      66             : 
      67          10 : TEST_MAIN()
      68             : {
      69          10 :         printf("%s: check row count returned\n", __FILE__);
      70          10 :         check_call(try_ctlogin, (&ctx, &conn, &cmd, 0));
      71          10 :         error_to_stdout = true;
      72             : 
      73             :         /* do not test error */
      74          10 :         run_command(cmd, "DROP PROCEDURE sample_rpc");
      75          10 :         run_command(cmd, "drop table #tmp1");
      76             : 
      77             :         /* test with rows from select */
      78          10 :         if (test(0, 0) || test(1, 0))
      79             :                 return 1;
      80             : 
      81             :         /* test with empty select */
      82          10 :         if (test(0, 1) || test(1, 1))
      83             :                 return 1;
      84             : 
      85          10 :         check_call(try_ctlogout, (ctx, conn, cmd, 0));
      86             : 
      87          10 :         return 0;
      88             : }
      89             : 
      90             : static int
      91          40 : test(int final_rows, int no_rows)
      92             : {
      93             :         CS_CHAR cmdbuf[4096];
      94             :         char results[1024];
      95             : 
      96          40 :         run_command(cmd, "create table #tmp1 (i int not null)");
      97             : 
      98          40 :         strlcpy(cmdbuf, "create proc sample_rpc as ", sizeof(cmdbuf));
      99             : 
     100          40 :         strlcpy(results, "CS_ROW_RESULT -1\n", sizeof(results));
     101          40 :         strlcat(cmdbuf, "insert into #tmp1 values(1) "
     102             :                         "insert into #tmp1 values(2) "
     103             :                         "insert into #tmp1 values(3) ", sizeof(cmdbuf)
     104             :         );
     105             : 
     106          40 :         if (no_rows) {
     107          20 :                 strlcat(cmdbuf,  "select * from #tmp1 where i > 10 ",
     108             :                         sizeof(cmdbuf));
     109          20 :                 strlcat(results, "CS_CMD_DONE 0\n", sizeof(results));
     110             :         } else {
     111          20 :                 strlcat(cmdbuf,  "select * from #tmp1 ", sizeof(cmdbuf));
     112          20 :                 strlcat(results, "CS_CMD_DONE 3\n", sizeof(results));
     113             :         }
     114             : 
     115          40 :         strlcat(results, "CS_STATUS_RESULT -1\n", sizeof(results));
     116             : 
     117          40 :         if (final_rows) {
     118          20 :                 strlcat(cmdbuf,  "insert into #tmp1 values(4) "
     119             :                                  "delete from #tmp1 where i <= 2 ",
     120             :                         sizeof(cmdbuf)
     121             :                 );
     122          20 :                 strlcat(results, "CS_CMD_SUCCEED 2\n"
     123             :                                  "CS_CMD_DONE 2\n", sizeof(results));
     124             :         } else {
     125          20 :                 strlcat(results, "CS_CMD_SUCCEED -1\n"
     126             :                                 "CS_CMD_DONE -1\n", sizeof(results));
     127             :         }
     128             : 
     129          40 :         printf("testing query:\n----\n%s\n----\n", cmdbuf);
     130             : 
     131          40 :         check_call(run_command, (cmd, cmdbuf));
     132             : 
     133          40 :         printf("----------\n");
     134          40 :         check_call(ct_command, (cmd, CS_RPC_CMD, "sample_rpc", CS_NULLTERM, CS_NO_RECOMPILE));
     135             : 
     136          40 :         check_call(ct_send, (cmd));
     137          40 :         ex_display_results(cmd, results);
     138             : 
     139             :         /* cleanup */
     140          40 :         run_command(cmd, "DROP PROCEDURE sample_rpc");
     141          40 :         run_command(cmd, "drop table #tmp1");
     142             : 
     143          40 :         return 0;
     144             : }
     145             : 
     146             : static CS_INT
     147          40 : ex_display_results(CS_COMMAND * cmd, char *results)
     148             : {
     149             :         CS_RETCODE ret;
     150             :         CS_INT res_type;
     151             :         CS_INT num_cols;
     152          40 :         CS_INT row_count = 0;
     153             :         CS_INT rows_read;
     154             :         CS_SMALLINT msg_id;
     155             : 
     156             :         /*
     157             :          * Process the results of the RPC.
     158             :          */
     159         280 :         while ((ret = ct_results(cmd, &res_type)) == CS_SUCCEED) {
     160             :                 char res[32];
     161             :                 int rows, pos;
     162             : 
     163         200 :                 CS_INT rowsAffected = -1;
     164         200 :                 ct_res_info(cmd, CS_ROW_COUNT, &rowsAffected, CS_UNUSED, NULL);
     165         200 :                 printf("ct_results returned %s type and %d rows\n", res_type_str(res_type), (int) rowsAffected);
     166             : 
     167             :                 /* check expected results are the same as got ones */
     168         200 :                 pos = -1;
     169         200 :                 assert(sscanf(results, "%30s %d %n", res, &rows, &pos) >= 2 && pos > 0);
     170         200 :                 results += pos;
     171         200 :                 if (strcmp(res_type_str(res_type), res) != 0 || rowsAffected != rows) {
     172           0 :                         fprintf(stderr, "Expected ct_results %s rows %d\n", res, rows);
     173           0 :                         exit(1);
     174             :                 }
     175             : 
     176         200 :                 switch (res_type) {
     177          80 :                 case CS_ROW_RESULT:
     178             :                 case CS_PARAM_RESULT:
     179             :                 case CS_STATUS_RESULT:
     180             : 
     181             :                         /*
     182             :                          * All three of these result types are fetchable.
     183             :                          * Since the result model for rpcs and rows have
     184             :                          * been unified in the New Client-Library, we
     185             :                          * will use the same routine to display them
     186             :                          */
     187             : 
     188             :                         /*
     189             :                          * Find out how many columns there are in this result set.
     190             :                          */
     191          80 :                         check_call(ct_res_info, (cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL));
     192             : 
     193             :                         /*
     194             :                          * Make sure we have at least one column
     195             :                          */
     196          80 :                         if (num_cols <= 0) {
     197           0 :                                 fprintf(stderr, "ct_res_info(CS_NUMDATA) returned zero columns");
     198           0 :                                 return 1;
     199             :                         }
     200             : 
     201         180 :                         while (((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED,
     202          80 :                                                 &rows_read)) == CS_SUCCEED) || (ret == CS_ROW_FAIL)) {
     203             :                                 /*
     204             :                                  * Increment our row count by the number of rows just fetched.
     205             :                                  */
     206         100 :                                 row_count = row_count + rows_read;
     207             : 
     208             :                                 /*
     209             :                                  * Check if we hit a recoverable error.
     210             :                                  */
     211         100 :                                 if (ret == CS_ROW_FAIL) {
     212           0 :                                         printf("Error on row %d.\n", row_count);
     213           0 :                                         fflush(stdout);
     214             :                                 }
     215             :                         }
     216             : 
     217             :                         /*
     218             :                          * We're done processing rows.  Let's check the final return
     219             :                          * value of ct_fetch().
     220             :                          */
     221          80 :                         switch ((int) ret) {
     222          80 :                         case CS_END_DATA:
     223             :                                 /*
     224             :                                  * Everything went fine.
     225             :                                  */
     226          80 :                                 printf("All done processing rows.\n");
     227          80 :                                 fflush(stdout);
     228             :                                 break;
     229             : 
     230           0 :                         case CS_FAIL:
     231             :                                 /*
     232             :                                  * Something terrible happened.
     233             :                                  */
     234           0 :                                 fprintf(stderr, "ct_fetch returned CS_FAIL\n");
     235           0 :                                 return 1;
     236             :                                 break;
     237             : 
     238           0 :                         default:
     239             :                                 /*
     240             :                                  * We got an unexpected return value.
     241             :                                  */
     242           0 :                                 fprintf(stderr, "ct_fetch returned %d\n", ret);
     243           0 :                                 return 1;
     244             :                                 break;
     245             : 
     246             :                         }
     247          80 :                         break;
     248             : 
     249           0 :                 case CS_MSG_RESULT:
     250           0 :                         check_call(ct_res_info, (cmd, CS_MSGTYPE, (CS_VOID *) & msg_id, CS_UNUSED, NULL));
     251           0 :                         printf("ct_result returned CS_MSG_RESULT where msg id = %d.\n", msg_id);
     252           0 :                         fflush(stdout);
     253           0 :                         break;
     254             : 
     255             :                 case CS_CMD_SUCCEED:
     256             :                 case CS_CMD_DONE:
     257             :                 case CS_CMD_FAIL:
     258             :                         break;
     259             : 
     260           0 :                 default:
     261             :                         /*
     262             :                          * We got something unexpected.
     263             :                          */
     264           0 :                         fprintf(stderr, "ct_results returned unexpected result type.");
     265           0 :                         return CS_FAIL;
     266             :                 }
     267             :         }
     268             : 
     269             :         /*
     270             :          * We're done processing results. Let's check the
     271             :          * return value of ct_results() to see if everything
     272             :          * went ok.
     273             :          */
     274          40 :         switch ((int) ret) {
     275             :         case CS_END_RESULTS:
     276             :                 /*
     277             :                  * Everything went fine.
     278             :                  */
     279             :                 break;
     280             : 
     281           0 :         case CS_FAIL:
     282             :                 /*
     283             :                  * Something failed happened.
     284             :                  */
     285           0 :                 fprintf(stderr, "ct_results failed.");
     286           0 :                 break;
     287             : 
     288           0 :         default:
     289             :                 /*
     290             :                  * We got an unexpected return value.
     291             :                  */
     292           0 :                 fprintf(stderr, "ct_results returned unexpected result type.");
     293           0 :                 break;
     294             :         }
     295             : 
     296             :         return CS_SUCCEED;
     297             : }

Generated by: LCOV version 1.13