Line data Source code
1 : #include "common.h"
2 :
3 : /* first MARS test, test 2 concurrent recordset */
4 :
5 : #define SET_STMT(n) do { \
6 : if (pcur_stmt != &n) { \
7 : if (pcur_stmt) *pcur_stmt = odbc_stmt; \
8 : pcur_stmt = &n; \
9 : odbc_stmt = *pcur_stmt; \
10 : } \
11 : } while(0)
12 :
13 : static void
14 2 : AutoCommit(int onoff)
15 : {
16 2 : CHKSetConnectAttr(SQL_ATTR_AUTOCOMMIT, TDS_INT2PTR(onoff), 0, "S");
17 2 : }
18 :
19 : static void
20 2 : EndTransaction(SQLSMALLINT type)
21 : {
22 2 : CHKEndTran(SQL_HANDLE_DBC, odbc_conn, type, "S");
23 2 : }
24 :
25 :
26 : static void
27 10 : my_attrs(void)
28 : {
29 10 : SQLSetConnectAttr(odbc_conn, 1224 /*SQL_COPT_SS_MARS_ENABLED*/, (SQLPOINTER) 1 /*SQL_MARS_ENABLED_YES*/, SQL_IS_UINTEGER);
30 10 : }
31 :
32 10 : TEST_MAIN()
33 : {
34 : /* adjust these parameters for memory leak testing */
35 : /* TODO a way for this test to detect memory leak here. */
36 10 : const int n_iterations = 20; /* E.g. 200000 */
37 10 : const int freq_parameterized = 2; /* set 1 to parameterize all, INT_MAX for none */
38 :
39 : SQLINTEGER len, out;
40 : int i, j;
41 : SQLHSTMT stmt1, stmt2;
42 10 : SQLHSTMT *pcur_stmt = NULL;
43 : SQLINTEGER bind1;
44 10 : char bind2[20] = "parameters";
45 :
46 10 : odbc_use_version3 = true;
47 10 : odbc_set_conn_attr = my_attrs;
48 10 : odbc_connect();
49 :
50 10 : stmt1 = odbc_stmt;
51 :
52 10 : out = 0;
53 10 : len = sizeof(out);
54 10 : CHKGetConnectAttr(1224, (SQLPOINTER) &out, sizeof(out), &len, "SE");
55 :
56 : /* test we really support MARS on this connection */
57 : /* TODO should out be correct ?? */
58 10 : printf("Following row can contain an error due to MARS detection (is expected)\n");
59 10 : if (!out || odbc_command2("BEGIN TRANSACTION", "SNoE") != SQL_ERROR) {
60 8 : printf("MARS not supported for this connection\n");
61 8 : odbc_disconnect();
62 8 : odbc_test_skipped();
63 0 : return 0;
64 : }
65 2 : odbc_read_error();
66 2 : if (!strstr(odbc_err, "MARS")) {
67 0 : fprintf(stderr, "Error message invalid \"%s\"\n", odbc_err);
68 0 : return 1;
69 : }
70 :
71 : /* create a test table with some data */
72 2 : odbc_command("create table #mars1 (n int, v varchar(100))");
73 122 : for (i = 0; i < 60; ++i) {
74 : char cmd[120], buf[80];
75 120 : memset(buf, 'a' + (i % 26), sizeof(buf));
76 120 : buf[i * 7 % 73] = 0;
77 120 : sprintf(cmd, "insert into #mars1 values(%d, '%s')", i, buf);
78 120 : odbc_command(cmd);
79 : }
80 :
81 : /* and another to avid locking problems */
82 2 : odbc_command("create table #mars2 (n int, v varchar(100))");
83 :
84 2 : AutoCommit(SQL_AUTOCOMMIT_OFF);
85 :
86 : /* try to do a select which return a lot of data (to test server didn't cache everything) */
87 2 : odbc_command("select a.n, b.n, c.n, a.v from #mars1 a, #mars1 b, #mars1 c order by a.n, b.n, c.n");
88 2 : CHKFetch("S");
89 :
90 2 : CHKAllocStmt(&stmt2, "S");
91 :
92 : /* Use a parameterized insert. This causes DONEINPROC to be returned by SQL Server,
93 : * leading to result_type==TDS_CMD_DONE when it's complete. Without the parameter,
94 : * result_type == TDS_DONE_RESULT.
95 : * And in odbc_SQLExecute(), it calls odbc_unlock_statement() for TDS_CMD_DONE, but
96 : * not for TDS_DONE_RESULT. (We don't know why...)
97 : * This means that the stmt->tds TDSSOCKET struct is completely freed after every
98 : * iteration of the insert if and only if it was a parameterized insert. So we need
99 : * to test both parameterized and non-parameterized inserts.
100 : */
101 2 : SQLBindParameter(stmt2, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &bind1, 0, NULL);
102 2 : SQLBindParameter(stmt2, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, &bind2, 20, NULL);
103 :
104 42 : for (i = 1; i <= n_iterations; ++i) {
105 40 : SET_STMT(stmt2);
106 :
107 : /* Test option - force reallocation of socket
108 : * odbc_reset_statement();
109 : */
110 40 : if (i % freq_parameterized == 0) {
111 20 : bind1 = i;
112 20 : odbc_command("@insert into #mars2 values(?, ?)");
113 : } else {
114 20 : odbc_command("@insert into #mars2 values(1, 'foo')");
115 : }
116 :
117 : /* Perform several fetches for each insert, so we also test continuing to draw
118 : * further packets of the fetch
119 : */
120 40 : SET_STMT(stmt1);
121 440 : for (j = 0; j < 10; ++j)
122 400 : CHKFetch("S");
123 : }
124 2 : printf("Performed %d inserts while fetching.\n", i - 1);
125 :
126 : /* reset statements */
127 2 : SET_STMT(stmt1);
128 2 : odbc_reset_statement();
129 2 : SET_STMT(stmt2);
130 2 : odbc_reset_statement();
131 :
132 : /* now to 2 select with prepare/execute */
133 2 : CHKPrepare(T("select a.n, b.n, a.v from #mars1 a, #mars1 b order by a.n, b.n"), SQL_NTS, "S");
134 2 : SET_STMT(stmt1);
135 2 : CHKPrepare(T("select a.n, b.n, a.v from #mars1 a, #mars1 b order by a.n desc, b.n"), SQL_NTS, "S");
136 2 : SET_STMT(stmt2);
137 2 : CHKExecute("S");
138 2 : SET_STMT(stmt1);
139 2 : CHKExecute("S");
140 2 : SET_STMT(stmt2);
141 2 : CHKFetch("S");
142 2 : SET_STMT(stmt1);
143 2 : CHKFetch("S");
144 2 : SET_STMT(stmt2);
145 2 : CHKFetch("S");
146 2 : odbc_reset_statement();
147 2 : SET_STMT(stmt1);
148 2 : CHKFetch("S");
149 2 : odbc_reset_statement();
150 :
151 2 : EndTransaction(SQL_COMMIT);
152 :
153 2 : odbc_disconnect();
154 2 : return 0;
155 : }
156 :
|