xref: /core/connectivity/source/drivers/firebird/DatabaseMetaData.cxx (revision b1ec05b4b1928433cd8c9130b0ae78ba62269537)
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.
4  *
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  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "DatabaseMetaData.hxx"
21 #include "Util.hxx"
22 
23 #include <ibase.h>
24 #include <rtl/ustrbuf.hxx>
25 #include <sal/log.hxx>
26 #include <FDatabaseMetaDataResultSet.hxx>
27 
28 #include <com/sun/star/sdbc/ColumnSearch.hpp>
29 #include <com/sun/star/sdbc/ColumnValue.hpp>
30 #include <com/sun/star/sdbc/DataType.hpp>
31 #include <com/sun/star/sdbc/IndexType.hpp>
32 #include <com/sun/star/sdbc/ResultSetType.hpp>
33 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
34 #include <com/sun/star/sdbc/SQLException.hpp>
35 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
36 #include <com/sun/star/sdbc/XRow.hpp>
37 #include <com/sun/star/sdbc/KeyRule.hpp>
38 #include <com/sun/star/sdbc/Deferrability.hpp>
39 
40 using namespace connectivity::firebird;
41 using namespace com::sun::star;
42 using namespace com::sun::star::uno;
43 using namespace com::sun::star::lang;
44 using namespace com::sun::star::beans;
45 using namespace com::sun::star::sdbc;
46 
ODatabaseMetaData(Connection * _pCon)47 ODatabaseMetaData::ODatabaseMetaData(Connection* _pCon)
48 : m_pConnection(_pCon)
49 {
50     SAL_WARN_IF(!m_pConnection.is(), "connectivity.firebird",
51             "ODatabaseMetaData::ODatabaseMetaData: No connection set!");
52 }
53 
~ODatabaseMetaData()54 ODatabaseMetaData::~ODatabaseMetaData()
55 {
56 }
57 
58 //----- Catalog Info -- UNSUPPORTED -------------------------------------------
getCatalogSeparator()59 OUString SAL_CALL ODatabaseMetaData::getCatalogSeparator()
60 {
61     return OUString();
62 }
63 
getMaxCatalogNameLength()64 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength()
65 {
66     return -1;
67 }
68 
getCatalogTerm()69 OUString SAL_CALL ODatabaseMetaData::getCatalogTerm()
70 {
71     return OUString();
72 }
73 
isCatalogAtStart()74 sal_Bool SAL_CALL ODatabaseMetaData::isCatalogAtStart()
75 {
76     return false;
77 }
78 
supportsCatalogsInTableDefinitions()79 sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInTableDefinitions()
80 {
81     return false;
82 }
83 
supportsCatalogsInIndexDefinitions()84 sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions()
85 {
86     return false;
87 }
88 
supportsCatalogsInDataManipulation()89 sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInDataManipulation(  )
90 {
91     return false;
92 }
93 
getCatalogs()94 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCatalogs()
95 {
96     OSL_FAIL("Not implemented yet!");
97     // TODO implement
98     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eCatalogs);
99 }
100 
supportsCatalogsInProcedureCalls()101 sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls()
102 {
103     return false;
104 }
105 
supportsCatalogsInPrivilegeDefinitions()106 sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions()
107 {
108     return false;
109 }
110 
111 //----- Schema Info -- UNSUPPORTED --------------------------------------------
supportsSchemasInProcedureCalls()112 sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls()
113 {
114     return false;
115 }
116 
supportsSchemasInPrivilegeDefinitions()117 sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions()
118 {
119     return false;
120 }
121 
supportsSchemasInDataManipulation()122 sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInDataManipulation()
123 {
124     return false;
125 }
126 
supportsSchemasInIndexDefinitions()127 sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions()
128 {
129     return false;
130 }
131 
supportsSchemasInTableDefinitions()132 sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInTableDefinitions()
133 {
134     return false;
135 }
136 
getMaxSchemaNameLength()137 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength()
138 {
139     return -1;
140 }
141 
getSchemaTerm()142 OUString SAL_CALL ODatabaseMetaData::getSchemaTerm()
143 {
144     return OUString();
145 }
146 
getSchemas()147 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemas()
148 {
149     OSL_FAIL("Not implemented yet!");
150     // TODO implement
151     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eSchemas);
152 }
153 
154 //----- Max Sizes/Lengths -----------------------------------------------------
getMaxBinaryLiteralLength()155 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength()
156 {
157     return 32767;
158 }
159 
getMaxRowSize()160 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize()
161 {
162     return 32767;
163 }
164 
getMaxCharLiteralLength()165 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength()
166 {
167     return 32767;
168 }
169 
getMaxColumnNameLength()170 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength()
171 {
172     return 31;
173 }
174 
getMaxColumnsInIndex()175 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex()
176 {
177     // TODO: No idea.
178     // See: http://www.firebirdsql.org/en/firebird-technical-specifications/
179     return 16;
180 }
181 
getMaxCursorNameLength()182 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength()
183 {
184     return 32;
185 }
186 
getMaxConnections()187 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections()
188 {
189     return 100; // Arbitrary
190 }
191 
getMaxColumnsInTable()192 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable()
193 {
194     // May however be smaller.
195     // See: http://www.firebirdsql.org/en/firebird-technical-specifications/
196     return 32767;
197 }
198 
getMaxStatementLength()199 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength()
200 {
201     return 32767;
202 }
203 
getMaxTableNameLength()204 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength()
205 {
206     return 31;
207 }
208 
getMaxTablesInSelect()209 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTablesInSelect(  )
210 {
211     return 0; // 0 means no limit
212 }
213 
214 
doesMaxRowSizeIncludeBlobs()215 sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs(  )
216 {
217     return false;
218 }
219 
220 // ---- Identifiers -----------------------------------------------------------
221 // Only quoted identifiers are case sensitive, unquoted are case insensitive
getIdentifierQuoteString()222 OUString SAL_CALL ODatabaseMetaData::getIdentifierQuoteString()
223 {
224     return u"\""_ustr;
225 }
226 
supportsMixedCaseQuotedIdentifiers()227 sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseQuotedIdentifiers(  )
228 {
229     return true;
230 }
231 
storesLowerCaseQuotedIdentifiers()232 sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers()
233 {
234     return false;
235 }
236 
storesMixedCaseQuotedIdentifiers()237 sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseQuotedIdentifiers()
238 {
239     // TODO: confirm this -- the documentation is highly ambiguous
240     // However it seems this should be true as quoted identifiers ARE
241     // stored mixed case.
242     return true;
243 }
244 
storesUpperCaseQuotedIdentifiers()245 sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers()
246 {
247     return false;
248 }
249 
250 // ---- Unquoted Identifiers -------------------------------------------------
251 // All unquoted identifiers are stored upper case.
supportsMixedCaseIdentifiers()252 sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers()
253 {
254     return false;
255 }
256 
storesLowerCaseIdentifiers()257 sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers()
258 {
259     return false;
260 }
261 
storesMixedCaseIdentifiers()262 sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers()
263 {
264     return false;
265 }
266 
storesUpperCaseIdentifiers()267 sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers()
268 {
269     return true;
270 }
271 
272 // ---- SQL Feature Support ---------------------------------------------------
supportsCoreSQLGrammar()273 sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar()
274 {
275     return true;
276 }
277 
supportsMinimumSQLGrammar()278 sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar()
279 {
280     return true;
281 }
282 
supportsAlterTableWithAddColumn()283 sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithAddColumn()
284 {
285     return true;
286 }
287 
supportsAlterTableWithDropColumn()288 sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithDropColumn()
289 {
290     return true;
291 }
292 
supportsPositionedDelete()293 sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete()
294 {
295     return true;
296 }
297 
supportsPositionedUpdate()298 sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate()
299 {
300     return true;
301 }
302 
supportsOuterJoins()303 sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins()
304 {
305     return true;
306 }
307 
supportsSelectForUpdate()308 sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate()
309 {
310     return true;
311 }
312 
allTablesAreSelectable()313 sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable()
314 {
315     // TODO: true if embedded, but unsure about remote server
316     return true;
317 }
318 
supportsConvert(sal_Int32,sal_Int32)319 sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert(sal_Int32,
320                                                      sal_Int32)
321 {
322     return false;
323 }
324 
supportsTypeConversion()325 sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion()
326 {
327     return false;
328 }
329 
supportsColumnAliasing()330 sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing()
331 {
332     return true;
333 }
334 
supportsTableCorrelationNames()335 sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames()
336 {
337     return true;
338 }
339 
getMaxIndexLength()340 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength(  )
341 {
342     return 0; // 0 means no limit
343 }
344 
supportsNonNullableColumns()345 sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns(  )
346 {
347     return true;
348 }
349 
getExtraNameCharacters()350 OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters(  )
351 {
352     return OUString();
353 }
354 
supportsDifferentTableCorrelationNames()355 sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames(  )
356 {
357     return false;
358 }
359 // ---- Data definition stuff -------------------------------------------------
dataDefinitionIgnoredInTransactions()360 sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions()
361 {
362     return false;
363 }
364 
dataDefinitionCausesTransactionCommit()365 sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit()
366 {
367     return true;
368 }
369 
supportsDataManipulationTransactionsOnly()370 sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly()
371 {
372     return true;
373 }
374 
375 sal_Bool SAL_CALL ODatabaseMetaData::
supportsDataDefinitionAndDataManipulationTransactions()376         supportsDataDefinitionAndDataManipulationTransactions()
377 {
378     return false;
379 }
380 //----- Transaction Support --------------------------------------------------
supportsTransactions()381 sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions()
382 {
383     return true;
384 }
385 
supportsOpenStatementsAcrossRollback()386 sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback()
387 {
388     return false;
389 }
390 
supportsOpenStatementsAcrossCommit()391 sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit()
392 {
393     return false;
394 }
395 
supportsOpenCursorsAcrossCommit()396 sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit()
397 {
398     return false;
399 }
400 
supportsOpenCursorsAcrossRollback()401 sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback()
402 {
403     return false;
404 }
405 
supportsMultipleTransactions()406 sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions()
407 {
408     return true;
409 }
410 
supportsTransactionIsolationLevel(sal_Int32 aLevel)411 sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel(
412         sal_Int32 aLevel)
413 {
414     return  aLevel == TransactionIsolation::READ_UNCOMMITTED
415            || aLevel == TransactionIsolation::READ_COMMITTED
416            || aLevel == TransactionIsolation::REPEATABLE_READ
417            || aLevel == TransactionIsolation::SERIALIZABLE;
418 }
419 
getDefaultTransactionIsolation()420 sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation()
421 {
422     return TransactionIsolation::REPEATABLE_READ;
423 }
424 
425 
supportsANSI92FullSQL()426 sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL(  )
427 {
428     return false;
429 }
430 
supportsANSI92EntryLevelSQL()431 sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL(  )
432 {
433     return true; // should be supported at least
434 }
435 
supportsIntegrityEnhancementFacility()436 sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility(  )
437 {
438     return true;
439 }
440 
getMaxStatements()441 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatements(  )
442 {
443     return 0; // 0 means no limit
444 }
445 
getMaxProcedureNameLength()446 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength(  )
447 {
448     return 31; // TODO: confirm
449 }
450 
allProceduresAreCallable()451 sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable(  )
452 {
453     return false;
454 }
455 
supportsStoredProcedures()456 sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures(  )
457 {
458     return true;
459 }
460 
isReadOnly()461 sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly(  )
462 {
463     return m_pConnection->isReadOnly();
464 }
465 
usesLocalFiles()466 sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles(  )
467 {
468     return m_pConnection->isEmbedded();
469 }
470 
usesLocalFilePerTable()471 sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable(  )
472 {
473     return false;
474 }
475 
nullPlusNonNullIsNull()476 sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull(  )
477 {
478     return false;
479 }
480 
supportsExpressionsInOrderBy()481 sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy(  )
482 {
483     return false;
484 }
485 
supportsGroupBy()486 sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy(  )
487 {
488     return true;
489 }
490 
supportsGroupByBeyondSelect()491 sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect(  )
492 {
493     // Unsure
494     return true;
495 }
496 
supportsGroupByUnrelated()497 sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated(  )
498 {
499     // Unsure
500     return false;
501 }
502 
503 
supportsMultipleResultSets()504 sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets(  )
505 {
506     return false;
507 }
508 
supportsLikeEscapeClause()509 sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause(  )
510 {
511     return false;
512 }
513 
supportsOrderByUnrelated()514 sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated(  )
515 {
516     return true;
517 }
518 
supportsUnion()519 sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion(  )
520 {
521     return true;
522 }
523 
supportsUnionAll()524 sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll(  )
525 {
526     return true;
527 }
528 
nullsAreSortedAtEnd()529 sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd(  )
530 {
531     return false;
532 }
533 
nullsAreSortedAtStart()534 sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart(  )
535 {
536     return false;
537 }
538 
nullsAreSortedHigh()539 sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh(  )
540 {
541     return false;
542 }
543 
nullsAreSortedLow()544 sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow(  )
545 {
546     return false;
547 }
548 
supportsCorrelatedSubqueries()549 sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries(  )
550 {
551     return false;
552 }
553 
supportsSubqueriesInComparisons()554 sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons(  )
555 {
556     return false;
557 }
558 
supportsSubqueriesInExists()559 sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists(  )
560 {
561     return false;
562 }
563 
supportsSubqueriesInIns()564 sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns(  )
565 {
566     return false;
567 }
568 
supportsSubqueriesInQuantifieds()569 sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds(  )
570 {
571     return false;
572 }
573 
supportsANSI92IntermediateSQL()574 sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL(  )
575 {
576     return false;
577 }
578 
getURL()579 OUString SAL_CALL ODatabaseMetaData::getURL()
580 {
581     return m_pConnection->getConnectionURL();
582 }
583 
getUserName()584 OUString SAL_CALL ODatabaseMetaData::getUserName(  )
585 {
586     return OUString();
587 }
588 
getDriverName()589 OUString SAL_CALL ODatabaseMetaData::getDriverName(  )
590 {
591     return OUString();
592 }
593 
getDriverVersion()594 OUString SAL_CALL ODatabaseMetaData::getDriverVersion()
595 {
596     return OUString();
597 }
598 
getDatabaseProductVersion()599 OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion(  )
600 {
601     uno::Reference< XStatement > xSelect = m_pConnection->createStatement();
602 
603     uno::Reference< XResultSet > xRs = xSelect->executeQuery(u"SELECT rdb$get_context('SYSTEM', 'ENGINE_VERSION') as version from rdb$database"_ustr);
604     (void)xRs->next(); // first and only row
605     uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
606     return xRow->getString(1);
607 }
608 
getDatabaseProductName()609 OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName(  )
610 {
611     return u"Firebird (engine12)"_ustr;
612 }
613 
getProcedureTerm()614 OUString SAL_CALL ODatabaseMetaData::getProcedureTerm(  )
615 {
616     return OUString();
617 }
618 
getDriverMajorVersion()619 sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion(  )
620 {
621     return 1;
622 }
623 
getDriverMinorVersion()624 sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion(  )
625 {
626     return 0;
627 }
628 
getSQLKeywords()629 OUString SAL_CALL ODatabaseMetaData::getSQLKeywords(  )
630 {
631     return OUString();
632 }
633 
getSearchStringEscape()634 OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape(  )
635 {
636     return OUString();
637 }
638 
getStringFunctions()639 OUString SAL_CALL ODatabaseMetaData::getStringFunctions(  )
640 {
641     return u"ASCII_CHAR,ASCII_VAL,BIT_LENGTH,CHAR_LENGTH,CHAR_TO_UUID,CHARACTER_LENGTH,"
642            "GEN_UUID,HASH,LEFT,LOWER,LPAD,OCTET_LENGTH,OVERLAY,POSITION,REPLACE,REVERSE,"
643            "RIGHT,RPAD,SUBSTRING,TRIM,UPPER,UUID_TO_CHAR"_ustr;
644 }
645 
getTimeDateFunctions()646 OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions(  )
647 {
648     return u"CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,DATEADD, DATEDIFF,"
649            "EXTRACT,'NOW','TODAY','TOMORROW','YESTERDAY'"_ustr;
650 }
651 
getSystemFunctions()652 OUString SAL_CALL ODatabaseMetaData::getSystemFunctions(  )
653 {
654     return OUString();
655 }
656 
getNumericFunctions()657 OUString SAL_CALL ODatabaseMetaData::getNumericFunctions(  )
658 {
659     return u"ABS,ACOS,ASIN,ATAN,ATAN2,BIN_AND,BIN_NOT,BIN_OR,BIN_SHL,"
660            "BIN_SHR,BIN_XOR,CEIL,CEILING,COS,COSH,COT,EXP,FLOOR,LN,"
661            "LOG,LOG10,MOD,PI,POWER,RAND,ROUND,SIGN,SIN,SINH,SQRT,TAN,TANH,TRUNC"_ustr;
662 }
663 
supportsExtendedSQLGrammar()664 sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar(  )
665 {
666     return false;
667 }
668 
supportsFullOuterJoins()669 sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins(  )
670 {
671     return false;
672 }
673 
supportsLimitedOuterJoins()674 sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins(  )
675 {
676     return false;
677 }
678 
getMaxColumnsInGroupBy()679 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy(  )
680 {
681     return 0; // 0 means no limit
682 }
683 
getMaxColumnsInOrderBy()684 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy(  )
685 {
686     return 0; // 0 means no limit
687 }
688 
getMaxColumnsInSelect()689 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect(  )
690 {
691     return 0; // 0 means no limit
692 }
693 
getMaxUserNameLength()694 sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength(  )
695 {
696     return 31;
697 }
698 
supportsResultSetType(sal_Int32 setType)699 sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType(sal_Int32 setType)
700 {
701     switch (setType)
702     {
703         case ResultSetType::FORWARD_ONLY:
704             return true;
705         default:
706             return false;
707     }
708 }
709 
supportsResultSetConcurrency(sal_Int32 aResultSetType,sal_Int32 aConcurrency)710 sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency(
711         sal_Int32 aResultSetType,
712         sal_Int32 aConcurrency)
713 {
714     if (aResultSetType == ResultSetType::FORWARD_ONLY
715         && aConcurrency == ResultSetConcurrency::READ_ONLY)
716         return true;
717     else
718         return false;
719 }
720 
ownUpdatesAreVisible(sal_Int32)721 sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 )
722 {
723     return false;
724 }
725 
ownDeletesAreVisible(sal_Int32)726 sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 )
727 {
728     return false;
729 }
730 
ownInsertsAreVisible(sal_Int32)731 sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 )
732 {
733     return false;
734 }
735 
othersUpdatesAreVisible(sal_Int32)736 sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 )
737 {
738     return false;
739 }
740 
othersDeletesAreVisible(sal_Int32)741 sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 )
742 {
743     return false;
744 }
745 
othersInsertsAreVisible(sal_Int32)746 sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 )
747 {
748     return false;
749 }
750 
updatesAreDetected(sal_Int32)751 sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 )
752 {
753     return false;
754 }
755 
deletesAreDetected(sal_Int32)756 sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 )
757 {
758     return false;
759 }
760 
insertsAreDetected(sal_Int32)761 sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 )
762 {
763     return false;
764 }
765 
supportsBatchUpdates()766 sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates()
767 {
768     // No batch support in firebird
769     return false;
770 }
771 
getConnection()772 uno::Reference< XConnection > SAL_CALL ODatabaseMetaData::getConnection()
773 {
774     return m_pConnection;
775 }
776 
getConnectionInfo()777 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL ODatabaseMetaData::getConnectionInfo()
778 {
779     // TODO IMPLEMENT
780     return Sequence< ::css::beans::PropertyValue >();
781 }
782 
autoCommitFailureClosesAllResultSets()783 sal_Bool SAL_CALL ODatabaseMetaData::autoCommitFailureClosesAllResultSets()
784 {
785     // TODO IMPLEMENT
786     return false;
787 }
788 
generatedKeyAlwaysReturned()789 sal_Bool SAL_CALL ODatabaseMetaData::generatedKeyAlwaysReturned()
790 {
791     // TODO IMPLEMENT
792     return false;
793 }
794 
getAttributes(const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &)795 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getAttributes( const ::rtl::OUString& /* catalog */,
796                            const ::rtl::OUString& /* schemaPattern */,
797                            const ::rtl::OUString& /* typeNamePattern */,
798                            const ::rtl::OUString& /* attributeNamePattern */)
799 {
800     // TODO IMPLEMENT
801     return nullptr;
802 }
803 
getClientInfoProperties()804 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getClientInfoProperties()
805 {
806     // TODO IMPLEMENT
807     return nullptr;
808 }
809 
getDatabaseMajorVersion()810 ::sal_Int32 SAL_CALL ODatabaseMetaData::getDatabaseMajorVersion()
811 {
812     // TODO IMPLEMENT
813     return 0;
814 }
815 
getDatabaseMinorVersion()816 ::sal_Int32 SAL_CALL ODatabaseMetaData::getDatabaseMinorVersion()
817 {
818     // TODO IMPLEMENT
819     return 0;
820 }
821 
getFunctions(const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString & functionNamePattern)822 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getFunctions( const ::rtl::OUString& /* catalog */, const ::rtl::OUString& /* schemaPattern */, const ::rtl::OUString& functionNamePattern )
823 {
824     OUString strQuery(
825             "SELECT "
826             " null as FUNCTION_CAT,"
827             "RDB$FUNCTION_NAME as FUNCTION_NAME,"
828             "RDB$DESCRIPTION as REMARKS,"
829             "cast(null as blob sub_type text) as JB_FUNCTION_SOURCE,"
830             "'UDF' as JB_FUNCTION_KIND,"
831             "trim(trailing from RDB$MODULE_NAME) as JB_MODULE_NAME,"
832             "trim(trailing from RDB$ENTRYPOINT) as JB_ENTRYPOINT,"
833             "cast(null as varchar(255)) as JB_ENGINE_NAME "
834             "FROM RDB$FUNCTIONS "
835             "WHERE RDB$FUNCTION_NAME = '" + functionNamePattern + "'");
836 
837     uno::Reference< XStatement > statement = m_pConnection->createStatement();
838     uno::Reference< XResultSet > rs = statement->executeQuery(strQuery);
839     return rs;
840 }
841 
getFunctionColumns(const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &)842 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getFunctionColumns( const ::rtl::OUString& /* catalog */, const ::rtl::OUString& /* schemaPattern */, const ::rtl::OUString& /* functionNamePattern */, const ::rtl::OUString& /* columnNamePattern */ )
843 {
844     // TODO IMPLEMENT
845     return nullptr;
846 }
847 
getMaxLogicalLobSize()848 ::sal_Int32 SAL_CALL ODatabaseMetaData::getMaxLogicalLobSize()
849 {
850     // TODO IMPLEMENT
851     return 0;
852 }
853 
getPseudoColumns(const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &)854 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPseudoColumns( const ::rtl::OUString& /* catalog */,
855                              const ::rtl::OUString& /* schemaPattern */,
856                              const ::rtl::OUString& /* tableNamePattern */,
857                              const ::rtl::OUString& /* columnNamePattern */)
858 {
859     // TODO IMPLEMENT
860     return nullptr;
861 }
862 
getResultSetHoldability()863 ::sal_Int32 SAL_CALL ODatabaseMetaData::getResultSetHoldability()
864 {
865     // TODO IMPLEMENT
866     return 0;
867 }
868 
getRowIdLifetime()869 ::sal_Int32 SAL_CALL ODatabaseMetaData::getRowIdLifetime()
870 {
871     // TODO IMPLEMENT
872     return 0;
873 }
874 
getSchemasFiltered(const::css::beans::Optional<::rtl::OUString> &,const::css::beans::Optional<::rtl::OUString> &)875 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemasFiltered( const ::css::beans::Optional< ::rtl::OUString >& /* catalog */,
876                                  const ::css::beans::Optional< ::rtl::OUString >& /* schemaPattern */)
877 {
878     // TODO IMPLEMENT
879     return nullptr;
880 }
881 
getSQLStateType()882 ::sal_Int32 SAL_CALL ODatabaseMetaData::getSQLStateType()
883 {
884     // TODO IMPLEMENT
885     return 0;
886 }
887 
getSuperTables(const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &)888 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSuperTables( const ::rtl::OUString& /* catalog */,
889                          const ::rtl::OUString& /* schemaPattern */, const ::rtl::OUString& /* tableNamePattern */)
890 {
891     // TODO IMPLEMENT
892     return nullptr;
893 }
894 
getSuperTypes(const::rtl::OUString &,const::rtl::OUString &,const::rtl::OUString &)895 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSuperTypes( const ::rtl::OUString& /* catalog */,
896                       const ::rtl::OUString& /* schemaPattern */,
897                       const ::rtl::OUString& /* typeNamePattern */)
898 {
899     // TODO IMPLEMENT
900     return nullptr;
901 }
902 
locatorsUpdateCopy()903 ::sal_Bool SAL_CALL ODatabaseMetaData::locatorsUpdateCopy()
904 {
905     // TODO IMPLEMENT
906     return false;
907 }
908 
supportsConvertInGeneral()909 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsConvertInGeneral()
910 {
911     // TODO IMPLEMENT
912     return false;
913 }
914 
supportsGetGeneratedKeys()915 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsGetGeneratedKeys()
916 {
917     // TODO IMPLEMENT
918     return false;
919 }
920 
supportsMultipleOpenResults()921 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleOpenResults()
922 {
923     // TODO IMPLEMENT
924     return false;
925 }
926 
supportsNamedParameters()927 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsNamedParameters()
928 {
929     // TODO IMPLEMENT
930     return false;
931 }
932 
supportsRefCursors()933 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsRefCursors()
934 {
935     // TODO IMPLEMENT
936     return false;
937 }
938 
supportsSavepoints()939 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsSavepoints()
940 {
941     // TODO IMPLEMENT
942     return false;
943 }
944 
supportsSharding()945 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsSharding()
946 {
947     // TODO IMPLEMENT
948     return false;
949 }
950 
supportsStatementPooling()951 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsStatementPooling()
952 {
953     // TODO IMPLEMENT
954     return false;
955 }
956 
supportsStoredFunctionsUsingCallSyntax()957 ::sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredFunctionsUsingCallSyntax()
958 {
959     // TODO IMPLEMENT
960     return false;
961 }
962 
963 // here follow all methods which return a resultset
964 // the first methods is an example implementation how to use this resultset
965 // of course you could implement it on your and you should do this because
966 // the general way is more memory expensive
967 
getTableTypes()968 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes(  )
969 {
970     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
971         ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes);
972 
973     ODatabaseMetaDataResultSet::ORows aResults;
974     ODatabaseMetaDataResultSet::ORow aRow(2);
975 
976     aRow[0] = new ORowSetValueDecorator(); // unused
977 
978     // TODO Put these statics to one place
979     // like postgreSQL's Statics class.
980 
981     aRow[1] = new ORowSetValueDecorator(u"TABLE"_ustr);
982     aResults.push_back(aRow);
983 
984     aRow[1] = new ORowSetValueDecorator(u"VIEW"_ustr);
985     aResults.push_back(aRow);
986 
987     aRow[1] = new ORowSetValueDecorator(u"SYSTEM TABLE"_ustr);
988     aResults.push_back(std::move(aRow));
989 
990     pResultSet->setRows(std::move(aResults));
991     return pResultSet;
992 }
993 
getTypeInfo()994 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo()
995 {
996     SAL_INFO("connectivity.firebird", "getTypeInfo()");
997 
998     // this returns an empty resultset where the column-names are already set
999     // in special the metadata of the resultset already returns the right columns
1000     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet =
1001             new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo);
1002     static ODatabaseMetaDataResultSet::ORows aResults = []()
1003     {
1004         ODatabaseMetaDataResultSet::ORows tmp;
1005         ODatabaseMetaDataResultSet::ORow aRow(19);
1006 
1007         // Common data
1008         aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); // Literal quote marks
1009         aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); // Literal quote marks
1010         aRow[7] = new ORowSetValueDecorator(ORowSetValue(true)); // Nullable
1011         aRow[8] = new ORowSetValueDecorator(ORowSetValue(true)); // Case sensitive
1012         aRow[10] = new ORowSetValueDecorator(ORowSetValue(false)); // Is unsigned
1013         // FIXED_PREC_SCALE: docs state "can it be a money value? " however
1014         // in reality this causes Base to treat all numbers as money formatted
1015         // by default which is wrong (and formatting as money value is still
1016         // possible for all values).
1017         aRow[11] = new ORowSetValueDecorator(ORowSetValue(false));
1018         // Localised Type Name -- TODO: implement (but can be null):
1019         aRow[13] = new ORowSetValueDecorator();
1020         aRow[16] = new ORowSetValueDecorator();             // Unused
1021         aRow[17] = new ORowSetValueDecorator();             // Unused
1022         aRow[18] = new ORowSetValueDecorator(sal_Int16(10));// Radix
1023 
1024         // Char
1025         aRow[1] = new ORowSetValueDecorator(u"CHAR"_ustr);
1026         aRow[2] = new ORowSetValueDecorator(DataType::CHAR);
1027         aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
1028         aRow[6] = new ORowSetValueDecorator(u"length"_ustr); // Create Params
1029         aRow[9] = new ORowSetValueDecorator(
1030                 sal_Int16(ColumnSearch::FULL)); // Searchable
1031         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1032         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1033         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1034         tmp.push_back(aRow);
1035 
1036         // Varchar
1037         aRow[1] = new ORowSetValueDecorator(u"VARCHAR"_ustr);
1038         aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR);
1039         aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
1040         aRow[6] = new ORowSetValueDecorator(u"length"_ustr); // Create Params
1041         aRow[9] = new ORowSetValueDecorator(
1042                 sal_Int16(ColumnSearch::FULL)); // Searchable
1043         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1044         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1045         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1046         tmp.push_back(aRow);
1047 
1048         // Binary (CHAR); we use the Firebird synonym CHARACTER
1049         // to fool LO into seeing it as different types.
1050         // It is distinguished from Text type by its character set OCTETS;
1051         // that will be added by Tables::createStandardColumnPart
1052         aRow[1] = new ORowSetValueDecorator(u"CHARACTER"_ustr);
1053         aRow[2] = new ORowSetValueDecorator(DataType::BINARY);
1054         aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
1055         aRow[6] = new ORowSetValueDecorator(u"length"_ustr); // Create Params
1056         aRow[9] = new ORowSetValueDecorator(
1057                 sal_Int16(ColumnSearch::NONE)); // Searchable
1058         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1059         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1060         tmp.push_back(aRow);
1061 
1062         // Varbinary (VARCHAR); see comment above about BINARY
1063         aRow[1] = new ORowSetValueDecorator(u"CHARACTER VARYING"_ustr);
1064         aRow[2] = new ORowSetValueDecorator(DataType::VARBINARY);
1065         aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length
1066         aRow[6] = new ORowSetValueDecorator(u"length"_ustr); // Create Params
1067         aRow[9] = new ORowSetValueDecorator(
1068                 sal_Int16(ColumnSearch::NONE)); // Searchable
1069 
1070         // Clob (SQL_BLOB)
1071         aRow[1] = new ORowSetValueDecorator(u"BLOB SUB_TYPE TEXT"_ustr); // BLOB, with subtype 1
1072         aRow[2] = new ORowSetValueDecorator(DataType::CLOB);
1073         aRow[3] = new ORowSetValueDecorator(sal_Int32(2147483647)); // Precision = max length
1074         aRow[6] = new ORowSetValueDecorator(); // Create Params
1075         aRow[9] = new ORowSetValueDecorator(
1076                 sal_Int16(ColumnSearch::FULL)); // Searchable
1077         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1078         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1079         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1080         tmp.push_back(aRow);
1081 
1082         // Longvarbinary (SQL_BLOB)
1083         // Distinguished from simple blob with a user-defined subtype.
1084         aRow[1] = new ORowSetValueDecorator(OUString("BLOB SUB_TYPE " + OUString::number(static_cast<short>(BlobSubtype::Image))) ); // BLOB, with subtype 0
1085         aRow[2] = new ORowSetValueDecorator(DataType::LONGVARBINARY);
1086         tmp.push_back(aRow);
1087 
1088         // Integer Types common
1089         {
1090             aRow[6] = new ORowSetValueDecorator(); // Create Params
1091             aRow[9] = new ORowSetValueDecorator(
1092                 sal_Int16(ColumnSearch::FULL)); // Searchable
1093             aRow[12] = new ORowSetValueDecorator(ORowSetValue(true)); // Autoincrement
1094             aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1095             aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1096         }
1097         // Smallint (SQL_SHORT)
1098         aRow[1] = new ORowSetValueDecorator(u"SMALLINT"_ustr);
1099         aRow[2] = new ORowSetValueDecorator(DataType::SMALLINT);
1100         aRow[3] = new ORowSetValueDecorator(sal_Int16(5)); // Prevision
1101         tmp.push_back(aRow);
1102         // Integer (SQL_LONG)
1103         aRow[1] = new ORowSetValueDecorator(u"INTEGER"_ustr);
1104         aRow[2] = new ORowSetValueDecorator(DataType::INTEGER);
1105         aRow[3] = new ORowSetValueDecorator(sal_Int16(10)); // Precision
1106         tmp.push_back(aRow);
1107         // Bigint (SQL_INT64)
1108         aRow[1] = new ORowSetValueDecorator(u"BIGINT"_ustr);
1109         aRow[2] = new ORowSetValueDecorator(DataType::BIGINT);
1110         aRow[3] = new ORowSetValueDecorator(sal_Int16(20)); // Precision
1111         tmp.push_back(aRow);
1112 
1113         // Decimal Types common
1114         {
1115             aRow[9] = new ORowSetValueDecorator(
1116                 sal_Int16(ColumnSearch::FULL)); // Searchable
1117             aRow[12] = new ORowSetValueDecorator(ORowSetValue(true)); // Autoincrement
1118         }
1119 
1120         aRow[6] = new ORowSetValueDecorator(u"PRECISION,SCALE"_ustr); // Create params
1121         // Numeric
1122         aRow[1] = new ORowSetValueDecorator(u"NUMERIC"_ustr);
1123         aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC);
1124         aRow[3] = new ORowSetValueDecorator(sal_Int16(18)); // Precision
1125         aRow[14] = new ORowSetValueDecorator(sal_Int16(0)); // Minimum scale
1126         aRow[15] = new ORowSetValueDecorator(sal_Int16(18)); // Max scale
1127         tmp.push_back(aRow);
1128         // Decimal
1129         aRow[1] = new ORowSetValueDecorator(u"DECIMAL"_ustr);
1130         aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL);
1131         aRow[3] = new ORowSetValueDecorator(sal_Int16(18)); // Precision
1132         aRow[14] = new ORowSetValueDecorator(sal_Int16(0)); // Minimum scale
1133         aRow[15] = new ORowSetValueDecorator(sal_Int16(18)); // Max scale
1134         tmp.push_back(aRow);
1135 
1136         aRow[6] = new ORowSetValueDecorator(); // Create Params
1137         // Float (SQL_FLOAT)
1138         aRow[1] = new ORowSetValueDecorator(u"FLOAT"_ustr);
1139         aRow[2] = new ORowSetValueDecorator(DataType::FLOAT);
1140         aRow[3] = new ORowSetValueDecorator(sal_Int16(7)); // Precision
1141         aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
1142         aRow[15] = new ORowSetValueDecorator(sal_Int16(7)); // Max scale
1143         tmp.push_back(aRow);
1144         // Double (SQL_DOUBLE)
1145         aRow[1] = new ORowSetValueDecorator(u"DOUBLE PRECISION"_ustr);
1146         aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE);
1147         aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision
1148         aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale
1149         aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale
1150         tmp.push_back(aRow);
1151 
1152         // TODO: no idea whether D_FLOAT corresponds to an sql type
1153 
1154         // SQL_TIMESTAMP
1155         aRow[1] = new ORowSetValueDecorator(u"TIMESTAMP"_ustr);
1156         aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP);
1157         aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
1158         aRow[6] = new ORowSetValueDecorator(); // Create Params
1159         aRow[9] = new ORowSetValueDecorator(
1160                 sal_Int16(ColumnSearch::FULL)); // Searchable
1161         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1162         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1163         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1164         tmp.push_back(aRow);
1165 
1166         // SQL_TYPE_TIME
1167         aRow[1] = new ORowSetValueDecorator(u"TIME"_ustr);
1168         aRow[2] = new ORowSetValueDecorator(DataType::TIME);
1169         aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
1170         aRow[6] = new ORowSetValueDecorator(); // Create Params
1171         aRow[9] = new ORowSetValueDecorator(
1172                 sal_Int16(ColumnSearch::FULL)); // Searchable
1173         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1174         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1175         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1176         tmp.push_back(aRow);
1177 
1178         // SQL_TYPE_DATE
1179         aRow[1] = new ORowSetValueDecorator(u"DATE"_ustr);
1180         aRow[2] = new ORowSetValueDecorator(DataType::DATE);
1181         aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length
1182         aRow[6] = new ORowSetValueDecorator(); // Create Params
1183         aRow[9] = new ORowSetValueDecorator(
1184                 sal_Int16(ColumnSearch::FULL)); // Searchable
1185         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1186         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1187         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1188         tmp.push_back(aRow);
1189 
1190         // SQL_BLOB
1191         aRow[1] = new ORowSetValueDecorator(u"BLOB SUB_TYPE BINARY"_ustr);
1192         aRow[2] = new ORowSetValueDecorator(DataType::BLOB);
1193         aRow[3] = new ORowSetValueDecorator(sal_Int32(0)); // Prevision = max length
1194         aRow[6] = new ORowSetValueDecorator(); // Create Params
1195         aRow[9] = new ORowSetValueDecorator(
1196                 sal_Int16(ColumnSearch::NONE)); // Searchable
1197         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1198         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1199         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1200         tmp.push_back(aRow);
1201 
1202         // SQL_BOOLEAN
1203         aRow[1] = new ORowSetValueDecorator(u"BOOLEAN"_ustr);
1204         aRow[2] = new ORowSetValueDecorator(DataType::BOOLEAN);
1205         aRow[3] = new ORowSetValueDecorator(sal_Int32(1)); // Prevision = max length
1206         aRow[6] = new ORowSetValueDecorator(); // Create Params
1207         aRow[9] = new ORowSetValueDecorator(
1208                 sal_Int16(ColumnSearch::BASIC)); // Searchable
1209         aRow[12] = new ORowSetValueDecorator(ORowSetValue(false)); // Autoincrement
1210         aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale
1211         aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale
1212         tmp.push_back(std::move(aRow));
1213         return tmp;
1214     }();
1215     // [-loplugin:redundantfcast] false positive:
1216     pResultSet->setRows(ODatabaseMetaDataResultSet::ORows(aResults));
1217     return pResultSet;
1218 }
1219 
getColumnPrivileges(const Any &,const OUString &,const OUString & sTable,const OUString & sColumnNamePattern)1220 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumnPrivileges(
1221         const Any& /*aCatalog*/,
1222         const OUString& /*sSchema*/,
1223         const OUString& sTable,
1224         const OUString& sColumnNamePattern)
1225 {
1226     SAL_INFO("connectivity.firebird", "getColumnPrivileges() with "
1227              "Table: " << sTable
1228              << " & ColumnNamePattern: " << sColumnNamePattern);
1229 
1230     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
1231         ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eColumnPrivileges);
1232     uno::Reference< XStatement > statement = m_pConnection->createStatement();
1233 
1234     static const char wld[] = "%";
1235     OUStringBuffer queryBuf(
1236             "SELECT "
1237             "priv.RDB$RELATION_NAME, "  // 1 Table name
1238             "priv.RDB$GRANTOR,"         // 2
1239             "priv.RDB$USER, "           // 3 Grantee
1240             "priv.RDB$PRIVILEGE, "      // 4
1241             "priv.RDB$GRANT_OPTION, "   // 5 is Grantable
1242             "priv.RDB$FIELD_NAME "      // 6 Column name
1243             "FROM RDB$USER_PRIVILEGES priv ");
1244 
1245     {
1246         OUString sAppend = u"WHERE priv.RDB$RELATION_NAME = '%' "_ustr;
1247         queryBuf.append(sAppend.replaceAll("%", sTable));
1248     }
1249     if (!sColumnNamePattern.isEmpty())
1250     {
1251         OUString sAppend;
1252         if (sColumnNamePattern.match(wld))
1253             sAppend = "AND priv.RDB$FIELD_NAME LIKE '%' ";
1254         else
1255             sAppend = "AND priv.RDB$FIELD_NAME = '%' ";
1256 
1257         queryBuf.append(sAppend.replaceAll(wld, sColumnNamePattern));
1258     }
1259 
1260     queryBuf.append(" ORDER BY priv.RDB$FIELD, "
1261                               "priv.RDB$PRIVILEGE");
1262 
1263     OUString query = queryBuf.makeStringAndClear();
1264 
1265     uno::Reference< XResultSet > rs = statement->executeQuery(query);
1266     uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1267     ODatabaseMetaDataResultSet::ORows aResults;
1268 
1269     ODatabaseMetaDataResultSet::ORow aCurrentRow(9);
1270     aCurrentRow[0] = new ORowSetValueDecorator(); // Unused
1271     aCurrentRow[1] = new ORowSetValueDecorator(); // 1. TABLE_CAT Unsupported
1272     aCurrentRow[2] = new ORowSetValueDecorator(); // 1. TABLE_SCHEM Unsupported
1273 
1274     while( rs->next() )
1275     {
1276         // 3. TABLE_NAME
1277         aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
1278         // 4. COLUMN_NAME
1279         aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(6)));
1280         aCurrentRow[5] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); // 5. GRANTOR
1281         aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // 6. GRANTEE
1282         aCurrentRow[7] = new ORowSetValueDecorator(xRow->getString(4)); // 7. Privilege
1283         aCurrentRow[8] = new ORowSetValueDecorator( ( xRow->getShort(5) == 1 ) ?
1284                     u"YES"_ustr : u"NO"_ustr); // 8. Grantable
1285 
1286         aResults.push_back(aCurrentRow);
1287     }
1288 
1289     pResultSet->setRows( std::move(aResults) );
1290 
1291     return pResultSet;
1292 }
1293 
getColumns(const Any &,const OUString &,const OUString & tableNamePattern,const OUString & columnNamePattern)1294 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
1295         const Any& /*catalog*/,
1296         const OUString& /*schemaPattern*/,
1297         const OUString& tableNamePattern,
1298         const OUString& columnNamePattern)
1299 {
1300     SAL_INFO("connectivity.firebird", "getColumns() with "
1301              "TableNamePattern: " << tableNamePattern <<
1302              " & ColumnNamePattern: " << columnNamePattern);
1303 
1304     OUStringBuffer queryBuf("SELECT "
1305         "relfields.RDB$RELATION_NAME, " // 1
1306         "relfields.RDB$FIELD_NAME, "    // 2
1307         "relfields.RDB$DESCRIPTION,"    // 3
1308         "relfields.RDB$DEFAULT_VALUE, " // 4
1309         "relfields.RDB$FIELD_POSITION, "// 5
1310         "fields.RDB$FIELD_TYPE, "       // 6
1311         "fields.RDB$FIELD_SUB_TYPE, "   // 7
1312         "fields.RDB$FIELD_LENGTH, "     // 8
1313         "fields.RDB$FIELD_PRECISION, "  // 9
1314         "fields.RDB$FIELD_SCALE, "      // 10
1315         // Specifically use relfields null flag -- the one in fields is used
1316         // for domains, whether a specific field is nullable is set in relfields,
1317         // this is also the one we manually fiddle when changing NULL/NOT NULL
1318         // (see Table.cxx)
1319         "relfields.RDB$NULL_FLAG, "      // 11
1320         "fields.RDB$CHARACTER_LENGTH, "   // 12
1321         "charset.RDB$CHARACTER_SET_NAME " // 13
1322         "FROM RDB$RELATION_FIELDS relfields "
1323         "JOIN RDB$FIELDS fields "
1324         "on (fields.RDB$FIELD_NAME = relfields.RDB$FIELD_SOURCE) "
1325         "LEFT JOIN RDB$CHARACTER_SETS charset "
1326         "on (fields.RDB$CHARACTER_SET_ID = charset.RDB$CHARACTER_SET_ID) "
1327         "WHERE (1 = 1) ");
1328 
1329     if (!tableNamePattern.isEmpty())
1330     {
1331         OUString sAppend;
1332         if (tableNamePattern.match("%"))
1333             sAppend = "AND relfields.RDB$RELATION_NAME LIKE '%' ";
1334         else
1335             sAppend = "AND relfields.RDB$RELATION_NAME = '%' ";
1336 
1337         queryBuf.append(sAppend.replaceAll("%", tableNamePattern));
1338     }
1339 
1340     if (!columnNamePattern.isEmpty())
1341     {
1342         OUString sAppend;
1343         if (columnNamePattern.match("%"))
1344             sAppend = "AND relfields.RDB$FIELD_NAME LIKE '%' ";
1345         else
1346             sAppend = "AND relfields.RDB$FIELD_NAME = '%' ";
1347 
1348         queryBuf.append(sAppend.replaceAll("%", columnNamePattern));
1349     }
1350 
1351     OUString query = queryBuf.makeStringAndClear();
1352 
1353     uno::Reference< XStatement > statement = m_pConnection->createStatement();
1354     uno::Reference< XResultSet > rs = statement->executeQuery(query);
1355     uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1356 
1357     ODatabaseMetaDataResultSet::ORows aResults;
1358     ODatabaseMetaDataResultSet::ORow aCurrentRow(19);
1359 
1360     aCurrentRow[0] =  new ORowSetValueDecorator(); // Unused -- numbering starts from 0
1361     aCurrentRow[1] =  new ORowSetValueDecorator(); // Catalog - can be null
1362     aCurrentRow[2] =  new ORowSetValueDecorator(); // Schema - can be null
1363     aCurrentRow[8] =  new ORowSetValueDecorator(); // Unused
1364     aCurrentRow[10] = new ORowSetValueDecorator(sal_Int32(10)); // Radix: fixed in FB
1365     aCurrentRow[14] = new ORowSetValueDecorator(); // Unused
1366     aCurrentRow[15] = new ORowSetValueDecorator(); // Unused
1367 
1368     while( rs->next() )
1369     {
1370         // 3. TABLE_NAME
1371         aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
1372         // 4. Column Name
1373         aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2)));
1374         // 5. Datatype
1375         short aType = getFBTypeFromBlrType(xRow->getShort(6));
1376         short aScale = xRow->getShort(10);
1377         OUString sCharsetName = xRow->getString(13);
1378         // result field may be filled with spaces
1379         sCharsetName = sCharsetName.trim();
1380         ColumnTypeInfo aInfo(aType, xRow->getShort(7), aScale,
1381                 sCharsetName);
1382 
1383         aCurrentRow[5] = new ORowSetValueDecorator(aInfo.getSdbcType());
1384         // 6. Typename (SQL_*)
1385         aCurrentRow[6] = new ORowSetValueDecorator(aInfo.getColumnTypeName());
1386 
1387         // 7. Column Sizes
1388         {
1389             sal_Int32 aColumnSize = 0;
1390             switch (aType)
1391             {
1392                 case SQL_TEXT:
1393                 case SQL_VARYING:
1394                     aColumnSize = xRow->getShort(12);
1395                     break;
1396                 case SQL_SHORT:
1397                 case SQL_LONG:
1398                 case SQL_FLOAT:
1399                 case SQL_DOUBLE:
1400                 case SQL_D_FLOAT:
1401                 case SQL_INT64:
1402                 case SQL_QUAD:
1403                     aColumnSize = xRow->getShort(9);
1404                     break;
1405                 case SQL_TIMESTAMP:
1406                 case SQL_BLOB:
1407                 case SQL_ARRAY:
1408                 case SQL_TYPE_TIME:
1409                 case SQL_TYPE_DATE:
1410                 case SQL_NULL:
1411                     // TODO: implement.
1412                     break;
1413             }
1414             aCurrentRow[7] = new ORowSetValueDecorator(aColumnSize);
1415         }
1416 
1417         // 9. Decimal digits (scale)
1418         // fb stores a negative number
1419         aCurrentRow[9] = new ORowSetValueDecorator( static_cast<sal_Int16>(-aScale) );
1420 
1421         // 11. Nullable
1422         if (xRow->getShort(11))
1423         {
1424             aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NO_NULLS);
1425         }
1426         else
1427         {
1428             aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NULLABLE);
1429         }
1430         // 12. Comments -- may be omitted
1431         {
1432             OUString aDescription;
1433             uno::Reference< XBlob > xBlob = xRow->getBlob(3);
1434             if (xBlob.is())
1435             {
1436                 const sal_Int64 aBlobLength = xBlob->length();
1437                 if (aBlobLength > SAL_MAX_INT32)
1438                 {
1439                     SAL_WARN("connectivity.firebird", "getBytes can't return " << aBlobLength << " bytes but only max " << SAL_MAX_INT32);
1440                     aDescription = OUString(reinterpret_cast<char*>(xBlob->getBytes(1, SAL_MAX_INT32).getArray()),
1441                                             SAL_MAX_INT32,
1442                                             RTL_TEXTENCODING_UTF8);
1443                 }
1444                 else
1445                 {
1446                     aDescription = OUString(reinterpret_cast<char*>(xBlob->getBytes(1, static_cast<sal_Int32>(aBlobLength)).getArray()),
1447                                             aBlobLength,
1448                                             RTL_TEXTENCODING_UTF8);
1449                 }
1450             }
1451             aCurrentRow[12] = new ORowSetValueDecorator(aDescription);
1452         }
1453         // 13. Default --  may be omitted.
1454         {
1455             uno::Reference< XBlob > xDefaultValueBlob = xRow->getBlob(4);
1456             if (xDefaultValueBlob.is())
1457             {
1458                 // TODO: Implement
1459             }
1460             aCurrentRow[13] = new ORowSetValueDecorator();
1461         }
1462 
1463         // 16. Bytes in Column for char
1464         if (aType == SQL_TEXT)
1465         {
1466             aCurrentRow[16] = new ORowSetValueDecorator(xRow->getShort(8));
1467         }
1468         else if (aType == SQL_VARYING)
1469         {
1470             aCurrentRow[16] = new ORowSetValueDecorator(sal_Int32(32767));
1471         }
1472         else
1473         {
1474             aCurrentRow[16] = new ORowSetValueDecorator(sal_Int32(0));
1475         }
1476         // 17. Index of column
1477         {
1478             short nColumnNumber = xRow->getShort(5);
1479             // Firebird stores column numbers beginning with 0 internally
1480             // SDBC expects column numbering to begin with 1.
1481             aCurrentRow[17] = new ORowSetValueDecorator(sal_Int32(nColumnNumber + 1));
1482         }
1483         // 18. Is nullable
1484         if (xRow->getShort(9))
1485         {
1486             aCurrentRow[18] = new ORowSetValueDecorator(u"NO"_ustr);
1487         }
1488         else
1489         {
1490             aCurrentRow[18] = new ORowSetValueDecorator(u"YES"_ustr);
1491         }
1492 
1493         aResults.push_back(aCurrentRow);
1494     }
1495     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
1496             ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eColumns);
1497     pResultSet->setRows( std::move(aResults) );
1498 
1499     return pResultSet;
1500 }
1501 
getTables(const Any &,const OUString &,const OUString & tableNamePattern,const Sequence<OUString> & types)1502 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables(
1503         const Any& /*catalog*/,
1504         const OUString& /*schemaPattern*/,
1505         const OUString& tableNamePattern,
1506         const Sequence< OUString >& types)
1507 {
1508     SAL_INFO("connectivity.firebird", "getTables() with "
1509              "TableNamePattern: " << tableNamePattern);
1510 
1511     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
1512         ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables);
1513     uno::Reference< XStatement > statement = m_pConnection->createStatement();
1514 
1515     static const char wld[] = "%";
1516     OUStringBuffer queryBuf(
1517             "SELECT "
1518             "RDB$RELATION_NAME, "
1519             "RDB$SYSTEM_FLAG, "
1520             "RDB$RELATION_TYPE, "
1521             "RDB$DESCRIPTION, "
1522             "RDB$VIEW_BLR "
1523             "FROM RDB$RELATIONS "
1524             "WHERE ");
1525 
1526     // TODO: GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, SYNONYM
1527     if (!types.hasElements() || (types.getLength() == 1 && types[0].match(wld)))
1528     {
1529         // from Firebird: src/jrd/constants.h
1530         // rel_persistent = 0, rel_view = 1, rel_external = 2
1531         // All table types? I.e. includes system tables.
1532         queryBuf.append("(RDB$RELATION_TYPE = 0 OR RDB$RELATION_TYPE = 1 OR RDB$RELATION_TYPE = 2) ");
1533     }
1534     else
1535     {
1536         queryBuf.append("( (0 = 1) ");
1537         for (OUString const & t : types)
1538         {
1539             if (t == "SYSTEM TABLE")
1540                 queryBuf.append("OR (RDB$SYSTEM_FLAG = 1 AND RDB$VIEW_BLR IS NULL) ");
1541             else if (t == "TABLE")
1542                 queryBuf.append("OR (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0 AND RDB$VIEW_BLR IS NULL) ");
1543             else if (t == "VIEW")
1544                 queryBuf.append("OR (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0 AND RDB$VIEW_BLR IS NOT NULL) ");
1545             else
1546                 throw SQLException(); // TODO: implement other types, see above.
1547         }
1548         queryBuf.append(") ");
1549     }
1550 
1551     if (!tableNamePattern.isEmpty())
1552     {
1553         OUString sAppend;
1554         if (tableNamePattern.match(wld))
1555             sAppend = "AND RDB$RELATION_NAME LIKE '%' ";
1556         else
1557             sAppend = "AND RDB$RELATION_NAME = '%' ";
1558 
1559         queryBuf.append(sAppend.replaceAll(wld, tableNamePattern));
1560     }
1561 
1562     queryBuf.append(" ORDER BY RDB$RELATION_TYPE, RDB$RELATION_NAME");
1563 
1564     OUString query = queryBuf.makeStringAndClear();
1565 
1566     uno::Reference< XResultSet > rs = statement->executeQuery(query);
1567     uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1568     ODatabaseMetaDataResultSet::ORows aResults;
1569 
1570     ODatabaseMetaDataResultSet::ORow aCurrentRow(6);
1571     aCurrentRow[0] = new ORowSetValueDecorator(); // 0. Unused
1572     aCurrentRow[1] = new ORowSetValueDecorator(); // 1. Table_Cat Unsupported
1573     aCurrentRow[2] = new ORowSetValueDecorator(); // 2. Table_Schem Unsupported
1574 
1575     while( rs->next() )
1576     {
1577         // 3. TABLE_NAME
1578         aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
1579         // 4. TABLE_TYPE
1580         {
1581             // TODO: check this as the docs are a bit unclear.
1582             sal_Int16 nSystemFlag = xRow->getShort(2);
1583             sal_Int16 nTableType  = xRow->getShort(3);
1584             xRow->getBlob(5); // We have to retrieve a column to verify it is null.
1585             bool aIsView      = !xRow->wasNull();
1586             OUString sTableType;
1587 
1588             if (nSystemFlag == 1)
1589             {
1590                 sTableType = "SYSTEM TABLE";
1591             }
1592             else if (aIsView)
1593             {
1594                 sTableType = "VIEW";
1595             }
1596             else
1597             {
1598                 // see above about src/jrd/constants.h
1599                 if (nTableType == 0 || nTableType == 2)
1600                     sTableType = "TABLE";
1601             }
1602 
1603             aCurrentRow[4] = new ORowSetValueDecorator(sTableType);
1604         }
1605         // 5. REMARKS
1606         {
1607             uno::Reference< XClob > xClob = xRow->getClob(4);
1608             if (xClob.is())
1609             {
1610                 aCurrentRow[5] = new ORowSetValueDecorator(xClob->getSubString(1, xClob->length()));
1611             }
1612         }
1613 
1614         aResults.push_back(aCurrentRow);
1615     }
1616 
1617     pResultSet->setRows( std::move(aResults) );
1618 
1619     return pResultSet;
1620 }
1621 
getProcedureColumns(const Any &,const OUString &,const OUString &,const OUString &)1622 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedureColumns(
1623     const Any&, const OUString&,
1624     const OUString&, const OUString& )
1625 {
1626     SAL_WARN("connectivity.firebird", "Not yet implemented");
1627     OSL_FAIL("Not implemented yet!");
1628     // TODO implement
1629     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eProcedureColumns);
1630 }
1631 
getProcedures(const Any &,const OUString &,const OUString &)1632 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedures(
1633     const Any&, const OUString&,
1634     const OUString& )
1635 {
1636     SAL_WARN("connectivity.firebird", "Not yet implemented");
1637     OSL_FAIL("Not implemented yet!");
1638     // TODO implement
1639     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eProcedures);
1640 }
1641 
getVersionColumns(const Any &,const OUString &,const OUString &)1642 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getVersionColumns(
1643     const Any&, const OUString&, const OUString& )
1644 {
1645     SAL_WARN("connectivity.firebird", "Not yet implemented");
1646     OSL_FAIL("Not implemented yet!");
1647     // TODO implement
1648     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eVersionColumns);
1649 }
1650 
getExportedKeys(const Any &,const OUString &,const OUString & table)1651 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getExportedKeys(
1652     const Any&, const OUString&, const OUString& table )
1653 {
1654     return ODatabaseMetaData::lcl_getKeys(false, table);
1655 }
1656 
getImportedKeys(const Any &,const OUString &,const OUString & table)1657 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getImportedKeys(
1658     const Any&, const OUString&, const OUString& table )
1659 {
1660     return ODatabaseMetaData::lcl_getKeys(true, table);
1661 }
1662 
lcl_getKeys(const bool bIsImport,std::u16string_view table)1663 uno::Reference< XResultSet > ODatabaseMetaData::lcl_getKeys(const bool bIsImport, std::u16string_view table )
1664 {
1665     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
1666         ODatabaseMetaDataResultSet(bIsImport?ODatabaseMetaDataResultSet::eImportedKeys:ODatabaseMetaDataResultSet::eExportedKeys);
1667 
1668     uno::Reference< XStatement > statement = m_pConnection->createStatement();
1669 
1670     OUString sSQL = u"SELECT "
1671            "RDB$REF_CONSTRAINTS.RDB$UPDATE_RULE, " // 1 update rule
1672            "RDB$REF_CONSTRAINTS.RDB$DELETE_RULE, " // 2 delete rule
1673            "RDB$REF_CONSTRAINTS.RDB$CONST_NAME_UQ, " // 3 primary or unique key name
1674            "RDB$REF_CONSTRAINTS.RDB$CONSTRAINT_NAME, " // 4 foreign key name
1675            "PRIM.RDB$DEFERRABLE, " // 5 deferrability
1676            "PRIM.RDB$INITIALLY_DEFERRED, " // 6 deferrability
1677            "PRIM.RDB$RELATION_NAME, " // 7 PK table name
1678            "PRIMARY_INDEX.RDB$FIELD_NAME, " // 8 PK column name
1679            "PRIMARY_INDEX.RDB$FIELD_POSITION, " // 9 PK sequence number
1680            "FOREI.RDB$RELATION_NAME, " // 10 FK table name
1681            "FOREIGN_INDEX.RDB$FIELD_NAME " // 11 FK column name
1682            "FROM RDB$REF_CONSTRAINTS "
1683            "INNER JOIN RDB$RELATION_CONSTRAINTS AS PRIM "
1684            "ON RDB$REF_CONSTRAINTS.RDB$CONST_NAME_UQ = PRIM.RDB$CONSTRAINT_NAME "
1685            "INNER JOIN RDB$RELATION_CONSTRAINTS AS FOREI "
1686            "ON RDB$REF_CONSTRAINTS.RDB$CONSTRAINT_NAME = FOREI.RDB$CONSTRAINT_NAME "
1687            "INNER JOIN RDB$INDEX_SEGMENTS AS PRIMARY_INDEX "
1688            "ON PRIM.RDB$INDEX_NAME = PRIMARY_INDEX.RDB$INDEX_NAME "
1689            "INNER JOIN RDB$INDEX_SEGMENTS AS FOREIGN_INDEX "
1690            "ON FOREI.RDB$INDEX_NAME = FOREIGN_INDEX.RDB$INDEX_NAME "
1691            "WHERE FOREI.RDB$CONSTRAINT_TYPE = 'FOREIGN KEY' "_ustr;
1692     if (bIsImport)
1693         sSQL += OUString::Concat("AND FOREI.RDB$RELATION_NAME = '")+ table +"'";
1694     else
1695         sSQL += OUString::Concat("AND PRIM.RDB$RELATION_NAME = '")+ table +"'";
1696 
1697     uno::Reference< XResultSet > rs = statement->executeQuery(sSQL);
1698     uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1699 
1700     ODatabaseMetaDataResultSet::ORows aResults;
1701     ODatabaseMetaDataResultSet::ORow aCurrentRow(15);
1702 
1703     // TODO is it necessary to initialize these?
1704     aCurrentRow[0] = new ORowSetValueDecorator(); // Unused
1705     aCurrentRow[1] = new ORowSetValueDecorator(); // PKTABLE_CAT unsupported
1706     aCurrentRow[2] = new ORowSetValueDecorator(); // PKTABLE_SCHEM unsupported
1707     aCurrentRow[5] = new ORowSetValueDecorator(); // FKTABLE_CAT unsupported
1708     aCurrentRow[6] = new ORowSetValueDecorator(); // FKTABLE_SCHEM unsupported
1709 
1710     std::map< OUString,sal_Int32> aRuleMap;
1711     aRuleMap[ u"CASCADE"_ustr] = KeyRule::CASCADE;
1712     aRuleMap[ u"RESTRICT"_ustr] = KeyRule::RESTRICT;
1713     aRuleMap[ u"SET NULL"_ustr] = KeyRule::SET_NULL;
1714     aRuleMap[ u"SET DEFAULT"_ustr] = KeyRule::SET_DEFAULT;
1715     aRuleMap[ u"NO ACTION"_ustr] = KeyRule::NO_ACTION;
1716 
1717     while(rs->next())
1718     {
1719         aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(7))); // PK table
1720         aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(8))); // PK column
1721         aCurrentRow[7] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(10))); // FK table
1722         aCurrentRow[8] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(11))); // FK column
1723 
1724         aCurrentRow[9] = new ORowSetValueDecorator(xRow->getShort(9)); // PK sequence number
1725         aCurrentRow[10] = new ORowSetValueDecorator(aRuleMap[sanitizeIdentifier(xRow->getString(1))]); // update role
1726         aCurrentRow[11] = new ORowSetValueDecorator(aRuleMap[sanitizeIdentifier(xRow->getString(2))]); // delete role
1727 
1728         aCurrentRow[12] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4))); // FK name
1729         aCurrentRow[13] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // PK name
1730 
1731         aCurrentRow[14] = new ORowSetValueDecorator(Deferrability::NONE); // deferrability
1732 
1733         // deferrability is currently not supported, but may be supported in the future.
1734         /*
1735         aCurrentRow[14] = (xRow->getString(5) == "NO" ?
1736                           new ORowSetValueDecorator(Deferrability::NONE)
1737                         : (xRow->getString(6) == "NO" ?
1738                             new ORowSetValueDecorator(Deferrability::INITIALLY_IMMEDIATE)
1739                           : new ORowSetValueDecorator(Deferrability::INITIALLY_DEFERRED));
1740         */
1741 
1742         aResults.push_back(aCurrentRow);
1743     }
1744 
1745     pResultSet->setRows( std::move(aResults) );
1746     return pResultSet;
1747 }
1748 
getPrimaryKeys(const Any &,const OUString &,const OUString & sTable)1749 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys(
1750         const Any& /*aCatalog*/,
1751         const OUString& /*sSchema*/,
1752         const OUString& sTable)
1753 {
1754     SAL_INFO("connectivity.firebird", "getPrimaryKeys() with "
1755              "Table: " << sTable);
1756 
1757     OUString sAppend = u"WHERE constr.RDB$RELATION_NAME = '%' "_ustr;
1758     OUString sQuery = "SELECT "
1759         "constr.RDB$RELATION_NAME, "    // 1. Table Name
1760         "inds.RDB$FIELD_NAME, "         // 2. Column Name
1761         "inds.RDB$FIELD_POSITION, "     // 3. Sequence Number
1762         "constr.RDB$CONSTRAINT_NAME "   // 4 Constraint name
1763         "FROM RDB$RELATION_CONSTRAINTS constr "
1764         "JOIN RDB$INDEX_SEGMENTS inds "
1765         "on (constr.RDB$INDEX_NAME = inds.RDB$INDEX_NAME) " +
1766         sAppend.replaceAll("%", sTable) +
1767         "AND constr.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
1768                     "ORDER BY inds.RDB$FIELD_NAME";
1769 
1770     uno::Reference< XStatement > xStatement = m_pConnection->createStatement();
1771     uno::Reference< XResultSet > xRs = xStatement->executeQuery(sQuery);
1772     uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
1773 
1774     ODatabaseMetaDataResultSet::ORows aResults;
1775     ODatabaseMetaDataResultSet::ORow aCurrentRow(7);
1776 
1777     aCurrentRow[0] =  new ORowSetValueDecorator(); // Unused -- numbering starts from 0
1778     aCurrentRow[1] =  new ORowSetValueDecorator(); // Catalog - can be null
1779     aCurrentRow[2] =  new ORowSetValueDecorator(); // Schema - can be null
1780 
1781     while(xRs->next())
1782     {
1783         // 3. Table Name
1784         if (xRs->getRow() == 1) // Table name doesn't change, so only retrieve once
1785         {
1786             aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
1787         }
1788         // 4. Column Name
1789         aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2)));
1790         // 5. KEY_SEQ (which key in the sequence)
1791         aCurrentRow[5] = new ORowSetValueDecorator(xRow->getShort(3));
1792         // 6. Primary Key Name
1793         aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4)));
1794 
1795         aResults.push_back(aCurrentRow);
1796     }
1797     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
1798             ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::ePrimaryKeys);
1799     pResultSet->setRows( std::move(aResults) );
1800 
1801     return pResultSet;
1802 }
1803 
getIndexInfo(const Any &,const OUString &,const OUString & sTable,sal_Bool bIsUnique,sal_Bool)1804 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo(
1805         const Any& /*aCatalog*/,
1806         const OUString& /*sSchema*/,
1807         const OUString& sTable,
1808         sal_Bool bIsUnique,
1809         sal_Bool) // TODO: what is bIsApproximate?
1810 
1811 {
1812     // Apparently this method can also return a "tableIndexStatistic"
1813     // However this is only mentioned in XDatabaseMetaData.idl (whose comments
1814     // are duplicated in the postgresql driver), and is otherwise undocumented.
1815     SAL_INFO("connectivity.firebird", "getPrimaryKeys() with "
1816              "Table: " << sTable);
1817 
1818     OUStringBuffer aQueryBuf("SELECT "
1819         "indices.RDB$RELATION_NAME, "               // 1. Table Name
1820         "index_segments.RDB$FIELD_NAME, "           // 2. Column Name
1821         "index_segments.RDB$FIELD_POSITION, "       // 3. Sequence Number
1822         "indices.RDB$INDEX_NAME, "                  // 4. Index name
1823         "indices.RDB$UNIQUE_FLAG, "                 // 5. Unique Flag
1824         "indices.RDB$INDEX_TYPE "                   // 6. Index Type
1825         "FROM RDB$INDICES indices "
1826         "JOIN RDB$INDEX_SEGMENTS index_segments "
1827         "on (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) "
1828         "WHERE indices.RDB$RELATION_NAME = '" + sTable + "' "
1829         "AND (indices.RDB$SYSTEM_FLAG = 0) ");
1830     // Not sure whether we should exclude system indices, but otoh. we never
1831     // actually deal with system tables (system indices only apply to system
1832     // tables) within the GUI.
1833 
1834     // Only filter if true (according to the docs), i.e.:
1835     // If false we return all indices, if true we return only unique indices
1836     if (bIsUnique)
1837         aQueryBuf.append("AND (indices.RDB$UNIQUE_FLAG = 1) ");
1838 
1839     OUString sQuery = aQueryBuf.makeStringAndClear();
1840 
1841     uno::Reference< XStatement > xStatement = m_pConnection->createStatement();
1842     uno::Reference< XResultSet > xRs = xStatement->executeQuery(sQuery);
1843     uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW );
1844 
1845     ODatabaseMetaDataResultSet::ORows aResults;
1846     ODatabaseMetaDataResultSet::ORow aCurrentRow(14);
1847 
1848     aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0
1849     aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null
1850     aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null
1851     aCurrentRow[5] = new ORowSetValueDecorator(); // Index Catalog -- can be null
1852     // Wikipedia indicates:
1853     // 'Firebird makes all indices of the database behave like well-tuned "clustered indexes" used by other architectures.'
1854     // but it's not "CLUSTERED", neither "STATISTIC" nor "HASHED" (the other specific types from offapi/com/sun/star/sdbc/IndexType.idl)
1855     // According to https://www.ibphoenix.com/resources/documents/design/doc_18,
1856     // it seems another type => OTHER
1857     aCurrentRow[7] = new ORowSetValueDecorator(IndexType::OTHER); // 7. INDEX TYPE
1858     aCurrentRow[13] = new ORowSetValueDecorator(); // Filter Condition -- can be null
1859 
1860     while(xRs->next())
1861     {
1862         // 3. Table Name
1863         if (xRs->getRow() == 1) // Table name doesn't change, so only retrieve once
1864         {
1865             aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
1866         }
1867 
1868         // 4. NON_UNIQUE -- i.e. specifically negate here.
1869         aCurrentRow[4] = new ORowSetValueDecorator(ORowSetValue(xRow->getShort(5) == 0));
1870         // 6. INDEX NAME
1871         aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4)));
1872 
1873         // 8. ORDINAL POSITION
1874         aCurrentRow[8] = new ORowSetValueDecorator(xRow->getShort(3));
1875         // 9. COLUMN NAME
1876         aCurrentRow[9] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2)));
1877         // 10. ASC(ending)/DESC(ending)
1878         if (xRow->getShort(6) == 1)
1879             aCurrentRow[10] = new ORowSetValueDecorator(u"D"_ustr);
1880         else
1881             aCurrentRow[10] = new ORowSetValueDecorator(u"A"_ustr);
1882         // TODO: double check this^^^, doesn't seem to be officially documented anywhere.
1883         // 11. CARDINALITY
1884         aCurrentRow[11] = new ORowSetValueDecorator(sal_Int32(0)); // TODO: determine how to do this
1885         // 12. PAGES
1886         aCurrentRow[12] = new ORowSetValueDecorator(sal_Int32(0)); // TODO: determine how to do this
1887 
1888         aResults.push_back(aCurrentRow);
1889     }
1890     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
1891             ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eIndexInfo);
1892     pResultSet->setRows( std::move(aResults) );
1893 
1894     return pResultSet;
1895 }
1896 
getBestRowIdentifier(const Any &,const OUString &,const OUString &,sal_Int32,sal_Bool)1897 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getBestRowIdentifier(
1898     const Any&, const OUString&, const OUString&, sal_Int32,
1899     sal_Bool )
1900 {
1901     OSL_FAIL("Not implemented yet!");
1902     // TODO implement
1903     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eBestRowIdentifier);
1904 }
1905 
getTablePrivileges(const Any &,const OUString &,const OUString & sTableNamePattern)1906 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges(
1907         const Any& /*aCatalog*/,
1908         const OUString& /*sSchemaPattern*/,
1909         const OUString& sTableNamePattern)
1910 {
1911     SAL_INFO("connectivity.firebird", "getTablePrivileges() with "
1912              "TableNamePattern: " << sTableNamePattern);
1913 
1914     rtl::Reference<ODatabaseMetaDataResultSet> pResultSet = new
1915         ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTablePrivileges);
1916     uno::Reference< XStatement > statement = m_pConnection->createStatement();
1917 
1918     // TODO: column specific privileges are included, we may need
1919     // to have WHERE RDB$FIELD_NAME = NULL or similar.
1920     static const char wld[] = "%";
1921     OUStringBuffer queryBuf(
1922             "SELECT "
1923             "priv.RDB$RELATION_NAME, "  // 1
1924             "priv.RDB$GRANTOR,"         // 2
1925             "priv.RDB$USER, "           // 3 Grantee
1926             "priv.RDB$PRIVILEGE, "      // 4
1927             "priv.RDB$GRANT_OPTION "    // 5 is Grantable
1928             "FROM RDB$USER_PRIVILEGES priv ");
1929 
1930     if (!sTableNamePattern.isEmpty())
1931     {
1932         OUString sAppend;
1933         if (sTableNamePattern.match(wld))
1934             sAppend = "WHERE priv.RDB$RELATION_NAME LIKE '%' ";
1935         else
1936             sAppend = "WHERE priv.RDB$RELATION_NAME = '%' ";
1937 
1938         queryBuf.append(sAppend.replaceAll(wld, sTableNamePattern));
1939     }
1940     queryBuf.append(" ORDER BY priv.RDB$RELATION_TYPE, "
1941                               "priv.RDB$RELATION_NAME, "
1942                               "priv.RDB$PRIVILEGE");
1943 
1944     OUString query = queryBuf.makeStringAndClear();
1945 
1946     uno::Reference< XResultSet > rs = statement->executeQuery(query);
1947     uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1948     ODatabaseMetaDataResultSet::ORows aResults;
1949 
1950     ODatabaseMetaDataResultSet::ORow aRow(8);
1951     aRow[0] = new ORowSetValueDecorator(); // Unused
1952     aRow[1] = new ORowSetValueDecorator(); // TABLE_CAT unsupported
1953     aRow[2] = new ORowSetValueDecorator(); // TABLE_SCHEM unsupported.
1954 
1955     while( rs->next() )
1956     {
1957         // 3. TABLE_NAME
1958         aRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1)));
1959         aRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); // 4. GRANTOR
1960         aRow[5] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // 5. GRANTEE
1961         aRow[6] = new ORowSetValueDecorator(xRow->getString(4)); // 6. Privilege
1962         aRow[7] = new ORowSetValueDecorator(ORowSetValue(bool(xRow->getBoolean(5)))); // 7. Is Grantable
1963 
1964         aResults.push_back(aRow);
1965     }
1966 
1967     pResultSet->setRows( std::move(aResults) );
1968 
1969     return pResultSet;
1970 }
1971 
getCrossReference(const Any &,const OUString &,const OUString &,const Any &,const OUString &,const OUString &)1972 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCrossReference(
1973     const Any&, const OUString&,
1974     const OUString&, const Any&,
1975     const OUString&, const OUString& )
1976 {
1977     OSL_FAIL("Not implemented yet!");
1978     // TODO implement
1979     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eCrossReference);
1980 }
1981 
getUDTs(const Any &,const OUString &,const OUString &,const Sequence<sal_Int32> &)1982 uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any&, const OUString&, const OUString&, const Sequence< sal_Int32 >& )
1983 {
1984     OSL_FAIL("Not implemented yet!");
1985     // TODO implement
1986     return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eUDTs);
1987 }
1988 
1989 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
1990