1 #include "common.h"
2 
3 /* Test for {?=call store(?)} syntax and run */
4 
5 static void test_with_conversions(void);
6 static void test_with_dbname(void);
7 
8 int
main(int argc,char * argv[])9 main(int argc, char *argv[])
10 {
11 	SQLINTEGER input, output;
12 	SQLLEN ind, ind2, ind3, ind4;
13 	SQLINTEGER out1;
14 	char out2[30];
15 
16 	odbc_connect();
17 
18 	odbc_command("IF OBJECT_ID('simpleresult') IS NOT NULL DROP PROC simpleresult");
19 
20 	odbc_command("create proc simpleresult @i int as begin return @i end");
21 
22 	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &input, 0, &ind2, "S");
23 	CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
24 
25 	CHKPrepare(T("{ \n?\t\r= call simpleresult(?)}"), SQL_NTS, "S");
26 
27 	input = 123;
28 	ind2 = sizeof(input);
29 	output = 0xdeadbeef;
30 	CHKExecute("S");
31 
32 	if (output != 123) {
33 		printf("Invalid result\n");
34 		exit(1);
35 	}
36 
37 	/* should return "Invalid cursor state" */
38 	if (SQLFetch(odbc_stmt) != SQL_ERROR) {
39 		printf("Data not expected\n");
40 		exit(1);
41 	}
42 	ODBC_CHECK_COLS(0);
43 
44 	/* just to reset some possible buffers */
45 	odbc_command("DECLARE @i INT");
46 
47 	/* same test but with SQLExecDirect and same bindings */
48 	input = 567;
49 	ind2 = sizeof(input);
50 	output = 0xdeadbeef;
51 	CHKExecDirect(T("{?=call simpleresult(?)}"), SQL_NTS, "S");
52 
53 	if (output != 567) {
54 		fprintf(stderr, "Invalid result\n");
55 		exit(1);
56 	}
57 
58 	/* should return "Invalid cursor state" */
59 	CHKFetch("E");
60 
61 	odbc_command("drop proc simpleresult");
62 
63 	odbc_command("IF OBJECT_ID('simpleresult2') IS NOT NULL DROP PROC simpleresult2");
64 
65 	/* force cursor close */
66 	SQLCloseCursor(odbc_stmt);
67 
68 	/* test output parameter */
69 	odbc_command("create proc simpleresult2 @i int, @x int output, @y varchar(20) output as begin select @x = 6789 select @y = 'test foo' return @i end");
70 
71 	CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0,  0, &output, 0,            &ind,  "S");
72 	CHKBindParameter(2, SQL_PARAM_INPUT,  SQL_C_SLONG, SQL_INTEGER, 0,  0, &input,  0,            &ind2, "S");
73 	CHKBindParameter(3, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0,  0, &out1,   0,            &ind3, "S");
74 	CHKBindParameter(4, SQL_PARAM_OUTPUT, SQL_C_CHAR,  SQL_VARCHAR, 20, 0, out2,    sizeof(out2), &ind4, "S");
75 
76 	CHKPrepare(T("{ \n?\t\r= call simpleresult2(?,?,?)}"), SQL_NTS, "S");
77 
78 	input = 987;
79 	ind2 = sizeof(input);
80 	out1 = 888;
81 	output = 0xdeadbeef;
82 	ind3 = SQL_DATA_AT_EXEC;
83 	ind4 = SQL_DEFAULT_PARAM;
84 	strcpy(out2, "bad!");
85 	CHKExecute("S");
86 
87 	if (output != 987 || ind3 <= 0 || ind4 <= 0 || out1 != 6789 || strcmp(out2, "test foo") != 0) {
88 		printf("ouput = %d ind3 = %d ind4 = %d out1 = %d out2 = %s\n", (int) output, (int) ind3, (int) ind4, (int) out1,
89 		       out2);
90 		printf("Invalid result\n");
91 		exit(1);
92 	}
93 
94 	/* should return "Invalid cursor state" */
95 	CHKFetch("E");
96 
97 	ODBC_CHECK_COLS(0);
98 
99 	odbc_command("drop proc simpleresult2");
100 
101 	/*
102 	 * test from shiv kumar
103 	 * Cfr ML 2006-11-21 "specifying a 0 for the StrLen_or_IndPtr in the
104 	 * SQLBindParameter call is not working on AIX"
105 	 */
106 	odbc_command("IF OBJECT_ID('rpc_read') IS NOT NULL DROP PROC rpc_read");
107 
108 	odbc_reset_statement();
109 
110 	odbc_command("create proc rpc_read @i int, @x timestamp as begin select 1 return 1234 end");
111 	SQLCloseCursor(odbc_stmt);
112 
113 	CHKPrepare(T("{ ? = CALL rpc_read ( ?, ? ) }"), SQL_NTS, "S");
114 
115 	ind = 0;
116 	CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
117 
118 	ind2 = 0;
119 	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &input, 0, &ind2, "S");
120 
121 	ind3 = 8;
122 	CHKBindParameter(3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, 8, 0, out2, 8, &ind3, "S");
123 
124 	CHKExecute("S");
125 
126 	CHKFetch("S");
127 
128 	CHKFetch("No");
129 
130 	odbc_reset_statement();
131 	odbc_command("drop proc rpc_read");
132 
133 	/*
134 	 * Test from Joao Amaral
135 	 * This test SQLExecute where a store procedure returns no result
136 	 * This seems similar to a previous one but use set instead of select
137 	 * (with is supported only by mssql and do not return all stuff as
138 	 * select does)
139 	 */
140 	if (odbc_db_is_microsoft()) {
141 
142 		odbc_reset_statement();
143 
144 		odbc_command("IF OBJECT_ID('sp_test') IS NOT NULL DROP PROC sp_test");
145 		odbc_command("create proc sp_test @res int output as set @res = 456");
146 
147 		odbc_reset_statement();
148 
149 		CHKPrepare(T("{ call sp_test(?)}"), SQL_NTS, "S");
150 		CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
151 
152 		output = 0xdeadbeef;
153 		CHKExecute("S");
154 
155 		if (output != 456) {
156 			fprintf(stderr, "Invalid result %d(%x)\n", (int) output, (int) output);
157 			return 1;
158 		}
159 		odbc_command("drop proc sp_test");
160 	}
161 	odbc_disconnect();
162 
163 	if (odbc_db_is_microsoft()) {
164 		odbc_use_version3 = 1;
165 		odbc_connect();
166 
167 		test_with_conversions();
168 		test_with_dbname();
169 		odbc_disconnect();
170 	}
171 
172 	printf("Done.\n");
173 	return 0;
174 }
175 
176 static void
test_with_conversions(void)177 test_with_conversions(void)
178 {
179 	SQLLEN ind, ind2, ind3;
180 	char out2[30];
181 
182 	/*
183 	 * test from Bower, Wayne
184 	 * Cfr ML 2012-03-02 "[freetds] [unixODBC][Driver Manager]Function sequence error (SQL-HY010)"
185 	 */
186 	odbc_command("IF OBJECT_ID('TMP_SP_Test_ODBC') IS NOT NULL DROP PROC TMP_SP_Test_ODBC");
187 	odbc_command("create proc TMP_SP_Test_ODBC @i int,\n@o int output\nas\nset nocount on\nselect @o = 55\nreturn 9\n");
188 	odbc_reset_statement();
189 
190 	CHKPrepare(T("{ ? = call TMP_SP_Test_ODBC (?, ?) }"), SQL_NTS, "S");
191 
192 	ind2 = 2;
193 	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 80, 0, "10", 2, &ind2, "S");
194 	ind3 = SQL_NULL_DATA;
195 	strcpy(out2, " ");
196 	CHKBindParameter(3, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind3, "S");
197 	ind = 1;
198 	CHKBindParameter(1, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind, "S");
199 
200 	/* mssql returns SUCCESS */
201 	CHKExecute("No");
202 
203 	ODBC_CHECK_COLS(0);
204 
205 	odbc_reset_statement();
206 	odbc_command("drop proc TMP_SP_Test_ODBC");
207 }
208 
209 static void
test_with_dbname(void)210 test_with_dbname(void)
211 {
212 	SQLINTEGER len;
213 	SQLTCHAR out[512];
214 	char sql[1024];
215 	SQLINTEGER output;
216 	SQLLEN ind;
217 	ODBC_BUF *odbc_buf = NULL;
218 
219 	len = sizeof(out);
220 	CHKGetConnectAttr(SQL_ATTR_CURRENT_CATALOG, (SQLPOINTER) out, sizeof(out), &len, "SI");
221 
222 	odbc_command("IF OBJECT_ID('TMP_SP_Test_ODBC') IS NOT NULL DROP PROC TMP_SP_Test_ODBC");
223 	odbc_command("create proc TMP_SP_Test_ODBC @o int output\nas\nset @o=55\nreturn 3\n");
224 	odbc_reset_statement();
225 
226 	sprintf(sql, "{call [%s]..TMP_SP_Test_ODBC(?)}", C(out));
227 	CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S");
228 	CHKPrepare(T(sql), SQL_NTS, "S");
229 
230 	output = 123;
231 	ind = sizeof(output);
232 	CHKExecute("S");
233 
234 	if (output != 55) {
235 		printf("Invalid result\n");
236 		exit(1);
237 	}
238 
239 	odbc_reset_statement();
240 	odbc_command("drop proc TMP_SP_Test_ODBC");
241 	ODBC_FREE();
242 }
243