Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2003, 2004 Frediano Ziglio
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 : #include "common.h"
20 :
21 : #include <ctype.h>
22 : #include <assert.h>
23 :
24 : /* try conversion from utf8 to iso8859-1 */
25 :
26 : static TDSSOCKET *tds;
27 : static int g_result = 0;
28 : static int einval_error = 0;
29 : static int eilseq_error = 0;
30 : static int einval_count = 0;
31 : static int eilseq_count = 0;
32 : static int e2big_count = 0;
33 : static char test_name[128];
34 :
35 : static int invalid_char = -1;
36 :
37 : static void
38 3088 : test(int n, int type)
39 : {
40 : int rc;
41 : TDS_INT result_type;
42 : char buf[1024+128], tmp[1024];
43 : TDSCOLUMN *curcol;
44 : char *src;
45 : int done_flags;
46 : int i;
47 : char prefix[32], suffix[32];
48 :
49 3088 : sprintf(test_name, "test %d len %d", type, n);
50 :
51 : /* do a select and check all results */
52 3088 : prefix[0] = 0;
53 3088 : suffix[0] = 0;
54 3088 : tmp[0] = 0;
55 3088 : switch (type) {
56 1544 : case 0:
57 1544 : strcpy(suffix, "C280C290");
58 1544 : break;
59 1544 : case 1:
60 : /* try two invalid in different part */
61 1544 : strcpy(prefix, "C480C290");
62 1544 : strcpy(suffix, "C480C290");
63 1544 : break;
64 : }
65 :
66 296448 : for (i = 0; i < n; ++i)
67 296448 : sprintf(strchr(tmp, 0), "%02X", 0x30 + (i % 10));
68 3088 : sprintf(buf, "select convert(varchar(255), 0x%s%s%s)", prefix, tmp, suffix);
69 3088 : rc = tds_submit_query(tds, buf);
70 3088 : if (rc != TDS_SUCCESS) {
71 0 : fprintf(stderr, "tds_submit_query() failed\n");
72 0 : exit(1);
73 : }
74 :
75 3088 : if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
76 0 : fprintf(stderr, "tds_process_tokens() failed\n");
77 0 : exit(1);
78 : }
79 :
80 3088 : if (result_type != TDS_ROWFMT_RESULT) {
81 0 : fprintf(stderr, "expected row fmt() failed\n");
82 0 : exit(1);
83 : }
84 :
85 3088 : if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
86 0 : fprintf(stderr, "tds_process_tokens() failed\n");
87 0 : exit(1);
88 : }
89 :
90 3088 : if (result_type != TDS_ROW_RESULT) {
91 0 : fprintf(stderr, "expected row result() failed\n");
92 0 : exit(1);
93 : }
94 :
95 : /* force tds to convert from utf8 to iso8859-1 (even on Sybase) */
96 3088 : tds_srv_charset_changed(tds->conn, "UTF-8");
97 3088 : tds->current_results->columns[0]->char_conv = tds->conn->char_convs[client2server_chardata];
98 :
99 3088 : rc = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
100 3088 : if (rc != TDS_SUCCESS) {
101 0 : fprintf(stderr, "tds_process_tokens() failed\n");
102 0 : exit(1);
103 : }
104 :
105 3088 : curcol = tds->current_results->columns[0];
106 3088 : src = (char*) curcol->column_data;
107 :
108 3088 : if (is_blob_col(curcol)) {
109 0 : TDSBLOB *blob = (TDSBLOB *) src;
110 :
111 0 : src = blob->textvalue;
112 : }
113 :
114 3088 : prefix[0] = 0;
115 3088 : suffix[0] = 0;
116 3088 : tmp[0] = 0;
117 3088 : switch (type) {
118 1544 : case 0:
119 1544 : strcpy(suffix, "\x80\x90");
120 1544 : break;
121 1544 : case 1:
122 : /* try two invalid in different part */
123 1544 : strcpy(prefix, "?\x90");
124 1544 : strcpy(suffix, "?\x90");
125 : /* some platforms replace invalid sequence with a fixed char */
126 1544 : if (invalid_char < 0)
127 8 : invalid_char = (unsigned char) src[0];
128 1544 : prefix[0] = (char) invalid_char;
129 1544 : suffix[0] = (char) invalid_char;
130 1544 : break;
131 : }
132 :
133 296448 : for (i = 0; i < n; ++i)
134 296448 : sprintf(strchr(tmp, 0), "%c", "0123456789"[i % 10]);
135 3088 : sprintf(buf, "%s%s%s", prefix, tmp, suffix);
136 :
137 3088 : if (strlen(buf) != curcol->column_cur_size || strncmp(buf, src, curcol->column_cur_size) != 0) {
138 0 : int l = curcol->column_cur_size;
139 :
140 0 : if (l > 1000)
141 0 : l = 1000;
142 0 : strncpy(tmp, src, l);
143 0 : tmp[l] = 0;
144 0 : fprintf(stderr, "Wrong result in %s\n Got: '%s' len %d\n Expected: '%s' len %u\n", test_name, tmp,
145 0 : curcol->column_cur_size, buf, (unsigned int) strlen(buf));
146 0 : exit(1);
147 : }
148 :
149 3088 : rc = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
150 3088 : if (rc != TDS_SUCCESS || result_type == TDS_ROW_RESULT) {
151 0 : fprintf(stderr, "tds_process_tokens() unexpected return\n");
152 0 : exit(1);
153 : }
154 :
155 3088 : while ((rc = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
156 0 : switch (result_type) {
157 : case TDS_NO_MORE_RESULTS:
158 : break;
159 :
160 0 : case TDS_DONE_RESULT:
161 : case TDS_DONEPROC_RESULT:
162 : case TDS_DONEINPROC_RESULT:
163 0 : if (!(done_flags & TDS_DONE_ERROR))
164 : break;
165 :
166 : default:
167 0 : fprintf(stderr, "tds_process_tokens() unexpected result_type\n");
168 0 : exit(1);
169 : break;
170 : }
171 0 : }
172 3088 : }
173 :
174 : static int
175 1544 : err_handler(const TDSCONTEXT * tds_ctx, TDSSOCKET * tds, TDSMESSAGE * msg)
176 : {
177 1544 : int error = 0;
178 :
179 1544 : if (strstr(msg->message, "EINVAL")) {
180 0 : ++einval_count;
181 0 : if (einval_error)
182 : error = 1;
183 1544 : } else if (strstr(msg->message, "could not be converted")) {
184 1544 : ++eilseq_count;
185 1544 : if (eilseq_error)
186 : error = 1;
187 0 : } else if (strstr(msg->message, "E2BIG")) {
188 0 : ++e2big_count;
189 0 : error = 1;
190 : } else {
191 : error = 1;
192 : }
193 :
194 : if (error) {
195 0 : fprintf(stderr, "Unexpected in %s error: %s\n", test_name, msg->message);
196 0 : g_result = 1;
197 : }
198 1544 : return TDS_INT_CANCEL;
199 : }
200 :
201 : int
202 8 : main(int argc, char **argv)
203 : {
204 : TDSLOGIN *login;
205 : int ret;
206 8 : int verbose = 0;
207 : int i;
208 : typedef int (*perr)(const TDSCONTEXT *, TDSSOCKET *, TDSMESSAGE *);
209 : const perr * my_err;
210 :
211 : /* use ISO8859-1 as our coding */
212 8 : strcpy(CHARSET, "ISO8859-1");
213 :
214 8 : ret = try_tds_login(&login, &tds, __FILE__, verbose);
215 8 : if (ret != TDS_SUCCESS) {
216 0 : fprintf(stderr, "try_tds_login() failed\n");
217 0 : return 1;
218 : }
219 :
220 : /* override a const in a safe way */
221 8 : my_err = &tds_get_ctx(tds)->err_handler;
222 8 : *((perr*)my_err) = err_handler;
223 :
224 : /* prepend some characters to check part of sequence error */
225 8 : einval_error = 1;
226 8 : eilseq_error = 1;
227 : /* do not stop on first error so we check conversion correct */
228 1552 : for (i = 0; i <= 192; ++i)
229 1544 : test(i, 0);
230 :
231 : /* try creating a double conversion warning */
232 8 : eilseq_error = 0;
233 8 : einval_error = 0; /* we already tested this error above */
234 1552 : for (i = 0; i <= 192; ++i) {
235 1544 : eilseq_count = 0;
236 1544 : test(i, 1);
237 1544 : if (eilseq_count > 1) {
238 0 : fprintf(stderr, "Two warnings returned instead of one in %s\n", test_name);
239 0 : g_result = 1;
240 0 : break;
241 : }
242 1544 : if (eilseq_count < 1 && invalid_char == '?') {
243 0 : fprintf(stderr, "No warning returned in %s\n", test_name);
244 0 : g_result = 1;
245 : }
246 : }
247 :
248 8 : try_tds_logout(login, tds, verbose);
249 8 : return g_result;
250 : }
|