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