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