@@ -48,62 +48,8 @@ void SQLColumnsResultSetMutator::transformRow(const std::vector<ColumnInfo> & /*
4848 const auto & type_name = type_name_wrapper.value ;
4949 const auto column_info = parseColumnType (type_name);
5050 const TypeInfo & type_info = statement.getTypeInfo (column_info.type , column_info.type_without_parameters );
51- // MS Access compatibility fixes
52- SQLSMALLINT access_data_type = type_info.data_type ;
53- std::string access_type_name = type_info.type_name ; // Fix String types for MS Access compatibility with Long Text support
54- if (type_info.type_id == String || type_info.type_id == FixedString || type_info.type_id == Array) {
55- // Determine whether to use VARCHAR (Short Text) or LONGVARCHAR (Long Text)
56- // based on the estimated column size
57- int estimated_size = 255 ; // Default for String/Array types
58-
59- if (type_info.type_id == FixedString) {
60- estimated_size = column_info.fixed_size ;
61- } else if (type_info.type_id == String || type_info.type_id == Array) {
62- // For dynamic strings, check if we have size information
63- // Use LONGVARCHAR for potentially large text content
64- estimated_size = (type_info.column_size > 255 ) ? type_info.column_size : 255 ;
65- }
66-
67- // Determine if Unicode support is needed
68- // Check if the column contains non-ASCII characters or if Unicode is explicitly required
69- bool needs_unicode = false ;
70-
71- // Check if the type name indicates Unicode support (e.g., contains UTF-8, Unicode markers)
72- if (type_name.find (" UTF" ) != std::string::npos ||
73- type_name.find (" Unicode" ) != std::string::npos ||
74- type_name.find (" NCHAR" ) != std::string::npos ||
75- type_name.find (" NVARCHAR" ) != std::string::npos) {
76- needs_unicode = true ;
77- }
78-
79- // For ClickHouse, assume Unicode support is generally needed since it uses UTF-8 by default
80- // This can be controlled by a driver setting if needed
81- // For now, we'll default to Unicode support for better compatibility
82- needs_unicode = true ;
83-
84- // Select appropriate data type based on size and Unicode requirements
85- if (needs_unicode) {
86- if (estimated_size > 255 ) {
87- access_data_type = SQL_WLONGVARCHAR;
88- access_type_name = " WLONGVARCHAR" ;
89- } else {
90- access_data_type = SQL_WVARCHAR;
91- access_type_name = " WVARCHAR" ;
92- }
93- } else {
94- // Use standard ANSI types for non-Unicode text
95- if (estimated_size > 255 ) {
96- access_data_type = SQL_LONGVARCHAR;
97- access_type_name = " LONGVARCHAR" ;
98- } else {
99- access_data_type = SQL_VARCHAR;
100- access_type_name = " VARCHAR" ;
101- }
102- }
103- }
104-
105- row.fields .at (COL_DATA_TYPE).data = DataSourceType<DataSourceTypeId::Int16>{access_data_type};
106- row.fields .at (COL_TYPE_NAME).data = DataSourceType<DataSourceTypeId::String>{access_type_name};
51+ row.fields .at (COL_DATA_TYPE).data = DataSourceType<DataSourceTypeId::Int16>{type_info.data_type };
52+ row.fields .at (COL_TYPE_NAME).data = DataSourceType<DataSourceTypeId::String>{type_info.type_name };
10753
10854 int column_size{};
10955 switch (type_info.type_id ) {
@@ -112,17 +58,6 @@ void SQLColumnsResultSetMutator::transformRow(const std::vector<ColumnInfo> & /*
11258 break ;
11359 case FixedString:
11460 column_size = column_info.fixed_size ;
115- break ; case String:
116- case Array:
117- // Intelligent sizing for MS Access compatibility
118- if (access_data_type == SQL_LONGVARCHAR || access_data_type == SQL_WLONGVARCHAR) {
119- // For Long Text fields, use a large but reasonable size
120- // MS Access Long Text can handle up to 1GB, but we'll use 65535 for ODBC compatibility
121- column_size = 65535 ;
122- } else {
123- // Standard VARCHAR/WVARCHAR size for Short Text fields
124- column_size = 255 ;
125- }
12661 break ;
12762 default :
12863 column_size = type_info.column_size ;
@@ -133,8 +68,7 @@ void SQLColumnsResultSetMutator::transformRow(const std::vector<ColumnInfo> & /*
13368 if (type_info.num_prec_radix .has_value ())
13469 row.fields .at (COL_NUM_PREC_RADIX).data = DataSourceType<DataSourceTypeId::Int16>{*type_info.num_prec_radix };
13570
136- // MS Access expects standard ODBC NULLABLE values
137- row.fields .at (COL_NULLABLE).data = DataSourceType<DataSourceTypeId::Int16>{column_info.is_nullable ? SQL_NULLABLE : SQL_NO_NULLS};
71+ row.fields .at (COL_NULLABLE).data = DataSourceType<DataSourceTypeId::Int16>{column_info.is_nullable };
13872
13973 if (type_info.type_id == Decimal)
14074 row.fields .at (COL_DECIMAL_DIGITS).data = DataSourceType<DataSourceTypeId::Int16>{column_info.scale };
@@ -146,39 +80,9 @@ void SQLColumnsResultSetMutator::transformRow(const std::vector<ColumnInfo> & /*
14680 row.fields .at (COL_SQL_DATA_TYPE).data = DataSourceType<DataSourceTypeId::Int16>{type_info.sql_data_type };
14781
14882 if (type_info.sql_datetime_sub .has_value ())
149- row.fields .at (COL_SQL_DATETIME_SUB).data = DataSourceType<DataSourceTypeId::Int16>{*type_info.sql_datetime_sub }; // MS Access compatible octet length for string types
150- // For UTF character encoding considerations, CHAR_OCTET_LENGTH should represent
151- // the maximum number of bytes needed to store a character in the column's encoding
152- int octet_length = type_info.octet_length ;
153- if (type_info.type_id == String || type_info.type_id == Array) {
154- // For variable-length string types, calculate octet length considering encoding
155- switch (access_data_type) {
156- case SQL_WLONGVARCHAR:
157- // For Unicode Long Text fields (wide characters)
158- // In UTF-16, characters can be 2-4 bytes, so we use 4 * column_size as maximum
159- octet_length = std::min (column_size * 4 , 262140 ); // 4 bytes per char, MS Access limit
160- break ;
161- case SQL_WVARCHAR:
162- // For Unicode VARCHAR fields (wide characters)
163- octet_length = std::min (column_size * 4 , 1020 ); // 4 bytes per char, VARCHAR practical limit
164- break ;
165- case SQL_LONGVARCHAR:
166- // For ANSI Long Text fields
167- // In UTF-8, characters can be 1-4 bytes, so we use 4 * column_size as maximum
168- octet_length = std::min (column_size * 4 , 262140 ); // 4 bytes per char, MS Access limit
169- break ;
170- case SQL_VARCHAR:
171- default :
172- // For ANSI VARCHAR fields
173- octet_length = std::min (column_size * 4 , 1020 ); // 4 bytes per char, VARCHAR practical limit
174- break ;
175- }
176- } else if (type_info.type_id == FixedString) {
177- // For fixed-length strings, the size is already defined
178- octet_length = column_info.fixed_size ;
179- }
180-
181- row.fields .at (COL_CHAR_OCTET_LENGTH).data = DataSourceType<DataSourceTypeId::Int32>{octet_length};
83+ row.fields .at (COL_SQL_DATETIME_SUB).data = DataSourceType<DataSourceTypeId::Int16>{*type_info.sql_datetime_sub };
84+
85+ row.fields .at (COL_CHAR_OCTET_LENGTH).data = DataSourceType<DataSourceTypeId::Int32>{type_info.octet_length };
18286
18387 row.fields .at (COL_IS_NULLABLE).data = DataSourceType<DataSourceTypeId::String>{column_info.is_nullable ? " YES" : " NO" };
18488}
0 commit comments