1 #include "common.h"
2 
3 #include <common/test_assert.h>
4 
5 /* test binding with UTF-8 encoding */
6 
7 #ifndef _WIN32
8 static void init_connect(void);
9 
10 static void
init_connect(void)11 init_connect(void)
12 {
13 	CHKAllocEnv(&odbc_env, "S");
14 	SQLSetEnvAttr(odbc_env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) (SQL_OV_ODBC3), SQL_IS_UINTEGER);
15 	CHKAllocConnect(&odbc_conn, "S");
16 }
17 
18 /* test table name, it contains two japanese characters */
19 static const char table_name[] = "mytab\xe7\x8e\x8b\xe9\xb4\xbb";
20 
21 static const char * const strings[] = {
22 	/* ascii */
23 	"aaa", "aaa",
24 	/* latin 1*/
25 	"abc\xc3\xa9\xc3\xa1\xc3\xb4", "abc\xc3\xa9\xc3\xae\xc3\xb4",
26 	/* Japanese... */
27 	"abc\xe7\x8e\x8b\xe9\xb4\xbb", "abc\xe7\x8e\x8b\xe9\xb4\xbb\xe5\x82\x91\xe7\x8e\x8b\xe9\xb4\xbb\xe5\x82\x91",
28 	NULL, NULL
29 };
30 
31 /* same strings in hex */
32 static const char * const strings_hex[] = {
33 	/* ascii */
34 	"0x610061006100", "0x610061006100",
35 	/* latin 1*/
36 	"0x610062006300e900e100f400", "0x610062006300e900ee00f400",
37 	/* Japanese... */
38 	"0x6100620063008b733b9d", "0x6100620063008b733b9d91508b733b9d9150",
39 	NULL, NULL
40 };
41 
42 static char tmp[2048];
43 
44 static void
TestBinding(int minimum)45 TestBinding(int minimum)
46 {
47 	const char * const*p;
48 	SQLINTEGER n;
49 	SQLLEN n_len;
50 
51 	sprintf(tmp, "DELETE FROM %s", table_name);
52 	odbc_command(tmp);
53 
54 	/* insert with SQLPrepare/SQLBindParameter/SQLExecute */
55 	sprintf(tmp, "INSERT INTO %s VALUES(?,?,?)", table_name);
56 	CHKPrepare(T(tmp), SQL_NTS, "S");
57 	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG,
58 		SQL_INTEGER, 0, 0, &n, 0, &n_len, "S");
59 	n_len = sizeof(n);
60 
61 	for (n = 1, p = strings; p[0] && p[1]; p += 2, ++n) {
62 		SQLLEN s1_len, s2_len;
63 		unsigned int len;
64 
65                 len = minimum ? ((int) strlen(strings_hex[p-strings]) - 2) / 4
66                     : 40;
67 		CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR,
68 			SQL_WCHAR, len, 0, (void *) p[0], 0, &s1_len, "S");
69                 len = minimum ? ((int)strlen(strings_hex[p+1-strings]) - 2) / 4
70                     : 40;
71 		/* FIXME this with SQL_VARCHAR produce wrong protocol data */
72 		CHKBindParameter(3, SQL_PARAM_INPUT, SQL_C_CHAR,
73 			SQL_WVARCHAR, len, 0, (void *) p[1], 0, &s2_len, "S");
74 		s1_len = strlen(p[0]);
75 		s2_len = strlen(p[1]);
76 		printf("insert #%d\n", (int) n);
77 		CHKExecute("S");
78 	}
79 
80 	/* check rows */
81 	for (n = 1, p = strings_hex; p[0] && p[1]; p += 2, ++n) {
82 		sprintf(tmp, "IF NOT EXISTS(SELECT * FROM %s WHERE k = %d AND c = %s AND vc = %s) SELECT 1", table_name, (int) n, p[0], p[1]);
83 		odbc_check_no_row(tmp);
84 	}
85 
86 	odbc_reset_statement();
87 }
88 
89 int
main(int argc,char * argv[])90 main(int argc, char *argv[])
91 {
92 	SQLSMALLINT len;
93 	const char * const*p;
94 	SQLINTEGER n;
95 
96 	if (odbc_read_login_info())
97 		exit(1);
98 
99 	/* connect string using DSN */
100 	init_connect();
101 	sprintf(tmp, "DSN=%s;UID=%s;PWD=%s;DATABASE=%s;ClientCharset=UTF-8;", odbc_server, odbc_user, odbc_password, odbc_database);
102 	CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SI");
103 	if (!odbc_driver_is_freetds()) {
104 		odbc_disconnect();
105 		printf("Driver is not FreeTDS, exiting\n");
106 		odbc_test_skipped();
107 		return 0;
108 	}
109 
110 	if (!odbc_db_is_microsoft() || odbc_db_version_int() < 0x08000000u) {
111 		odbc_disconnect();
112 		printf("Test for MSSQL only\n");
113 		odbc_test_skipped();
114 		return 0;
115 	}
116 
117 	CHKAllocStmt(&odbc_stmt, "S");
118 
119 	/* create test table */
120 	sprintf(tmp, "IF OBJECT_ID(N'%s') IS NOT NULL DROP TABLE %s", table_name, table_name);
121 	odbc_command(tmp);
122 	sprintf(tmp, "CREATE TABLE %s (k int, c NCHAR(10), vc NVARCHAR(10))", table_name);
123 	odbc_command(tmp);
124 
125 	/* insert with INSERT statements */
126 	for (n = 1, p = strings; p[0] && p[1]; p += 2, ++n) {
127 		sprintf(tmp, "INSERT INTO %s VALUES (%d,N'%s',N'%s')", table_name, (int) n, p[0], p[1]);
128 		odbc_command(tmp);
129 	}
130 
131 	/* check rows */
132 	for (n = 1, p = strings_hex; p[0] && p[1]; p += 2, ++n) {
133 		sprintf(tmp, "IF NOT EXISTS(SELECT * FROM %s WHERE k = %d AND c = %s AND vc = %s) SELECT 1", table_name, (int) n, p[0], p[1]);
134 		odbc_check_no_row(tmp);
135 	}
136 
137 	TestBinding(0);
138 
139 	TestBinding(1);
140 
141 	/* cleanup */
142 	sprintf(tmp, "IF OBJECT_ID(N'%s') IS NOT NULL DROP TABLE %s", table_name, table_name);
143 	odbc_command(tmp);
144 
145 	odbc_disconnect();
146 	printf("Done.\n");
147 	return 0;
148 }
149 
150 #else
151 
152 int
main(void)153 main(void)
154 {
155 	/* on Windows SQLExecDirect is always converted to SQLExecDirectW by the DM */
156 	printf("Not possible for this platform.\n");
157 	odbc_test_skipped();
158 	return 0;
159 }
160 #endif
161