Line data Source code
1 : #include "common.h"
2 :
3 : /* test RAISERROR in a store procedure, from Tom Rogers tests */
4 :
5 : /* TODO add support for Sybase */
6 :
7 : #define SP_TEXT "{?=call #tmp1(?,?,?)}"
8 : #define OUTSTRING_LEN 20
9 : #define INVALID_RETURN (-12345)
10 :
11 : static const char create_proc[] =
12 : "CREATE PROCEDURE #tmp1\n"
13 : " @InParam int,\n"
14 : " @OutParam int OUTPUT,\n"
15 : " @OutString varchar(20) OUTPUT\n"
16 : "AS\n"
17 : "%s"
18 : " SET @OutParam = @InParam\n"
19 : " SET @OutString = 'This is bogus!'\n"
20 : " SELECT 'Here is the first row' AS FirstResult\n"
21 : " RAISERROR('An error occurred.', @InParam, 1)\n"
22 : "%s"
23 : " RETURN (0)";
24 :
25 : static SQLSMALLINT ReturnCode;
26 : static char OutString[OUTSTRING_LEN];
27 : static int g_nocount, g_second_select;
28 :
29 : #ifdef TDS_NO_DM
30 : static const int tds_no_dm = 1;
31 : #else
32 : static const int tds_no_dm = 0;
33 : #endif
34 :
35 : static void
36 142 : TestResult(SQLRETURN result0, int level, const char *func)
37 : {
38 142 : ODBC_BUF *odbc_buf = NULL;
39 : SQLTCHAR SqlState[6];
40 : SQLINTEGER NativeError;
41 : SQLTCHAR MessageText[1000];
42 : SQLSMALLINT TextLength;
43 142 : SQLRETURN result = result0, rc;
44 :
45 142 : if (result == SQL_NO_DATA && strcmp(func, "SQLFetch") == 0)
46 12 : result = SQL_SUCCESS_WITH_INFO;
47 :
48 142 : if ((level <= 10 && result != SQL_SUCCESS_WITH_INFO) || (level > 10 && result != SQL_ERROR) || ReturnCode != INVALID_RETURN) {
49 0 : fprintf(stderr, "%s failed!\n", func);
50 0 : exit(1);
51 : }
52 :
53 : /*
54 : * unixODBC till 2.2.11 do not support getting error if SQL_NO_DATA
55 : */
56 : if (!tds_no_dm && result0 == SQL_NO_DATA && strcmp(func, "SQLFetch") == 0)
57 : return;
58 :
59 142 : SqlState[0] = 0;
60 142 : MessageText[0] = 0;
61 142 : NativeError = 0;
62 142 : rc = CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, SqlState, &NativeError, MessageText, TDS_VECTOR_SIZE(MessageText), &TextLength, "SI");
63 142 : printf("Func=%s Result=%d DIAG REC 1: State=%s Error=%d: %s\n", func, (int) rc, C(SqlState), (int) NativeError, C(MessageText));
64 :
65 142 : if (strstr(C(MessageText), "An error occurred") == NULL) {
66 0 : fprintf(stderr, "Wrong error returned!\n");
67 0 : fprintf(stderr, "Error returned: %s\n", C(MessageText));
68 0 : exit(1);
69 : }
70 142 : ODBC_FREE();
71 : }
72 :
73 : #define MY_ERROR(msg) odbc_report_error(msg, line, __FILE__)
74 :
75 : static void
76 408 : CheckData(const char *s, int line)
77 : {
78 : char buf[80];
79 : SQLLEN ind;
80 : SQLRETURN rc;
81 :
82 408 : rc = CHKGetData(1, SQL_C_CHAR, buf, sizeof(buf), &ind, "SE");
83 :
84 408 : if (rc == SQL_ERROR) {
85 288 : buf[0] = 0;
86 288 : ind = 0;
87 : }
88 :
89 408 : if (strlen(s) != ind || strcmp(buf, s) != 0)
90 0 : MY_ERROR("Invalid result");
91 408 : }
92 :
93 : #define CheckData(s) CheckData(s, __LINE__)
94 :
95 : static void
96 190 : CheckReturnCode(SQLRETURN result, SQLSMALLINT expected, int line)
97 : {
98 190 : if (ReturnCode == expected && (expected != INVALID_RETURN || strcmp(OutString, "Invalid!") == 0)
99 190 : && (expected == INVALID_RETURN || strcmp(OutString, "This is bogus!") == 0))
100 : return;
101 :
102 0 : printf("SpDateTest Output:\n");
103 0 : printf(" Result = %d\n", (int) result);
104 0 : printf(" Return Code = %d\n", (int) ReturnCode);
105 0 : printf(" OutString = \"%s\"\n", OutString);
106 0 : MY_ERROR("Invalid ReturnCode");
107 : }
108 :
109 : #define CheckReturnCode(res, exp) CheckReturnCode(res, exp, __LINE__)
110 :
111 : static void
112 72 : Test(int level)
113 : {
114 : SQLRETURN result;
115 72 : SQLSMALLINT InParam = level;
116 72 : SQLSMALLINT OutParam = 1;
117 72 : SQLLEN cbReturnCode = 0, cbInParam = 0, cbOutParam = 0;
118 72 : SQLLEN cbOutString = SQL_NTS;
119 :
120 : char sql[80];
121 :
122 144 : printf("ODBC %d nocount %s select %s level %d\n", odbc_use_version3 ? 3 : 2,
123 144 : g_nocount ? "yes" : "no", g_second_select ? "yes" : "no", level);
124 :
125 72 : ReturnCode = INVALID_RETURN;
126 72 : memset(&OutString, 0, sizeof(OutString));
127 :
128 : /* test with SQLExecDirect */
129 72 : sprintf(sql, "RAISERROR('An error occurred.', %d, 1)", level);
130 72 : result = odbc_command_with_result(odbc_stmt, sql);
131 :
132 72 : TestResult(result, level, "SQLExecDirect");
133 :
134 : /* test with SQLPrepare/SQLExecute */
135 72 : if (!SQL_SUCCEEDED(SQLPrepare(odbc_stmt, T(SP_TEXT), strlen(SP_TEXT)))) {
136 0 : fprintf(stderr, "SQLPrepare failure!\n");
137 0 : exit(1);
138 : }
139 :
140 72 : SQLBindParameter(odbc_stmt, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &ReturnCode, 0, &cbReturnCode);
141 72 : SQLBindParameter(odbc_stmt, 2, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &InParam, 0, &cbInParam);
142 72 : SQLBindParameter(odbc_stmt, 3, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &OutParam, 0, &cbOutParam);
143 72 : strcpy(OutString, "Invalid!");
144 72 : SQLBindParameter(odbc_stmt, 4, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, OUTSTRING_LEN, 0, OutString, OUTSTRING_LEN,
145 : &cbOutString);
146 :
147 72 : CHKExecute("S");
148 :
149 : /* first select, check data are returned.
150 : * SET statements before does not affect results
151 : */
152 72 : CheckData("");
153 72 : CHKFetch("S");
154 72 : CheckData("Here is the first row");
155 :
156 72 : result = SQLFetch(odbc_stmt);
157 72 : if (odbc_use_version3) {
158 : SQLTCHAR SqlState[6];
159 : SQLINTEGER NativeError;
160 : SQLTCHAR MessageText[1000];
161 : SQLSMALLINT TextLength;
162 : SQLRETURN expected;
163 : SQLLEN rows;
164 :
165 48 : if (result != SQL_NO_DATA)
166 0 : ODBC_REPORT_ERROR("SQLFetch should return NO DATA");
167 48 : CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, SqlState, &NativeError, MessageText,
168 : TDS_VECTOR_SIZE(MessageText), &TextLength, "No");
169 48 : result = SQLMoreResults(odbc_stmt);
170 48 : expected = level > 10 ? SQL_ERROR : SQL_SUCCESS_WITH_INFO;
171 48 : if (result != expected)
172 0 : ODBC_REPORT_ERROR("SQLMoreResults returned unexpected result");
173 48 : if (!g_second_select && g_nocount) {
174 12 : if (ReturnCode == INVALID_RETURN) {
175 2 : result = SQLMoreResults(odbc_stmt);
176 : } else {
177 10 : CheckReturnCode(result, 0);
178 10 : ReturnCode = INVALID_RETURN;
179 10 : TestResult(result, level, "SQLMoreResults");
180 10 : ReturnCode = 0;
181 : }
182 : } else {
183 36 : TestResult(result, level, "SQLMoreResults");
184 : }
185 :
186 : /* a recordset with only warnings/errors do not contains rows */
187 48 : if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1)
188 0 : ODBC_REPORT_ERROR("SQLRowCount returned some rows");
189 : } else {
190 : /* in ODBC 2 errors/warnings are not handled as different recordset */
191 24 : TestResult(result, level, "SQLFetch");
192 : }
193 :
194 72 : if (odbc_driver_is_freetds())
195 72 : CheckData("");
196 :
197 72 : if (!g_second_select) {
198 : SQLLEN rows;
199 :
200 24 : if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1)
201 0 : ODBC_REPORT_ERROR("SQLRowCount returned some rows");
202 24 : CheckReturnCode(result, g_nocount ? 0 : INVALID_RETURN);
203 :
204 24 : result = SQLMoreResults(odbc_stmt);
205 : #ifdef ENABLE_DEVELOPING
206 : if (result != SQL_NO_DATA)
207 : ODBC_REPORT_ERROR("SQLMoreResults should return NO DATA");
208 :
209 : ODBC_CHECK_ROWS(-2);
210 : #endif
211 24 : CheckReturnCode(result, 0);
212 : return;
213 : }
214 :
215 48 : if (!odbc_use_version3 || !g_nocount) {
216 : /* mssql 2008 return SUCCESS_WITH_INFO with previous error */
217 36 : CHKMoreResults("S");
218 36 : result = SQL_SUCCESS;
219 : }
220 :
221 48 : CheckReturnCode(result, INVALID_RETURN);
222 :
223 48 : CheckData("");
224 48 : if (g_nocount && odbc_use_version3 && g_second_select && level >= 10) {
225 6 : if (CHKFetch("SE") == SQL_ERROR) {
226 2 : SQLMoreResults(odbc_stmt);
227 2 : CHKFetch("S");
228 : }
229 : } else {
230 42 : CHKFetch("S");
231 : }
232 48 : CheckData("Here is the last row");
233 :
234 48 : CHKFetch("No");
235 48 : CheckData("");
236 :
237 48 : if (!odbc_use_version3 || g_nocount)
238 36 : CheckReturnCode(result, 0);
239 : #ifdef ENABLE_DEVELOPING
240 : else
241 : CheckReturnCode(result, INVALID_RETURN);
242 : #endif
243 :
244 : /* FIXME how to handle return in store procedure ?? */
245 48 : result = SQLMoreResults(odbc_stmt);
246 : #ifdef ENABLE_DEVELOPING
247 : if (result != SQL_NO_DATA)
248 : ODBC_REPORT_ERROR("SQLMoreResults return other data");
249 : #endif
250 :
251 48 : CheckReturnCode(result, 0);
252 :
253 48 : CheckData("");
254 48 : ODBC_FREE();
255 : }
256 :
257 : static void
258 48 : Test2(int nocount, int second_select)
259 : {
260 : char sql[512];
261 :
262 48 : g_nocount = nocount;
263 48 : g_second_select = second_select;
264 :
265 : /* this test do not work with Sybase */
266 48 : if (!odbc_db_is_microsoft())
267 12 : return;
268 :
269 36 : sprintf(sql, create_proc, nocount ? " SET NOCOUNT ON\n" : "",
270 : second_select ? " SELECT 'Here is the last row' AS LastResult\n" : "");
271 36 : odbc_command(sql);
272 :
273 36 : Test(5);
274 :
275 36 : Test(11);
276 :
277 36 : odbc_command("DROP PROC #tmp1");
278 : }
279 :
280 : int
281 8 : main(int argc, char *argv[])
282 : {
283 8 : odbc_connect();
284 :
285 8 : Test2(0, 1);
286 :
287 8 : Test2(1, 1);
288 :
289 8 : odbc_disconnect();
290 :
291 8 : odbc_use_version3 = 1;
292 :
293 8 : odbc_connect();
294 :
295 8 : Test2(0, 1);
296 8 : Test2(1, 1);
297 :
298 8 : Test2(0, 0);
299 8 : Test2(1, 0);
300 :
301 8 : odbc_disconnect();
302 :
303 8 : printf("Done.\n");
304 : return 0;
305 : }
|