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