LCOV - code coverage report
Current view: top level - src/odbc/unittests - qn.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 59 62 95.2 %
Date: 2026-07-19 14:02:14 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : #include <assert.h>
       4             : #include "odbcss.h"
       5             : #include <freetds/thread.h>
       6             : #include <freetds/replacements.h>
       7             : 
       8             : /* test query notifications */
       9             : 
      10             : #ifdef TDS_HAVE_MUTEX
      11             : #define SWAP(t,a,b) do { t xyz = a; a = b; b = xyz; } while(0)
      12             : #define SWAP_CONN() do { SWAP(HENV,env,odbc_env); SWAP(HDBC,dbc,odbc_conn); SWAP(HSTMT,stmt,odbc_stmt);} while(0)
      13             : 
      14             : static HENV env = SQL_NULL_HENV;
      15             : static HDBC dbc = SQL_NULL_HDBC;
      16             : static HSTMT stmt = SQL_NULL_HSTMT;
      17             : 
      18           4 : static TDS_THREAD_PROC_DECLARE(change_thread_proc, arg TDS_UNUSED)
      19             : {
      20           4 :         SQLHSTMT odbc_stmt = stmt;
      21             : 
      22           4 :         odbc_command("UPDATE ftds_test SET v = 'hi!'");
      23           4 :         CHKMoreResults("No");
      24           4 :         CHKMoreResults("SNo");
      25             : 
      26           4 :         return TDS_THREAD_RESULT(0);
      27             : }
      28             : 
      29          10 : TEST_MAIN()
      30             : {
      31          10 :         char *sql = NULL;
      32             :         tds_thread th;
      33             :         SQLSMALLINT cols, col;
      34             :         char message[1024];
      35             : 
      36          10 :         odbc_connect();
      37             : 
      38          10 :         if (!odbc_db_is_microsoft() || odbc_tds_version() < 0x702) {
      39           6 :                 odbc_disconnect();
      40           6 :                 printf("Query notifications available only using TDS 7.2 or newer\n");
      41           6 :                 odbc_test_skipped();
      42           0 :                 return 0;
      43             :         }
      44             : 
      45           4 :         sql = odbc_buf_asprintf(&odbc_buf, "ALTER DATABASE %s SET ENABLE_BROKER", common_pwd.database);
      46           4 :         odbc_command(sql);
      47             : 
      48           4 :         odbc_command2("DROP SERVICE FTDS_Service", "SENo");
      49           4 :         odbc_command2("DROP QUEUE FTDS_Queue", "SENo");
      50           4 :         odbc_command2("DROP TABLE ftds_test", "SENo");
      51             : 
      52           4 :         odbc_command("CREATE TABLE ftds_test(i int PRIMARY KEY, v varchar(100))");
      53           4 :         odbc_command("INSERT INTO ftds_test VALUES(1, 'hello')");
      54             : 
      55           4 :         odbc_command("CREATE QUEUE FTDS_Queue\n"
      56             :                      "CREATE SERVICE FTDS_Service ON QUEUE FTDS_Queue\n"
      57             :                      "([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]);");
      58             : 
      59             :         /* clear queue */
      60             :         for (;;) {
      61           4 :                 odbc_command("RECEIVE * FROM FTDS_Queue");
      62           4 :                 if (CHKFetch("SNo") == SQL_NO_DATA)
      63             :                         break;
      64           0 :                 CHKMoreResults("SNo");
      65           0 :                 CHKMoreResults("SNo");
      66             :         }
      67           4 :         odbc_reset_statement();
      68             : 
      69             :         /* connect another time for thread */
      70           4 :         SWAP_CONN();
      71           4 :         odbc_connect();
      72           4 :         SWAP_CONN();
      73             : 
      74           4 :         sql = odbc_buf_asprintf(&odbc_buf, "service=FTDS_Service;local database=%s", common_pwd.database);
      75           4 :         CHKSetStmtAttr(SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS, T(sql), SQL_NTS, "S");
      76           4 :         CHKSetStmtAttr(SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT, T("Table has changed"), SQL_NTS, "S");
      77           4 :         CHKSetStmtAttr(SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT, TDS_INT2PTR(60), SQL_IS_UINTEGER, "S");
      78             : 
      79           4 :         odbc_command("SELECT v FROM dbo.ftds_test");
      80             : 
      81           4 :         odbc_reset_statement();
      82             : 
      83             :         /* launch another thread to update the table we are looking to */
      84           4 :         assert(tds_thread_create(&th, change_thread_proc, NULL) == 0);
      85             : 
      86           4 :         odbc_command("WAITFOR (RECEIVE * FROM FTDS_Queue)");
      87             : 
      88           4 :         memset(message, 0, sizeof(message));
      89           4 :         CHKNumResultCols(&cols, "S");
      90          12 :         while (CHKFetch("SNo") == SQL_SUCCESS) {
      91          58 :                 for (col = 0; col < cols; ++col) {
      92             :                         char buf[1024];
      93             :                         SQLLEN len;
      94             :                         SQLTCHAR name[128];
      95             :                         SQLSMALLINT namelen, type, digits, nullable;
      96             :                         SQLULEN size;
      97             : 
      98          58 :                         CHKDescribeCol(col + 1, name, TDS_VECTOR_SIZE(name), &namelen, &type, &size, &digits, &nullable, "S");
      99          58 :                         if (col == 13) {
     100           4 :                                 CHKGetData(col + 1, SQL_C_BINARY, buf, sizeof(buf), &len, "S");
     101             :                         } else {
     102          54 :                                 CHKGetData(col + 1, SQL_C_CHAR, buf, sizeof(buf), &len, "S");
     103             :                         }
     104          58 :                         if (col == 13) {
     105             :                                 int i;
     106        1064 :                                 for (i = 2; i < len; i+= 2)
     107        1064 :                                         buf[i / 2 - 1] = buf[i];
     108           4 :                                 buf[len / 2 - 1] = 0;
     109           4 :                                 strcpy(message, buf);
     110             :                         }
     111          58 :                         printf("%s: %s\n", C(name), buf);
     112             :                 }
     113             :         }
     114             : 
     115           8 :         tds_thread_join(th, NULL);
     116             : 
     117           4 :         SWAP_CONN();
     118           4 :         odbc_disconnect();
     119           4 :         SWAP_CONN();
     120             : 
     121             :         /* cleanup */
     122           4 :         odbc_command2("DROP SERVICE FTDS_Service", "SENo");
     123           4 :         odbc_command2("DROP QUEUE FTDS_Queue", "SENo");
     124           4 :         odbc_command2("DROP TABLE ftds_test", "SENo");
     125             : 
     126           4 :         odbc_disconnect();
     127             : 
     128           4 :         assert(strstr(message, "Table has changed") != NULL);
     129           4 :         assert(strstr(message, "info=\"update\"") != NULL);
     130             : 
     131             :         return 0;
     132             : }
     133             : #else
     134             : TEST_MAIN()
     135             : {
     136             :         printf("Not possible for this platform.\n");
     137             :         odbc_test_skipped();
     138             :         return 0;
     139             : }
     140             : #endif

Generated by: LCOV version 1.13