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
|