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