bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / firebird / Util.cxx
blob6cc70b4270f404279539c44e200141583fa20d59
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "Util.hxx"
11 #include <rtl/ustrbuf.hxx>
12 #include <sal/log.hxx>
14 #include <com/sun/star/sdbc/DataType.hpp>
15 #include <com/sun/star/sdbc/SQLException.hpp>
17 using namespace ::connectivity;
19 using namespace ::com::sun::star;
20 using namespace ::com::sun::star::sdbc;
21 using namespace ::com::sun::star::uno;
23 using namespace firebird;
25 OUString firebird::sanitizeIdentifier(const OUString& rIdentifier)
27 OUString sRet = rIdentifier.trim();
28 assert(sRet.getLength() <= 31); // Firebird identifiers cannot be longer than this.
30 return sRet;
33 OUString firebird::StatusVectorToString(const ISC_STATUS_ARRAY& rStatusVector,
34 std::u16string_view rCause)
36 OUStringBuffer buf;
37 const ISC_STATUS* pStatus = reinterpret_cast<const ISC_STATUS*>(&rStatusVector);
39 buf.append("firebird_sdbc error:");
40 try
42 char msg[512]; // Size is based on suggestion in docs.
43 while(fb_interpret(msg, sizeof(msg), &pStatus))
45 // TODO: verify encoding
46 buf.append("\n*");
47 buf.append(OUString(msg, strlen(msg), RTL_TEXTENCODING_UTF8));
50 catch (...)
52 SAL_WARN("connectivity.firebird", "ignore fb_interpret exception");
54 buf.append(OUString::Concat("\ncaused by\n'") + rCause + "'\n");
56 OUString error = buf.makeStringAndClear();
57 SAL_WARN("connectivity.firebird", error);
58 return error;
61 void firebird::evaluateStatusVector(const ISC_STATUS_ARRAY& rStatusVector,
62 std::u16string_view rCause,
63 const uno::Reference< XInterface >& _rxContext)
65 if (IndicatesError(rStatusVector))
67 OUString error = StatusVectorToString(rStatusVector, rCause);
68 throw SQLException(error, _rxContext, OUString(), 1, Any());
72 static sal_Int32 lcl_getNumberType( short aType, NumberSubType aSubType )
74 switch(aSubType)
76 case NumberSubType::Numeric:
77 return DataType::NUMERIC;
78 case NumberSubType::Decimal:
79 return DataType::DECIMAL;
80 default:
81 switch(aType)
83 case SQL_SHORT:
84 return DataType::SMALLINT;
85 case SQL_LONG:
86 return DataType::INTEGER;
87 case SQL_DOUBLE:
88 return DataType::DOUBLE;
89 case SQL_INT64:
90 return DataType::BIGINT;
91 default:
92 assert(false); // not a number
93 return 0;
97 static sal_Int32 lcl_getCharColumnType( short aType, std::u16string_view sCharset )
99 switch(aType)
101 case SQL_TEXT:
102 if( sCharset == u"OCTETS")
103 return DataType::BINARY;
104 else
105 return DataType::CHAR;
106 case SQL_VARYING:
107 if( sCharset == u"OCTETS")
108 return DataType::VARBINARY;
109 else
110 return DataType::VARCHAR;
111 default:
112 assert(false);
113 return 0;
117 sal_Int32 firebird::ColumnTypeInfo::getSdbcType() const
119 short aType = m_aType & ~1; // Remove last bit -- it is used to denote whether column
120 // can store Null, not needed for type determination
121 short aSubType = m_aSubType;
122 if( m_nScale > 0 )
124 // numeric / decimal
125 if(aType == SQL_SHORT || aType == SQL_LONG || aType == SQL_DOUBLE
126 || aType == SQL_INT64)
128 // if scale is set without subtype then imply numeric
129 if( static_cast<NumberSubType>(aSubType) == NumberSubType::Other )
130 aSubType = static_cast<short>(NumberSubType::Numeric);
134 switch (aType)
136 case SQL_TEXT:
137 case SQL_VARYING:
138 return lcl_getCharColumnType(aType, m_sCharsetName);
139 case SQL_SHORT:
140 case SQL_LONG:
141 case SQL_DOUBLE:
142 case SQL_INT64:
143 return lcl_getNumberType(aType, static_cast<NumberSubType>(aSubType) );
144 case SQL_FLOAT:
145 return DataType::FLOAT;
146 case SQL_D_FLOAT:
147 return DataType::DOUBLE;
148 case SQL_TIMESTAMP:
149 return DataType::TIMESTAMP;
150 case SQL_BLOB:
151 switch (static_cast<BlobSubtype>(aSubType))
153 case BlobSubtype::Blob:
154 return DataType::BLOB;
155 case BlobSubtype::Clob:
156 return DataType::CLOB;
157 case BlobSubtype::Image:
158 return DataType::LONGVARBINARY;
159 default:
160 SAL_WARN("connectivity.firebird", "Unknown subtype for Blob type: " << aSubType);
161 assert(!"Unknown subtype for Blob type"); // Should never happen
162 return 0;
164 case SQL_ARRAY:
165 return DataType::ARRAY;
166 case SQL_TYPE_TIME:
167 return DataType::TIME;
168 case SQL_TYPE_DATE:
169 return DataType::DATE;
170 case SQL_NULL:
171 return DataType::SQLNULL;
172 case SQL_QUAD: // Is a "Blob ID" according to the docs
173 return 0; // TODO: verify
174 case SQL_BOOLEAN:
175 return DataType::BOOLEAN;
176 default:
177 assert(false); // Should never happen
178 return 0;
182 OUString firebird::ColumnTypeInfo::getColumnTypeName() const
184 sal_Int32 nDataType = this->getSdbcType();
185 switch (nDataType)
187 case DataType::BIT:
188 return "BIT";
189 case DataType::TINYINT:
190 return "TINYINT";
191 case DataType::SMALLINT:
192 return "SMALLINT";
193 case DataType::INTEGER:
194 return "INTEGER";
195 case DataType::BIGINT:
196 return "BIGINT";
197 case DataType::FLOAT:
198 return "FLOAT";
199 case DataType::REAL:
200 return "REAL";
201 case DataType::DOUBLE:
202 return "DOUBLE";
203 case DataType::NUMERIC:
204 return "NUMERIC";
205 case DataType::DECIMAL:
206 return "DECIMAL";
207 case DataType::CHAR:
208 return "CHAR";
209 case DataType::VARCHAR:
210 return "VARCHAR";
211 case DataType::LONGVARCHAR:
212 return "LONGVARCHAR";
213 case DataType::DATE:
214 return "DATE";
215 case DataType::TIME:
216 return "TIME";
217 case DataType::TIMESTAMP:
218 return "TIMESTAMP";
219 case DataType::BINARY:
220 // in Firebird, that is the same datatype "CHAR" as DataType::CHAR,
221 // only with CHARACTER SET OCTETS; we use the synonym CHARACTER
222 // to fool LO into seeing it as different types.
223 return "CHARACTER";
224 case DataType::VARBINARY:
225 // see above comment about DataType::BINARY.
226 return "CHARACTER VARYING";
227 case DataType::LONGVARBINARY:
228 return "BLOB SUB_TYPE " + OUString::number(static_cast<short>(BlobSubtype::Image));
229 case DataType::ARRAY:
230 return "ARRAY";
231 case DataType::BLOB:
232 return "BLOB SUB_TYPE BINARY";
233 case DataType::CLOB:
234 return "BLOB SUB_TYPE TEXT";
235 case DataType::BOOLEAN:
236 return "BOOLEAN";
237 case DataType::SQLNULL:
238 return "NULL";
239 default:
240 assert(false); // Should never happen
241 return OUString();
245 short firebird::getFBTypeFromBlrType(short blrType)
247 switch (blrType)
249 case blr_text:
250 return SQL_TEXT;
251 case blr_text2:
252 assert(false);
253 return 0; // No idea if this should be supported
254 case blr_varying:
255 return SQL_VARYING;
256 case blr_varying2:
257 assert(false);
258 return 0; // No idea if this should be supported
259 case blr_short:
260 return SQL_SHORT;
261 case blr_long:
262 return SQL_LONG;
263 case blr_float:
264 return SQL_FLOAT;
265 case blr_double:
266 return SQL_DOUBLE;
267 case blr_d_float:
268 return SQL_D_FLOAT;
269 case blr_timestamp:
270 return SQL_TIMESTAMP;
271 case blr_blob:
272 return SQL_BLOB;
273 // case blr_SQL_ARRAY:
274 // return OUString("SQL_ARRAY");
275 case blr_sql_time:
276 return SQL_TYPE_TIME;
277 case blr_sql_date:
278 return SQL_TYPE_DATE;
279 case blr_int64:
280 return SQL_INT64;
281 // case SQL_NULL:
282 // return OUString("SQL_NULL");
283 case blr_quad:
284 return SQL_QUAD;
285 case blr_bool:
286 return SQL_BOOLEAN;
287 default:
288 // If this happens we have hit one of the extra types in ibase.h
289 // look up blr_* for a list, e.g. blr_domain_name, blr_not_nullable etc.
290 assert(false);
291 return 0;
295 void firebird::mallocSQLVAR(XSQLDA* pSqlda)
297 // TODO: confirm the sizings below.
298 XSQLVAR* pVar = pSqlda->sqlvar;
299 for (int i=0; i < pSqlda->sqld; i++, pVar++)
301 int dtype = (pVar->sqltype & ~1); /* drop flag bit for now */
302 switch(dtype) {
303 case SQL_TEXT:
304 pVar->sqldata = static_cast<char *>(malloc(sizeof(char)*pVar->sqllen));
305 break;
306 case SQL_VARYING:
307 pVar->sqldata = static_cast<char *>(malloc(sizeof(char)*pVar->sqllen + 2));
308 break;
309 case SQL_SHORT:
310 pVar->sqldata = static_cast<char*>(malloc(sizeof(sal_Int16)));
311 break;
312 case SQL_LONG:
313 pVar->sqldata = static_cast<char*>(malloc(sizeof(sal_Int32)));
314 break;
315 case SQL_FLOAT:
316 pVar->sqldata = static_cast<char *>(malloc(sizeof(float)));
317 break;
318 case SQL_DOUBLE:
319 pVar->sqldata = static_cast<char *>(malloc(sizeof(double)));
320 break;
321 case SQL_D_FLOAT:
322 pVar->sqldata = static_cast<char *>(malloc(sizeof(double)));
323 break;
324 case SQL_TIMESTAMP:
325 pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_TIMESTAMP)));
326 break;
327 // an ARRAY is in fact a BLOB of a specialized type
328 // See https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-bnrytypes.html#fblangref25-datatypes-array
329 case SQL_ARRAY:
330 case SQL_BLOB:
331 pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_QUAD)));
332 break;
333 case SQL_TYPE_TIME:
334 pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_TIME)));
335 break;
336 case SQL_TYPE_DATE:
337 pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_DATE)));
338 break;
339 case SQL_INT64:
340 pVar->sqldata = static_cast<char *>(malloc(sizeof(sal_Int64)));
341 break;
342 case SQL_BOOLEAN:
343 pVar->sqldata = static_cast<char *>(malloc(sizeof(sal_Bool)));
344 break;
345 case SQL_NULL:
346 assert(false); // TODO: implement
347 break;
348 case SQL_QUAD:
349 assert(false); // TODO: implement
350 break;
351 default:
352 SAL_WARN("connectivity.firebird", "Unknown type: " << dtype);
353 assert(false);
354 break;
356 /* allocate variable to hold NULL status */
357 pVar->sqlind = static_cast<short *>(malloc(sizeof(short)));
361 void firebird::freeSQLVAR(XSQLDA* pSqlda)
363 XSQLVAR* pVar = pSqlda->sqlvar;
364 for (int i=0; i < pSqlda->sqld; i++, pVar++)
366 int dtype = (pVar->sqltype & ~1); /* drop flag bit for now */
367 switch(dtype) {
368 case SQL_TEXT:
369 case SQL_VARYING:
370 case SQL_SHORT:
371 case SQL_LONG:
372 case SQL_FLOAT:
373 case SQL_DOUBLE:
374 case SQL_D_FLOAT:
375 case SQL_TIMESTAMP:
376 // an ARRAY is in fact a BLOB of a specialized type
377 // See https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-bnrytypes.html#fblangref25-datatypes-array
378 case SQL_ARRAY:
379 case SQL_BLOB:
380 case SQL_INT64:
381 case SQL_TYPE_TIME:
382 case SQL_TYPE_DATE:
383 case SQL_BOOLEAN:
384 if(pVar->sqldata)
386 free(pVar->sqldata);
387 pVar->sqldata = nullptr;
389 break;
390 case SQL_NULL:
391 assert(false); // TODO: implement
392 break;
393 case SQL_QUAD:
394 assert(false); // TODO: implement
395 break;
396 default:
397 SAL_WARN("connectivity.firebird", "Unknown type: " << dtype);
398 // assert(false);
399 break;
402 if(pVar->sqlind)
404 free(pVar->sqlind);
405 pVar->sqlind = nullptr;
411 OUString firebird::escapeWith( const OUString& sText, const char aKey, const char aEscapeChar)
413 OUString sRet(sText);
414 sal_Int32 aIndex = 0;
415 for (;;)
417 aIndex = sRet.indexOf(aKey, aIndex);
418 if ( aIndex <= 0 || aIndex >= sRet.getLength())
419 break;
420 sRet = sRet.replaceAt(aIndex, 1, OUStringChar(aEscapeChar) + OUStringChar(aKey) );
421 aIndex += 2;
424 return sRet;
427 sal_Int64 firebird::pow10Integer(int nDecimalCount)
429 sal_Int64 nRet = 1;
430 for(int i=0; i< nDecimalCount; i++)
432 nRet *= 10;
434 return nRet;
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */