1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
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.
33 OUString
firebird::StatusVectorToString(const ISC_STATUS_ARRAY
& rStatusVector
,
34 std::u16string_view rCause
)
37 const ISC_STATUS
* pStatus
= reinterpret_cast<const ISC_STATUS
*>(&rStatusVector
);
39 buf
.append("firebird_sdbc error:");
42 char msg
[512]; // Size is based on suggestion in docs.
43 while(fb_interpret(msg
, sizeof(msg
), &pStatus
))
45 // TODO: verify encoding
47 buf
.append(OUString(msg
, strlen(msg
), RTL_TEXTENCODING_UTF8
));
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
);
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
)
76 case NumberSubType::Numeric
:
77 return DataType::NUMERIC
;
78 case NumberSubType::Decimal
:
79 return DataType::DECIMAL
;
84 return DataType::SMALLINT
;
86 return DataType::INTEGER
;
88 return DataType::DOUBLE
;
90 return DataType::BIGINT
;
92 assert(false); // not a number
97 static sal_Int32
lcl_getCharColumnType( short aType
, std::u16string_view sCharset
)
102 if( sCharset
== u
"OCTETS")
103 return DataType::BINARY
;
105 return DataType::CHAR
;
107 if( sCharset
== u
"OCTETS")
108 return DataType::VARBINARY
;
110 return DataType::VARCHAR
;
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
;
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
);
138 return lcl_getCharColumnType(aType
, m_sCharsetName
);
143 return lcl_getNumberType(aType
, static_cast<NumberSubType
>(aSubType
) );
145 return DataType::FLOAT
;
147 return DataType::DOUBLE
;
149 return DataType::TIMESTAMP
;
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
;
160 SAL_WARN("connectivity.firebird", "Unknown subtype for Blob type: " << aSubType
);
161 assert(!"Unknown subtype for Blob type"); // Should never happen
165 return DataType::ARRAY
;
167 return DataType::TIME
;
169 return DataType::DATE
;
171 return DataType::SQLNULL
;
172 case SQL_QUAD
: // Is a "Blob ID" according to the docs
173 return 0; // TODO: verify
175 return DataType::BOOLEAN
;
177 assert(false); // Should never happen
182 OUString
firebird::ColumnTypeInfo::getColumnTypeName() const
184 sal_Int32 nDataType
= this->getSdbcType();
189 case DataType::TINYINT
:
191 case DataType::SMALLINT
:
193 case DataType::INTEGER
:
195 case DataType::BIGINT
:
197 case DataType::FLOAT
:
201 case DataType::DOUBLE
:
203 case DataType::NUMERIC
:
205 case DataType::DECIMAL
:
209 case DataType::VARCHAR
:
211 case DataType::LONGVARCHAR
:
212 return "LONGVARCHAR";
217 case DataType::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.
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
:
232 return "BLOB SUB_TYPE BINARY";
234 return "BLOB SUB_TYPE TEXT";
235 case DataType::BOOLEAN
:
237 case DataType::SQLNULL
:
240 assert(false); // Should never happen
245 short firebird::getFBTypeFromBlrType(short blrType
)
253 return 0; // No idea if this should be supported
258 return 0; // No idea if this should be supported
270 return SQL_TIMESTAMP
;
273 // case blr_SQL_ARRAY:
274 // return OUString("SQL_ARRAY");
276 return SQL_TYPE_TIME
;
278 return SQL_TYPE_DATE
;
282 // return OUString("SQL_NULL");
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.
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 */
304 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(char)*pVar
->sqllen
));
307 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(char)*pVar
->sqllen
+ 2));
310 pVar
->sqldata
= static_cast<char*>(malloc(sizeof(sal_Int16
)));
313 pVar
->sqldata
= static_cast<char*>(malloc(sizeof(sal_Int32
)));
316 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(float)));
319 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(double)));
322 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(double)));
325 pVar
->sqldata
= static_cast<char*>(malloc(sizeof(ISC_TIMESTAMP
)));
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
331 pVar
->sqldata
= static_cast<char*>(malloc(sizeof(ISC_QUAD
)));
334 pVar
->sqldata
= static_cast<char*>(malloc(sizeof(ISC_TIME
)));
337 pVar
->sqldata
= static_cast<char*>(malloc(sizeof(ISC_DATE
)));
340 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(sal_Int64
)));
343 pVar
->sqldata
= static_cast<char *>(malloc(sizeof(sal_Bool
)));
346 assert(false); // TODO: implement
349 assert(false); // TODO: implement
352 SAL_WARN("connectivity.firebird", "Unknown type: " << dtype
);
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 */
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
387 pVar
->sqldata
= nullptr;
391 assert(false); // TODO: implement
394 assert(false); // TODO: implement
397 SAL_WARN("connectivity.firebird", "Unknown type: " << dtype
);
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;
417 aIndex
= sRet
.indexOf(aKey
, aIndex
);
418 if ( aIndex
<= 0 || aIndex
>= sRet
.getLength())
420 sRet
= sRet
.replaceAt(aIndex
, 1, OUStringChar(aEscapeChar
) + OUStringChar(aKey
) );
427 sal_Int64
firebird::pow10Integer(int nDecimalCount
)
430 for(int i
=0; i
< nDecimalCount
; i
++)
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */