1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * Effective License of whole file:
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
25 * Copyright: 2000 by Sun Microsystems, Inc.
27 * Contributor(s): Joerg Budischewski
29 * All parts contributed on or after August 2011:
31 * This Source Code Form is subject to the terms of the Mozilla Public
32 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
35 * Some portions were adapted from JDBC PostgreSQL driver:
37 * Copyright (c) 2004-2008, PostgreSQL Global Development Group
39 * Licence of original JDBC driver code:
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions are met:
44 * 1. Redistributions of source code must retain the above copyright notice,
45 * this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright notice,
47 * this list of conditions and the following disclaimer in the documentation
48 * and/or other materials provided with the distribution.
49 * 3. Neither the name of the PostgreSQL Global Development Group nor the names
50 * of its contributors may be used to endorse or promote products derived
51 * from this software without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
57 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
58 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
59 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
60 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
61 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
62 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63 * POSSIBILITY OF SUCH DAMAGE.
65 ************************************************************************/
68 #include <string_view>
70 #include <sal/log.hxx>
71 #include "pq_databasemetadata.hxx"
72 #include "pq_driver.hxx"
73 #include "pq_sequenceresultset.hxx"
74 #include "pq_statics.hxx"
75 #include "pq_tools.hxx"
77 #include <o3tl/string_view.hxx>
78 #include <rtl/ustrbuf.hxx>
79 #include <sal/macros.h>
80 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
81 #include <com/sun/star/sdbc/ResultSetType.hpp>
82 #include <com/sun/star/sdbc/XParameters.hpp>
83 #include <com/sun/star/sdbc/DataType.hpp>
84 #include <com/sun/star/sdbc/IndexType.hpp>
85 #include <com/sun/star/sdbc/ColumnValue.hpp>
86 #include <com/sun/star/sdbc/ColumnSearch.hpp>
89 using ::osl::MutexGuard
;
92 using namespace com::sun::star::sdbc
;
94 using com::sun::star::uno::Reference
;
95 using com::sun::star::uno::Sequence
;
96 using com::sun::star::uno::Any
;
97 using com::sun::star::uno::UNO_QUERY
;
98 using com::sun::star::uno::UNO_QUERY_THROW
;
100 namespace pq_sdbc_driver
102 // These are pre-processor versions of KeyRule.idl declarations
103 // These are inherited from JDBC, and thus won't change anytime soon.
104 // Having them as pre-processor definitions allows to include them
105 // into compile-time strings (through SAL_STRINGIFY), which can be passed to ASCII_STR.
106 // That is without resorting to horrendous hacks in template meta-programming.
107 #define KEYRULE_CASCADE 0
108 #define KEYRULE_RESTRICT 1
109 #define KEYRULE_SET_NULL 2
110 #define KEYRULE_NO_ACTION 4
111 #define KEYRULE_SET_DEFAULT 4
112 // Ditto for Deferrability.idl
113 #define DEFERRABILITY_INITIALLY_DEFERRED 5
114 #define DEFERRABILITY_INITIALLY_IMMEDIATE 6
115 #define DEFERRABILITY_NONE 7
117 DatabaseMetaData::DatabaseMetaData(
118 ::rtl::Reference
< comphelper::RefCountedMutex
> refMutex
,
119 css::uno::Reference
< css::sdbc::XConnection
> origin
,
120 ConnectionSettings
*pSettings
)
121 : m_xMutex(std::move( refMutex
)),
122 m_pSettings( pSettings
),
123 m_origin(std::move( origin
)),
124 m_getIntSetting_stmt ( m_origin
->prepareStatement(u
"SELECT setting FROM pg_catalog.pg_settings WHERE name=?"_ustr
) )
126 init_getReferences_stmt();
127 init_getPrivs_stmt();
130 sal_Bool
DatabaseMetaData::allProceduresAreCallable( )
136 sal_Bool
DatabaseMetaData::allTablesAreSelectable( )
141 OUString
DatabaseMetaData::getURL( )
144 // LEM TODO: implement
148 OUString
DatabaseMetaData::getUserName( )
150 return m_pSettings
->user
;
153 sal_Bool
DatabaseMetaData::isReadOnly( )
159 sal_Bool
DatabaseMetaData::nullsAreSortedHigh( )
161 // Whether NULL values are considered, for sorting purposes, LARGER than any other value.
162 // Specification: http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#nullsAreSortedHigh()
163 // PostgreSQL behaviour: http://www.postgresql.org/docs/9.1/static/queries-order.html
167 sal_Bool
DatabaseMetaData::nullsAreSortedLow( )
169 return ! nullsAreSortedHigh();
172 sal_Bool
DatabaseMetaData::nullsAreSortedAtStart( )
177 sal_Bool
DatabaseMetaData::nullsAreSortedAtEnd( )
182 OUString
DatabaseMetaData::getDatabaseProductName( )
184 return u
"PostgreSQL"_ustr
;
187 OUString
DatabaseMetaData::getDatabaseProductVersion( )
189 return OUString::createFromAscii( PQparameterStatus( m_pSettings
->pConnection
, "server_version" ) );
191 OUString
DatabaseMetaData::getDriverName( )
193 return u
"postgresql-sdbc"_ustr
;
196 OUString
DatabaseMetaData::getDriverVersion( )
198 return PQ_SDBC_DRIVER_VERSION
;
201 sal_Int32
DatabaseMetaData::getDriverMajorVersion( )
203 return PQ_SDBC_MAJOR
;
206 sal_Int32
DatabaseMetaData::getDriverMinorVersion( )
208 return PQ_SDBC_MINOR
;
211 sal_Bool
DatabaseMetaData::usesLocalFiles( )
214 // https://wiki.documentfoundation.org/Documentation/DevGuide/Database_Access#XDatabaseMetaData_Interface
215 // says "Returns true when the catalog name of the
216 // database should not appear in the DatasourceBrowser
217 // of LibreOffice API, otherwise false is returned."
218 // So, hmmm, think about it.
222 sal_Bool
DatabaseMetaData::usesLocalFilePerTable( )
227 sal_Bool
DatabaseMetaData::supportsMixedCaseIdentifiers( )
232 sal_Bool
DatabaseMetaData::storesUpperCaseIdentifiers( )
237 sal_Bool
DatabaseMetaData::storesLowerCaseIdentifiers( )
243 sal_Bool
DatabaseMetaData::storesMixedCaseIdentifiers( )
249 sal_Bool
DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
254 sal_Bool
DatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
260 sal_Bool
DatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
266 sal_Bool
DatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
272 OUString
DatabaseMetaData::getIdentifierQuoteString( )
277 OUString
DatabaseMetaData::getSQLKeywords( )
279 // In Java 6, this is all keywords that are not SQL:2003
280 // In Java 2 v1.4 and as per LibreOffice SDK doc, this is all keywords that are not SQL92
281 // I understand this to mean "reserved keywords" only.
282 // See http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
283 // LEM TODO: consider using pg_get_keywords(), filter on catcode
288 "ASYMMETRIC," //SQL:2003
291 "CURRENT_CATALOG," //SQL:2008
292 "CURRENT_ROLE," //SQL:1999
293 "CURRENT_SCHEMA," //SQL:2008
298 "LIMIT," //SQL:1999; non-reserved in SQL:2003
299 "LOCALTIME," //SQL:1999
300 "LOCALTIMESTAMP," //SQL:1999
304 "PLACING," //non-reserved in SQL:2003
305 "RETURNING," //non-reserved in SQL:2008
306 "SIMILAR," //SQL:2003
309 "WINDOW"_ustr
//SQL:2003
312 OUString
DatabaseMetaData::getNumericFunctions( )
314 // See https://www.postgresql.org/docs/9.1/static/functions-math.html
315 // LEM TODO: Err... https://wiki.documentfoundation.org/Documentation/DevGuide/Database_Access#Support_Scalar_Functions
316 // says this should be "Open Group CLI" names, not PostgreSQL names.
317 // Currently this is just a list of supported functions in PostgreSQL, with PostgreSQL names.
318 // And it is my job to map from Open Group CLI names/syntax to PostgreSQL names/syntax. Where? By parsing the SQL???
319 // Should look at what the JDBC driver is doing.
353 OUString
DatabaseMetaData::getStringFunctions( )
355 // See http://www.postgresql.org/docs/9.1/static/functions-string.html
384 "pg_client_encoding,"
390 "regexp_split_to_array,"
391 "regexp_split_to_table,"
407 OUString
DatabaseMetaData::getSystemFunctions( )
409 // See http://www.postgresql.org/docs/9.1/static/functions-info.html
410 // and http://www.postgresql.org/docs/9.1/static/functions-admin.html
424 "pg_is_other_temp_schema,"
425 "pg_listening_channels,"
427 "pg_postmaster_start_time,"
431 "has_any_column_privilege,"
432 "has_any_column_privilege,"
433 "has_any_column_privilege,"
434 "has_column_privilege,"
435 "has_database_privilege,"
436 "has_foreign_data_wrapper_privilege,"
437 "has_function_privilege,"
438 "has_language_privilege,"
439 "has_schema_privilege,"
440 "has_sequence_privilege,"
441 "has_server_privilege,"
442 "has_table_privilege,"
443 "has_tablespace_privilege,"
445 "pg_collation_is_visible,"
446 "pg_conversion_is_visible,"
447 "pg_function_is_visible,"
448 "pg_opclass_is_visible,"
449 "pg_operator_is_visible,"
450 "pg_table_is_visible,"
451 "pg_ts_config_is_visible,"
452 "pg_ts_dict_is_visible,"
453 "pg_ts_parser_is_visible,"
454 "pg_ts_template_is_visible,"
455 "pg_type_is_visible,"
457 "pg_describe_object,"
458 "pg_get_constraintdef,"
460 "pg_get_functiondef,"
461 "pg_get_function_arguments,"
462 "pg_get_function_identity_arguments,"
463 "pg_get_function_result,"
467 "pg_get_serial_sequence,"
471 "pg_options_to_table,"
472 "pg_tablespace_databases,"
478 "txid_current_snapshot,"
480 "txid_snapshot_xmax,"
481 "txid_snapshot_xmin,"
482 "txid_visible_in_snapshot,"
491 "pg_terminate_backend,"
492 "pg_create_restore_point,"
493 "pg_current_xlog_insert_location,"
494 "pg_current_xlog_location,"
499 "pg_xlogfile_name_offset,"
501 "pg_last_xlog_receive_location,"
502 "pg_last_xlog_replay_location,"
503 "pg_last_xact_replay_timestamp,"
504 "pg_is_xlog_replay_paused,"
505 "pg_xlog_replay_pause,"
506 "pg_xlog_replay_resume,"
513 "pg_tablespace_size,"
514 "pg_tablespace_size,"
515 "pg_total_relation_size,"
516 "pg_relation_filenode,"
517 "pg_relation_filepath,"
520 "pg_read_binary_file,"
523 "pg_advisory_lock_shared,"
524 "pg_advisory_unlock,"
525 "pg_advisory_unlock_all,"
526 "pg_advisory_unlock_shared,"
527 "pg_advisory_xact_lock,"
528 "pg_advisory_xact_lock_shared,"
529 "pg_try_advisory_lock,"
530 "pg_try_advisory_lock_shared,"
531 "pg_try_advisory_xact_lock,"
532 "pg_try_advisory_xact_lock_shared,"
536 OUString
DatabaseMetaData::getTimeDateFunctions( )
560 "statement_timestamp,"
562 "transaction_timestamp,"_ustr
565 OUString
DatabaseMetaData::getSearchStringEscape( )
569 OUString
DatabaseMetaData::getExtraNameCharacters( )
574 sal_Bool
DatabaseMetaData::supportsAlterTableWithAddColumn( )
579 sal_Bool
DatabaseMetaData::supportsAlterTableWithDropColumn( )
584 sal_Bool
DatabaseMetaData::supportsColumnAliasing( )
589 sal_Bool
DatabaseMetaData::nullPlusNonNullIsNull( )
594 sal_Bool
DatabaseMetaData::supportsTypeConversion( )
596 // LEM: this is specifically whether the "CONVERT" function is supported
597 // It seems that in PostgreSQL, that function is only for string encoding, so no.
601 sal_Bool
DatabaseMetaData::supportsConvert( sal_Int32
, sal_Int32
)
606 sal_Bool
DatabaseMetaData::supportsTableCorrelationNames( )
608 // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..."
613 sal_Bool
DatabaseMetaData::supportsDifferentTableCorrelationNames( )
617 sal_Bool
DatabaseMetaData::supportsExpressionsInOrderBy( )
622 sal_Bool
DatabaseMetaData::supportsOrderByUnrelated( )
627 sal_Bool
DatabaseMetaData::supportsGroupBy( )
632 sal_Bool
DatabaseMetaData::supportsGroupByUnrelated( )
637 sal_Bool
DatabaseMetaData::supportsGroupByBeyondSelect( )
642 sal_Bool
DatabaseMetaData::supportsLikeEscapeClause( )
647 sal_Bool
DatabaseMetaData::supportsMultipleResultSets( )
652 sal_Bool
DatabaseMetaData::supportsMultipleTransactions( )
654 // Allows multiple transactions open at once (on different connections!)
658 sal_Bool
DatabaseMetaData::supportsNonNullableColumns( )
664 sal_Bool
DatabaseMetaData::supportsMinimumSQLGrammar( )
669 sal_Bool
DatabaseMetaData::supportsCoreSQLGrammar( )
671 // LEM: jdbc driver says not, although the comments in it seem old
672 // fdo#45249 Base query design won't use any aggregate function
673 // (except COUNT(*) unless we say yes, so say yes.
674 // Actually, Base assumes *also* support for aggregate functions "collect, fusion, intersection"
675 // as soon as supportsCoreSQLGrammar() returns true.
676 // Those are *not* Core SQL, though. They are in optional feature S271 "Basic multiset support"
680 sal_Bool
DatabaseMetaData::supportsExtendedSQLGrammar( )
685 sal_Bool
DatabaseMetaData::supportsANSI92EntryLevelSQL( )
690 sal_Bool
DatabaseMetaData::supportsANSI92IntermediateSQL( )
692 // LEM: jdbc driver says not, although the comments in it seem old
696 sal_Bool
DatabaseMetaData::supportsANSI92FullSQL( )
698 // LEM: jdbc driver says not, although the comments in it seem old
702 sal_Bool
DatabaseMetaData::supportsIntegrityEnhancementFacility( )
704 // LEM: jdbc driver says yes, although comment says they are not sure what this means...
708 sal_Bool
DatabaseMetaData::supportsOuterJoins( )
713 sal_Bool
DatabaseMetaData::supportsFullOuterJoins( )
718 sal_Bool
DatabaseMetaData::supportsLimitedOuterJoins( )
724 OUString
DatabaseMetaData::getSchemaTerm( )
726 return u
"SCHEMA"_ustr
;
729 OUString
DatabaseMetaData::getProcedureTerm( )
731 return u
"function"_ustr
;
734 OUString
DatabaseMetaData::getCatalogTerm( )
736 return u
"DATABASE"_ustr
;
739 sal_Bool
DatabaseMetaData::isCatalogAtStart( )
744 OUString
DatabaseMetaData::getCatalogSeparator( )
749 sal_Bool
DatabaseMetaData::supportsSchemasInDataManipulation( )
754 sal_Bool
DatabaseMetaData::supportsSchemasInProcedureCalls( )
759 sal_Bool
DatabaseMetaData::supportsSchemasInTableDefinitions( )
764 sal_Bool
DatabaseMetaData::supportsSchemasInIndexDefinitions( )
769 sal_Bool
DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
774 sal_Bool
DatabaseMetaData::supportsCatalogsInDataManipulation( )
779 sal_Bool
DatabaseMetaData::supportsCatalogsInProcedureCalls( )
784 sal_Bool
DatabaseMetaData::supportsCatalogsInTableDefinitions( )
790 sal_Bool
DatabaseMetaData::supportsCatalogsInIndexDefinitions( )
796 sal_Bool
DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
802 // LEM TODO: positioned (through cursor) updates and deletes seem
803 // to be supported; see {UPDATE,DELETE} /table/ (...) WHERE CURRENT OF /cursor_name/" syntax
804 // and http://www.postgresql.org/docs/9.1/static/view-pg-cursors.html
805 // http://www.postgresql.org/docs/9.1/static/libpq-example.html actually uses a cursor :)
806 sal_Bool
DatabaseMetaData::supportsPositionedDelete( )
808 // LEM: jdbc driver says not, although the comments in it seem old
812 sal_Bool
DatabaseMetaData::supportsPositionedUpdate( )
814 // LEM: jdbc driver says not, although the comments in it seem old
819 sal_Bool
DatabaseMetaData::supportsSelectForUpdate( )
825 sal_Bool
DatabaseMetaData::supportsStoredProcedures( )
831 sal_Bool
DatabaseMetaData::supportsSubqueriesInComparisons( )
836 sal_Bool
DatabaseMetaData::supportsSubqueriesInExists( )
841 sal_Bool
DatabaseMetaData::supportsSubqueriesInIns( )
846 sal_Bool
DatabaseMetaData::supportsSubqueriesInQuantifieds( )
848 // LEM: jdbc driver says yes, although comment says they don't know what this means...
852 sal_Bool
DatabaseMetaData::supportsCorrelatedSubqueries( )
856 sal_Bool
DatabaseMetaData::supportsUnion( )
861 sal_Bool
DatabaseMetaData::supportsUnionAll( )
866 sal_Bool
DatabaseMetaData::supportsOpenCursorsAcrossCommit( )
871 sal_Bool
DatabaseMetaData::supportsOpenCursorsAcrossRollback( )
876 sal_Bool
DatabaseMetaData::supportsOpenStatementsAcrossCommit( )
880 sal_Bool
DatabaseMetaData::supportsOpenStatementsAcrossRollback( )
885 sal_Int32
DatabaseMetaData::getMaxBinaryLiteralLength( )
890 sal_Int32
DatabaseMetaData::getMaxCharLiteralLength( )
895 // Copied / adapted / simplified from JDBC driver
896 sal_Int32
DatabaseMetaData::getIntSetting(const OUString
& settingName
)
898 MutexGuard
guard( m_xMutex
->GetMutex() );
900 Reference
< XParameters
> params(m_getIntSetting_stmt
, UNO_QUERY_THROW
);
901 params
->setString(1, settingName
);
902 Reference
< XResultSet
> rs
= m_getIntSetting_stmt
->executeQuery();
903 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
904 OSL_VERIFY(rs
->next());
905 OSL_ENSURE(rs
->isFirst(), "postgresql-sdbc DatabaseMetaData getIntSetting not on first row");
906 OSL_ENSURE(rs
->isLast(), "postgresql-sdbc DatabaseMetaData getIntSetting not on last row");
907 return xRow
->getInt(1);
910 sal_Int32
DatabaseMetaData::getMaxNameLength()
912 if ( m_pSettings
->maxNameLen
== 0)
913 m_pSettings
->maxNameLen
= getIntSetting( u
"max_identifier_length"_ustr
);
914 OSL_ENSURE(m_pSettings
->maxNameLen
, "postgresql-sdbc: maxNameLen is zero");
915 return m_pSettings
->maxNameLen
;
918 sal_Int32
DatabaseMetaData::getMaxIndexKeys()
920 if ( m_pSettings
->maxIndexKeys
== 0)
921 m_pSettings
->maxIndexKeys
= getIntSetting(u
"max_index_keys"_ustr
);
922 OSL_ENSURE(m_pSettings
->maxIndexKeys
, "postgresql-sdbc: maxIndexKeys is zero");
923 return m_pSettings
->maxIndexKeys
;
926 sal_Int32
DatabaseMetaData::getMaxColumnNameLength( )
928 return getMaxNameLength();
931 sal_Int32
DatabaseMetaData::getMaxColumnsInGroupBy( )
936 sal_Int32
DatabaseMetaData::getMaxColumnsInIndex( )
938 return getMaxIndexKeys();
941 sal_Int32
DatabaseMetaData::getMaxColumnsInOrderBy( )
946 sal_Int32
DatabaseMetaData::getMaxColumnsInSelect( )
951 sal_Int32
DatabaseMetaData::getMaxColumnsInTable( )
956 sal_Int32
DatabaseMetaData::getMaxConnections( )
958 // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports
962 sal_Int32
DatabaseMetaData::getMaxCursorNameLength( ) //TODO, don't know
964 return getMaxNameLength();
967 sal_Int32
DatabaseMetaData::getMaxIndexLength( ) //TODO, don't know
969 // LEM: that's the index itself, not its name
973 sal_Int32
DatabaseMetaData::getMaxSchemaNameLength( )
975 return getMaxNameLength();
978 sal_Int32
DatabaseMetaData::getMaxProcedureNameLength( )
980 return getMaxNameLength();
983 sal_Int32
DatabaseMetaData::getMaxCatalogNameLength( )
985 return getMaxNameLength();
988 sal_Int32
DatabaseMetaData::getMaxRowSize( )
990 // jdbc driver says 1GB, but http://www.postgresql.org/about/ says 1.6TB
991 // and that 1GB is the maximum _field_ size
992 // The row limit does not fit into a sal_Int32
996 sal_Bool
DatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
998 // LEM: Err... PostgreSQL basically does not do BLOBs well
999 // In any case, BLOBs do not change the maximal row length AFAIK
1003 sal_Int32
DatabaseMetaData::getMaxStatementLength( )
1005 // LEM: actually, that would be 2^sizeof(size_t)-1
1006 // on the server? on the client (because of libpq)? minimum of the two? not sure
1007 // Anyway, big, so say unlimited.
1011 sal_Int32
DatabaseMetaData::getMaxStatements( ) //TODO, don't know
1016 sal_Int32
DatabaseMetaData::getMaxTableNameLength( )
1018 return getMaxNameLength();
1021 sal_Int32
DatabaseMetaData::getMaxTablesInSelect( )
1026 sal_Int32
DatabaseMetaData::getMaxUserNameLength( )
1028 return getMaxNameLength();
1031 sal_Int32
DatabaseMetaData::getDefaultTransactionIsolation( )
1033 return css::sdbc::TransactionIsolation::READ_COMMITTED
;
1036 sal_Bool
DatabaseMetaData::supportsTransactions( )
1041 sal_Bool
DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level
)
1043 if ( level
== css::sdbc::TransactionIsolation::READ_COMMITTED
1044 || level
== css::sdbc::TransactionIsolation::SERIALIZABLE
1045 || level
== css::sdbc::TransactionIsolation::READ_UNCOMMITTED
1046 || level
== css::sdbc::TransactionIsolation::REPEATABLE_READ
)
1052 sal_Bool
DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
1057 sal_Bool
DatabaseMetaData::supportsDataManipulationTransactionsOnly( )
1062 sal_Bool
DatabaseMetaData::dataDefinitionCausesTransactionCommit( )
1067 sal_Bool
DatabaseMetaData::dataDefinitionIgnoredInTransactions( )
1072 css::uno::Reference
< XResultSet
> DatabaseMetaData::getProcedures(
1073 const css::uno::Any
&,
1077 // 1. PROCEDURE_CAT string => procedure catalog (may be NULL )
1078 // 2. PROCEDURE_SCHEM string => procedure schema (may be NULL )
1079 // 3. PROCEDURE_NAME string => procedure name
1080 // 4. reserved for future use
1081 // 5. reserved for future use
1082 // 6. reserved for future use
1083 // 7. REMARKS string => explanatory comment on the procedure
1084 // 8. PROCEDURE_TYPE short => kind of procedure:
1085 // * UNKNOWN - May return a result
1086 // * NO - Does not return a result
1087 // * RETURN - Returns a result
1089 // LEM TODO: implement
1090 // LEM TODO: at least fake the columns, even if no row.
1091 MutexGuard
guard( m_xMutex
->GetMutex() );
1092 return new SequenceResultSet(
1093 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> > (), m_pSettings
->tc
);
1096 css::uno::Reference
< XResultSet
> DatabaseMetaData::getProcedureColumns(
1097 const css::uno::Any
&,
1102 MutexGuard
guard( m_xMutex
->GetMutex() );
1103 // LEM TODO: implement
1104 // LEM TODO: at least fake the columns, even if no row.
1105 return new SequenceResultSet(
1106 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1109 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTables(
1110 const css::uno::Any
&,
1111 const OUString
& schemaPattern
,
1112 const OUString
& tableNamePattern
,
1113 const css::uno::Sequence
< OUString
>& )
1115 Statics
&statics
= getStatics();
1117 MutexGuard
guard( m_xMutex
->GetMutex() );
1119 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTables() got called with " << schemaPattern
<< "." << tableNamePattern
);
1121 // ignore catalog, as a single pq connection does not support multiple catalogs
1123 // LEM TODO: this does not give the right column names, not the right number of columns, etc.
1124 // Take "inspiration" from JDBC driver
1125 // Ah, this is used to create a XResultSet manually... Try to do it directly in SQL
1126 Reference
< XPreparedStatement
> statement
= m_origin
->prepareStatement(
1128 "DISTINCT ON (pg_namespace.nspname, relname ) " // avoid duplicates (pg_settings !)
1129 "pg_namespace.nspname, relname, relkind, pg_description.description "
1130 "FROM pg_namespace, pg_class LEFT JOIN pg_description ON pg_class.oid = pg_description.objoid "
1131 "WHERE relnamespace = pg_namespace.oid "
1132 "AND ( relkind = 'r' OR relkind = 'v') "
1133 "AND pg_namespace.nspname LIKE ? "
1134 "AND relname LIKE ? "_ustr
1135 // "ORDER BY pg_namespace.nspname || relname"
1138 Reference
< XParameters
> parameters( statement
, UNO_QUERY_THROW
);
1139 parameters
->setString( 1 , schemaPattern
);
1140 parameters
->setString( 2 , tableNamePattern
);
1142 Reference
< XResultSet
> rs
= statement
->executeQuery();
1143 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1144 std::vector
< std::vector
<Any
> > vec
;
1148 std::vector
< Any
> row( 5 );
1150 row
[0] <<= m_pSettings
->catalog
;
1151 row
[1] <<= xRow
->getString( 1 );
1152 row
[2] <<= xRow
->getString( 2 );
1153 OUString type
= xRow
->getString(3);
1156 if( xRow
->getString(1) == "pg_catalog" )
1158 row
[3] <<= statics
.SYSTEM_TABLE
;
1162 row
[3] <<= statics
.TABLE
;
1165 else if( type
== "v" )
1167 row
[3] <<= statics
.VIEW
;
1171 row
[3] <<= statics
.UNKNOWN
;
1173 row
[4] <<= xRow
->getString(4);
1175 // no description in postgresql AFAIK
1176 vec
.push_back( row
);
1178 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1179 if( closeable
.is() )
1182 return new SequenceResultSet(
1183 m_xMutex
, *this, std::vector(statics
.tablesRowNames
), std::move(vec
), m_pSettings
->tc
);
1188 // sort no schema first, then "public", then normal schemas, then internal schemas
1189 int compare_schema(std::u16string_view nsA
, std::u16string_view nsB
)
1193 return nsB
.empty() ? 0 : -1;
1195 else if (nsB
.empty())
1197 assert(!nsA
.empty());
1200 else if(nsA
== u
"public")
1202 return (nsB
== u
"public") ? 0 : -1;
1204 else if(nsB
== u
"public")
1206 assert(nsA
!= u
"public");
1209 else if(o3tl::starts_with(nsA
, u
"pg_"))
1211 if(o3tl::starts_with(nsB
, u
"pg_"))
1212 return nsA
.compare(nsB
);
1216 else if(o3tl::starts_with(nsB
, u
"pg_"))
1222 return nsA
.compare(nsB
);
1226 struct SortInternalSchemasLastAndPublicFirst
1228 bool operator () ( const std::vector
< Any
> & a
, const std::vector
< Any
> & b
)
1234 return compare_schema(valueA
, valueB
) < 0;
1239 css::uno::Reference
< XResultSet
> DatabaseMetaData::getSchemas( )
1241 MutexGuard
guard( m_xMutex
->GetMutex() );
1243 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getSchemas() got called");
1245 // <b>TABLE_SCHEM</b> string =&gt; schema name
1246 Reference
< XStatement
> statement
= m_origin
->createStatement();
1247 Reference
< XResultSet
> rs
= statement
->executeQuery(
1248 u
"SELECT nspname from pg_namespace"_ustr
);
1249 // LEM TODO: look at JDBC driver and consider doing the same
1250 // in particular, excluding temporary schemas, but maybe better through pg_is_other_temp_schema(oid) OR == pg_my_temp_schema()
1252 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1253 std::vector
< std::vector
<Any
> > vec
;
1256 vec
.push_back( { Any(xRow
->getString(1)) } );
1259 // sort public first, sort internal schemas last, sort rest in alphabetic order
1260 std::sort( vec
.begin(), vec
.end(), SortInternalSchemasLastAndPublicFirst() );
1262 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1263 if( closeable
.is() )
1265 return new SequenceResultSet(
1266 m_xMutex
, *this, std::vector(getStatics().schemaNames
), std::move(vec
), m_pSettings
->tc
);
1269 css::uno::Reference
< XResultSet
> DatabaseMetaData::getCatalogs( )
1271 // LEM TODO: return the current catalog like JDBC driver?
1272 // at least fake the columns, even if no content
1273 MutexGuard
guard( m_xMutex
->GetMutex() );
1274 return new SequenceResultSet(
1275 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1278 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTableTypes( )
1280 // LEM TODO: this can be made dynamic, see JDBC driver
1281 MutexGuard
guard( m_xMutex
->GetMutex() );
1282 return new SequenceResultSet(
1283 m_xMutex
, *this, std::vector(getStatics().tableTypeNames
), std::vector(getStatics().tableTypeData
),
1288 /** returns the constant from sdbc.DataType
1290 sal_Int32
typeNameToDataType( const OUString
&typeName
, std::u16string_view typtype
)
1292 // sal_Int32 ret = css::sdbc::DataType::DISTINCT;
1293 // map all unknown types to memo (longvarchar). This allows to show them in
1294 // string representation. Additionally, the edit-table-type-selection-box
1295 // is not so unusable anymore.
1296 sal_Int32 ret
= css::sdbc::DataType::LONGVARCHAR
;
1297 if( typtype
== u
"b" )
1299 // as long as the OOo framework does not support arrays,
1300 // the user is better of with interpreting arrays as strings !
1301 // if( typeName.getLength() && '_' == typeName[0] )
1303 // it's just a naming convention, but as long as we don't have anything better,
1304 // we take it as granted
1305 // ret = css::sdbc::DataType::ARRAY;
1308 Statics
&statics
= getStatics();
1309 BaseTypeMap::const_iterator ii
= statics
.baseTypeMap
.find( typeName
);
1310 if( ii
!= statics
.baseTypeMap
.end() )
1315 else if( typtype
== u
"c" )
1317 ret
= css::sdbc::DataType::STRUCT
;
1319 else if( typtype
== u
"d" )
1321 ret
= css::sdbc::DataType::LONGVARCHAR
;
1327 bool isSystemColumn( sal_Int16 attnum
)
1332 // is not exported by the postgres header
1333 const int PQ_VARHDRSZ
= sizeof( sal_Int32
);
1335 // Oh, quelle horreur
1336 // LEM TODO: Need to severely rewrite that!
1337 // should probably just "do the same" as ODBC or JDBC drivers...
1338 void extractPrecisionAndScale(
1339 sal_Int32 dataType
, sal_Int32 atttypmod
, sal_Int32
*precision
, sal_Int32
*scale
)
1341 if( atttypmod
< PQ_VARHDRSZ
)
1350 case css::sdbc::DataType::NUMERIC
:
1351 case css::sdbc::DataType::DECIMAL
:
1353 *precision
= ( ( atttypmod
- PQ_VARHDRSZ
) >> 16 ) & 0xffff;
1354 *scale
= (atttypmod
- PQ_VARHDRSZ
) & 0xffff;
1358 *precision
= atttypmod
- PQ_VARHDRSZ
;
1364 struct DatabaseTypeDescription
1366 DatabaseTypeDescription()
1368 DatabaseTypeDescription( OUString name
, OUString type
) :
1369 typeName(std::move( name
)),
1370 typeType(std::move( type
))
1372 DatabaseTypeDescription( const DatabaseTypeDescription
&source
) :
1373 typeName( source
.typeName
),
1374 typeType( source
.typeType
)
1376 DatabaseTypeDescription
& operator = ( const DatabaseTypeDescription
& source
)
1378 typeName
= source
.typeName
;
1379 typeType
= source
.typeType
;
1387 typedef std::unordered_map
1390 DatabaseTypeDescription
1391 > Oid2DatabaseTypeDescriptionMap
;
1393 static void columnMetaData2DatabaseTypeDescription(
1394 Oid2DatabaseTypeDescriptionMap
&oidMap
,
1395 const Reference
< XResultSet
> &rs
,
1396 const Reference
< XStatement
> &stmt
)
1398 Reference
< XRow
> row( rs
, UNO_QUERY_THROW
);
1400 OUStringBuffer
queryBuf(128);
1401 queryBuf
.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " );
1404 if( row
->getString( 9 ) == "d" && oidMap
.find( row
->getInt( 12 ) ) == oidMap
.end() )
1406 oidMap
[row
->getInt(12)] = DatabaseTypeDescription();
1408 queryBuf
.append( " OR " );
1409 queryBuf
.append( "oid = " + OUString::number( row
->getInt(12 ) ) );
1417 Reference
< XResultSet
> rsDomain
= stmt
->executeQuery( queryBuf
.makeStringAndClear() );
1418 row
.set( rsDomain
, UNO_QUERY_THROW
);
1419 while( rsDomain
->next() )
1421 oidMap
[row
->getInt(1)] = DatabaseTypeDescription(row
->getString(3), row
->getString(2) );
1423 disposeNoThrow( stmt
);
1429 css::uno::Reference
< XResultSet
> DatabaseMetaData::getColumns(
1430 const css::uno::Any
&,
1431 const OUString
& schemaPattern
,
1432 const OUString
& tableNamePattern
,
1433 const OUString
& columnNamePattern
)
1435 // LEM TODO: review in comparison with JDBC driver
1436 Statics
&statics
= getStatics();
1439 MutexGuard
guard( m_xMutex
->GetMutex() );
1441 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumns() got called with "
1442 << schemaPattern
<< "." << tableNamePattern
<< "." << columnNamePattern
);
1444 // ignore catalog, as a single pq connection
1445 // does not support multiple catalogs anyway
1446 // We don't use information_schema.columns because it contains
1447 // only the columns the current user has any privilege over.
1449 // 1. TABLE_CAT string => table catalog (may be NULL)
1451 // 2. TABLE_SCHEM string => table schema (may be NULL)
1452 // => pg_namespace.nspname
1453 // 3. TABLE_NAME string => table name
1454 // => pg_class.relname
1455 // 4. COLUMN_NAME string => column name
1456 // => pg_attribute.attname
1457 // 5. DATA_TYPE short => SQL type from java.sql.Types
1458 // => pg_type.typname => sdbc.DataType
1459 // 6. TYPE_NAME string => Data source dependent type name, for a UDT the
1460 // type name is fully qualified
1461 // => pg_type.typname
1462 // 7. COLUMN_SIZE long => column size. For char or date types this is
1463 // the maximum number of characters, for numeric
1464 // or decimal types this is precision.
1465 // => pg_attribute.atttypmod
1466 // 8. BUFFER_LENGTH is not used.
1468 // 9. DECIMAL_DIGITS long => the number of fractional digits
1469 // => don't know ! TODO !
1470 // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2)
1472 // 11. NULLABLE long => is NULL allowed?
1473 // NO_NULLS - might not allow NULL values
1474 // NULABLE - definitely allows NULL values
1475 // NULLABLE_UNKNOWN - nullability unknown
1476 // => pg_attribute.attnotnull
1477 // 12. REMARKS string => comment describing column (may be NULL )
1478 // => pg_description.description
1479 // 13. COLUMN_DEF string => default value (may be NULL)
1480 // => pg_type.typdefault
1481 // 14. SQL_DATA_TYPE long => unused
1483 // 15. SQL_DATETIME_SUB long => unused
1485 // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of
1486 // bytes in the column
1487 // => pg_type.typlen
1488 // 17. ORDINAL_POSITION int => index of column in table (starting at 1)
1489 // pg_attribute.attnum
1490 // 18. IS_NULLABLE string => "NO" means column definitely does not allow
1491 // NULL values; "YES" means the column might
1492 // allow NULL values. An empty string means
1494 // => pg_attribute.attnotnull
1495 OUString strDefaultValue
= getColExprForDefaultSettingVal(m_pSettings
);
1496 Reference
< XPreparedStatement
> statement
= m_origin
->prepareStatement(
1497 "SELECT pg_namespace.nspname, " // 1
1498 "pg_class.relname, " // 2
1499 "pg_attribute.attname, " // 3
1500 "pg_type.typname, " // 4
1501 "pg_attribute.atttypmod, " // 5
1502 "pg_attribute.attnotnull, " // 6
1503 "pg_type.typdefault, " // 7
1504 "pg_type.typtype, " // 8
1505 + strDefaultValue
+ // 9
1506 ",pg_description.description, " // 10
1507 "pg_type.typbasetype, " // 11
1508 "pg_attribute.attnum " // 12
1510 "pg_attribute LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum "
1511 "LEFT JOIN pg_description ON pg_attribute.attrelid = pg_description.objoid AND pg_attribute.attnum=pg_description.objsubid,"
1512 " pg_type, pg_namespace "
1513 "WHERE pg_attribute.attrelid = pg_class.oid "
1514 "AND pg_attribute.atttypid = pg_type.oid "
1515 "AND pg_class.relnamespace = pg_namespace.oid "
1516 "AND NOT pg_attribute.attisdropped "
1517 "AND pg_namespace.nspname LIKE ? "
1518 "AND pg_class.relname LIKE ? "
1519 "AND pg_attribute.attname LIKE ? "
1520 "ORDER BY pg_namespace.nspname, pg_class.relname, pg_attribute.attnum"
1523 Reference
< XParameters
> parameters( statement
, UNO_QUERY_THROW
);
1524 parameters
->setString( 1 , schemaPattern
);
1525 parameters
->setString( 2 , tableNamePattern
);
1526 parameters
->setString( 3 , columnNamePattern
);
1528 Reference
< XResultSet
> rs
= statement
->executeQuery();
1529 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1530 std::vector
< std::vector
<Any
> > vec
;
1532 Oid2DatabaseTypeDescriptionMap domainMap
;
1533 Reference
< XStatement
> domainTypeStmt
= m_origin
->createStatement();
1534 columnMetaData2DatabaseTypeDescription( domainMap
, rs
, domainTypeStmt
);
1536 sal_uInt32
colNum(0);
1537 OUString
sSchema( u
"#invalid#"_ustr
);
1538 OUString
sTable( u
"#invalid#"_ustr
);
1542 if( ! isSystemColumn( xRow
->getShort( 12 ) ) )
1544 OUString
sNewSchema( xRow
->getString(1) );
1545 OUString
sNewTable( xRow
->getString(2) );
1546 if ( sNewSchema
!= sSchema
|| sNewTable
!= sTable
)
1549 sSchema
= sNewSchema
;
1554 sal_Int32 precision
, scale
, type
;
1555 std::vector
< Any
> row( 18 );
1556 row
[0] <<= m_pSettings
->catalog
;
1557 row
[1] <<= sNewSchema
;
1558 row
[2] <<= sNewTable
;
1559 row
[3] <<= xRow
->getString(3);
1560 if( xRow
->getString(8) == "d" )
1562 DatabaseTypeDescription
desc( domainMap
[xRow
->getInt(11)] );
1563 type
= typeNameToDataType( desc
.typeName
, desc
.typeType
);
1567 type
= typeNameToDataType( xRow
->getString(4), xRow
->getString(8) );
1569 extractPrecisionAndScale( type
, xRow
->getInt(5) , &precision
, &scale
);
1571 row
[5] <<= xRow
->getString(4);
1572 row
[6] <<= precision
;
1573 // row[7] BUFFER_LENGTH not used
1575 // row[9] RADIX TODO
1576 if( xRow
->getBoolean( 6 ) && ! isSystemColumn(xRow
->getInt( 12 )) )
1578 row
[10] <<= OUString::number(css::sdbc::ColumnValue::NO_NULLS
);
1579 row
[17] <<= statics
.NO
;
1583 row
[10] <<= OUString::number(css::sdbc::ColumnValue::NULLABLE
);
1584 row
[17] <<= statics
.YES
;
1587 row
[11] <<= xRow
->getString( 10 ); // comment
1588 row
[12] <<= xRow
->getString( 9 ); // COLUMN_DEF = pg_type.typdefault
1589 // row[13] SQL_DATA_TYPE not used
1590 // row[14] SQL_DATETIME_SUB not used
1591 row
[15] <<= precision
;
1592 row
[16] <<= colNum
;
1594 vec
.push_back( row
);
1597 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1598 if( closeable
.is() )
1601 return new SequenceResultSet(
1602 m_xMutex
, *this, std::vector(statics
.columnRowNames
), std::move(vec
), m_pSettings
->tc
);
1605 css::uno::Reference
< XResultSet
> DatabaseMetaData::getColumnPrivileges(
1606 const css::uno::Any
&,
1607 const OUString
& schema
,
1608 const OUString
& table
,
1609 const OUString
& columnNamePattern
)
1611 MutexGuard
guard( m_xMutex
->GetMutex() );
1613 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumnPrivileges() got called with "
1614 << schema
<< "." << table
<< "." << columnNamePattern
);
1616 Reference
< XParameters
> parameters( m_getColumnPrivs_stmt
, UNO_QUERY_THROW
);
1617 parameters
->setString( 1 , schema
);
1618 parameters
->setString( 2 , table
);
1619 parameters
->setString( 3 , columnNamePattern
);
1621 Reference
< XResultSet
> rs
= m_getColumnPrivs_stmt
->executeQuery();
1626 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTablePrivileges(
1627 const css::uno::Any
&,
1628 const OUString
& schemaPattern
,
1629 const OUString
& tableNamePattern
)
1631 MutexGuard
guard( m_xMutex
->GetMutex() );
1633 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTablePrivileges() got called with "
1634 << schemaPattern
<< "." << tableNamePattern
);
1636 Reference
< XParameters
> parameters( m_getTablePrivs_stmt
, UNO_QUERY_THROW
);
1637 parameters
->setString( 1 , schemaPattern
);
1638 parameters
->setString( 2 , tableNamePattern
);
1640 Reference
< XResultSet
> rs
= m_getTablePrivs_stmt
->executeQuery();
1645 css::uno::Reference
< XResultSet
> DatabaseMetaData::getBestRowIdentifier(
1646 const css::uno::Any
&,
1652 //LEM TODO: implement! See JDBC driver
1653 MutexGuard
guard( m_xMutex
->GetMutex() );
1654 return new SequenceResultSet(
1655 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1658 css::uno::Reference
< XResultSet
> DatabaseMetaData::getVersionColumns(
1659 const css::uno::Any
&,
1663 //LEM TODO: implement! See JDBC driver
1664 MutexGuard
guard( m_xMutex
->GetMutex() );
1665 return new SequenceResultSet(
1666 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1669 css::uno::Reference
< XResultSet
> DatabaseMetaData::getPrimaryKeys(
1670 const css::uno::Any
&,
1671 const OUString
& schema
,
1672 const OUString
& table
)
1675 MutexGuard
guard( m_xMutex
->GetMutex() );
1677 // 1. TABLE_CAT string => table catalog (may be NULL )
1678 // 2. TABLE_SCHEM string => table schema (may be NULL )
1679 // 3. TABLE_NAME string => table name
1680 // 4. COLUMN_NAME string => column name
1681 // 5. KEY_SEQ short => sequence number within primary key
1682 // 6. PK_NAME string => primary key name (may be NULL )
1684 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getPrimaryKeys() got called with "
1685 << schema
<< "." << table
);
1687 Reference
< XPreparedStatement
> statement
= m_origin
->prepareStatement(
1688 u
"SELECT nmsp.nspname, "
1693 "FROM pg_constraint as con,pg_class as cl, pg_namespace as nmsp "
1694 "WHERE con.connamespace = nmsp.oid AND con.conrelid = cl.oid AND con.contype = 'p' "
1695 "AND nmsp.nspname LIKE ? AND cl.relname LIKE ?"_ustr
);
1697 Reference
< XParameters
> parameters( statement
, UNO_QUERY_THROW
);
1698 parameters
->setString( 1 , schema
);
1699 parameters
->setString( 2 , table
);
1701 Reference
< XResultSet
> rs
= statement
->executeQuery();
1702 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1703 std::vector
< std::vector
<Any
> > vec
;
1707 std::vector
< Any
> row( 6 );
1708 row
[0] <<= m_pSettings
->catalog
;
1709 row
[1] <<= xRow
->getString(1);
1710 row
[2] <<= xRow
->getString(2);
1711 OUString array
= xRow
->getString(3);
1712 row
[4] <<= xRow
->getString(5); // the relid
1713 row
[5] <<= xRow
->getString(4);
1716 // now retrieve the columns information
1717 // unfortunately, postgresql does not allow array of variable size in
1718 // WHERE clauses (in the default installation), so we have to choose
1719 // this expensive and somewhat ugly way
1720 // annotation: postgresql shouldn't have chosen an array here, instead they
1721 // should have multiple rows per table
1722 // LEM: to transform an array into several rows, see unnest;
1723 // it is as simple as "SELECT foo, bar, unnest(qux) FROM ..."
1724 // where qux is the column that contains an array.
1725 while( array
[i
] && '}' != array
[i
] )
1729 while( array
[i
] && array
[i
] != '}' && array
[i
] != ',' ) i
++;
1730 row
[3] <<= array
.copy(start
, i
- start
);
1731 vec
.push_back( row
);
1736 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1737 if( closeable
.is() )
1742 OUString lastTableOid
;
1743 sal_Int32 index
= 0;
1744 std::vector
< std::vector
< Any
> > ret( vec
.size() );
1746 for (auto const& elem
: vec
)
1749 std::vector
< Any
> row
= elem
;
1753 row
[4] >>= tableOid
;
1755 statement
= m_origin
->prepareStatement(
1756 u
"SELECT att.attname FROM "
1757 "pg_attribute AS att, pg_class AS cl WHERE "
1758 "att.attrelid = ? AND att.attnum = ?"_ustr
);
1760 parameters
.set( statement
, UNO_QUERY_THROW
);
1761 parameters
->setString( 1 , tableOid
);
1762 parameters
->setString( 2 , attnum
);
1764 rs
= statement
->executeQuery();
1765 xRow
.set( rs
, UNO_QUERY_THROW
);
1769 row
[3] <<= xRow
->getString( 1 );
1770 if( tableOid
!= lastTableOid
)
1772 lastTableOid
= tableOid
;
1773 row
[4] <<= OUString::number( index
);
1777 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1778 if( closeable
.is() )
1781 ret
[elements
] = std::move(row
);
1784 return new SequenceResultSet(
1785 m_xMutex
, *this, std::vector(getStatics().primaryKeyNames
), std::move(ret
), m_pSettings
->tc
);
1788 // Copied / adapted / simplified from JDBC driver
1789 #define SQL_CASE_KEYRULE " WHEN 'c' THEN " SAL_STRINGIFY(KEYRULE_CASCADE) \
1790 " WHEN 'n' THEN " SAL_STRINGIFY(KEYRULE_SET_NULL) \
1791 " WHEN 'd' THEN " SAL_STRINGIFY(KEYRULE_SET_DEFAULT) \
1792 " WHEN 'r' THEN " SAL_STRINGIFY(KEYRULE_RESTRICT) \
1793 " WHEN 'a' THEN " SAL_STRINGIFY(KEYRULE_NO_ACTION) \
1796 #define SQL_GET_REFERENCES \
1797 "WITH con AS (SELECT oid, conname, contype, condeferrable, condeferred, conrelid, confrelid, confupdtype, confdeltype, generate_subscripts(conkey,1) AS conkeyseq, unnest(conkey) AS conkey , unnest(confkey) AS confkey FROM pg_catalog.pg_constraint) " \
1798 "SELECT NULL::text AS PKTABLE_CAT, pkn.nspname AS PKTABLE_SCHEM, pkc.relname AS PKTABLE_NAME, pka.attname AS PKCOLUMN_NAME, " \
1799 " NULL::text AS FKTABLE_CAT, fkn.nspname AS FKTABLE_SCHEM, fkc.relname AS FKTABLE_NAME, fka.attname AS FKCOLUMN_NAME, " \
1800 " con.conkeyseq AS KEY_SEQ, " \
1801 " CASE con.confupdtype " \
1803 " END AS UPDATE_RULE, " \
1804 " CASE con.confdeltype " \
1806 " END AS DELETE_RULE, " \
1807 " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \
1809 " WHEN con.condeferrable AND con.condeferred THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_DEFERRED) \
1810 " WHEN con.condeferrable THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_IMMEDIATE) \
1811 " ELSE " SAL_STRINGIFY(DEFERRABILITY_NONE) \
1812 " END AS DEFERRABILITY " \
1814 " pg_catalog.pg_namespace pkn, pg_catalog.pg_class pkc, pg_catalog.pg_attribute pka, " \
1815 " pg_catalog.pg_namespace fkn, pg_catalog.pg_class fkc, pg_catalog.pg_attribute fka, " \
1816 " con, pg_catalog.pg_depend dep, pg_catalog.pg_class pkic " \
1817 "WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey AND con.confrelid = pkc.oid " \
1818 " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey AND con.conrelid = fkc.oid " \
1819 " AND con.contype = 'f' AND con.oid = dep.objid AND pkic.oid = dep.refobjid AND pkic.relkind = 'i' AND dep.classid = 'pg_constraint'::regclass::oid AND dep.refclassid = 'pg_class'::regclass::oid "
1821 #define SQL_GET_REFERENCES_PSCHEMA " AND pkn.nspname = ? "
1822 #define SQL_GET_REFERENCES_PTABLE " AND pkc.relname = ? "
1823 #define SQL_GET_REFERENCES_FSCHEMA " AND fkn.nspname = ? "
1824 #define SQL_GET_REFERENCES_FTABLE " AND fkc.relname = ? "
1825 #define SQL_GET_REFERENCES_ORDER_SOME_PTABLE "ORDER BY fkn.nspname, fkc.relname, conkeyseq"
1826 #define SQL_GET_REFERENCES_ORDER_NO_PTABLE "ORDER BY pkn.nspname, pkc.relname, conkeyseq"
1828 #define SQL_GET_REFERENCES_NONE_NONE_NONE_NONE \
1829 u"" SQL_GET_REFERENCES \
1830 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1832 #define SQL_GET_REFERENCES_SOME_NONE_NONE_NONE \
1833 u"" SQL_GET_REFERENCES \
1834 SQL_GET_REFERENCES_PSCHEMA \
1835 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1837 #define SQL_GET_REFERENCES_NONE_SOME_NONE_NONE \
1838 u"" SQL_GET_REFERENCES \
1839 SQL_GET_REFERENCES_PTABLE \
1840 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1842 #define SQL_GET_REFERENCES_SOME_SOME_NONE_NONE \
1843 u"" SQL_GET_REFERENCES \
1844 SQL_GET_REFERENCES_PSCHEMA \
1845 SQL_GET_REFERENCES_PTABLE \
1846 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1848 #define SQL_GET_REFERENCES_NONE_NONE_SOME_NONE \
1849 u"" SQL_GET_REFERENCES \
1850 SQL_GET_REFERENCES_FSCHEMA \
1851 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1853 #define SQL_GET_REFERENCES_NONE_NONE_NONE_SOME \
1854 u"" SQL_GET_REFERENCES \
1855 SQL_GET_REFERENCES_FTABLE \
1856 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1858 #define SQL_GET_REFERENCES_NONE_NONE_SOME_SOME \
1859 u"" SQL_GET_REFERENCES \
1860 SQL_GET_REFERENCES_FSCHEMA \
1861 SQL_GET_REFERENCES_FTABLE \
1862 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1864 #define SQL_GET_REFERENCES_SOME_NONE_SOME_NONE \
1865 u"" SQL_GET_REFERENCES \
1866 SQL_GET_REFERENCES_PSCHEMA \
1867 SQL_GET_REFERENCES_FSCHEMA \
1868 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1870 #define SQL_GET_REFERENCES_SOME_NONE_NONE_SOME \
1871 u"" SQL_GET_REFERENCES \
1872 SQL_GET_REFERENCES_PSCHEMA \
1873 SQL_GET_REFERENCES_FTABLE \
1874 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1876 #define SQL_GET_REFERENCES_SOME_NONE_SOME_SOME \
1877 u"" SQL_GET_REFERENCES \
1878 SQL_GET_REFERENCES_PSCHEMA \
1879 SQL_GET_REFERENCES_FSCHEMA \
1880 SQL_GET_REFERENCES_FTABLE \
1881 SQL_GET_REFERENCES_ORDER_NO_PTABLE ""_ustr
1883 #define SQL_GET_REFERENCES_NONE_SOME_SOME_NONE \
1884 u"" SQL_GET_REFERENCES \
1885 SQL_GET_REFERENCES_PTABLE \
1886 SQL_GET_REFERENCES_FSCHEMA \
1887 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1889 #define SQL_GET_REFERENCES_NONE_SOME_NONE_SOME \
1890 u"" SQL_GET_REFERENCES \
1891 SQL_GET_REFERENCES_PTABLE \
1892 SQL_GET_REFERENCES_FTABLE \
1893 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1895 #define SQL_GET_REFERENCES_NONE_SOME_SOME_SOME \
1896 u"" SQL_GET_REFERENCES \
1897 SQL_GET_REFERENCES_PTABLE \
1898 SQL_GET_REFERENCES_FSCHEMA \
1899 SQL_GET_REFERENCES_FTABLE \
1900 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1902 #define SQL_GET_REFERENCES_SOME_SOME_SOME_NONE \
1903 u"" SQL_GET_REFERENCES \
1904 SQL_GET_REFERENCES_PSCHEMA \
1905 SQL_GET_REFERENCES_PTABLE \
1906 SQL_GET_REFERENCES_FSCHEMA \
1907 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1909 #define SQL_GET_REFERENCES_SOME_SOME_NONE_SOME \
1910 u"" SQL_GET_REFERENCES \
1911 SQL_GET_REFERENCES_PSCHEMA \
1912 SQL_GET_REFERENCES_PTABLE \
1913 SQL_GET_REFERENCES_FTABLE \
1914 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1916 #define SQL_GET_REFERENCES_SOME_SOME_SOME_SOME \
1917 u"" SQL_GET_REFERENCES \
1918 SQL_GET_REFERENCES_PSCHEMA \
1919 SQL_GET_REFERENCES_PTABLE \
1920 SQL_GET_REFERENCES_FSCHEMA \
1921 SQL_GET_REFERENCES_FTABLE \
1922 SQL_GET_REFERENCES_ORDER_SOME_PTABLE ""_ustr
1924 void DatabaseMetaData::init_getReferences_stmt ()
1926 m_getReferences_stmt
[0] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_NONE
);
1927 m_getReferences_stmt
[1] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_NONE
);
1928 m_getReferences_stmt
[2] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_NONE
);
1929 m_getReferences_stmt
[3] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_NONE
);
1930 m_getReferences_stmt
[4] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_NONE
);
1931 m_getReferences_stmt
[5] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_NONE
);
1932 m_getReferences_stmt
[6] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_NONE
);
1933 m_getReferences_stmt
[7] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_NONE
);
1934 m_getReferences_stmt
[8] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_SOME
);
1935 m_getReferences_stmt
[9] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_SOME
);
1936 m_getReferences_stmt
[10] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_SOME
);
1937 m_getReferences_stmt
[11] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_SOME
);
1938 m_getReferences_stmt
[12] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_SOME
);
1939 m_getReferences_stmt
[13] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_SOME
);
1940 m_getReferences_stmt
[14] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_SOME
);
1941 m_getReferences_stmt
[15] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_SOME
);
1944 void DatabaseMetaData::init_getPrivs_stmt ()
1946 OUStringBuffer
sSQL(300);
1948 " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable "
1950 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name,"
1951 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
1952 " FROM information_schema.table_privileges");
1953 if ( PQserverVersion( m_pSettings
->pConnection
) < 90200 )
1954 // information_schema.table_privileges does not fill in default ACLs when no ACL
1955 // assume default ACL is "owner has all privileges" and add it
1958 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME,"
1959 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
1960 " FROM pg_catalog.pg_class c,"
1961 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) p (privilege),"
1962 " pg_catalog.pg_roles ro,"
1963 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
1965 " VALUES (0::oid, 'PUBLIC')"
1966 " ) AS rg (oid, rolname),"
1967 " pg_catalog.pg_namespace pn"
1968 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
1969 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid");
1972 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
1973 " WHERE table_schem LIKE ? AND table_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
1974 " ORDER BY table_schem, table_name, privilege" );
1976 m_getTablePrivs_stmt
= m_origin
->prepareStatement( sSQL
.makeStringAndClear() );
1979 " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.COLUMN_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.PRIVILEGE, dp.IS_GRANTABLE FROM ("
1980 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name, column_name,"
1981 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
1982 " FROM information_schema.column_privileges");
1983 if ( PQserverVersion( m_pSettings
->pConnection
) < 90200 )
1984 // information_schema.table_privileges does not fill in default ACLs when no ACL
1985 // assume default ACL is "owner has all privileges" and add it
1988 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, a.attname AS column_name,"
1989 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
1990 " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a,"
1991 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) p (privilege),"
1992 " pg_catalog.pg_roles ro,"
1993 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
1995 " VALUES (0::oid, 'PUBLIC')"
1996 " ) AS rg (oid, rolname),"
1997 " pg_catalog.pg_namespace pn"
1998 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
1999 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid AND a.attrelid = c.oid AND a.attnum > 0");
2002 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
2003 " WHERE table_schem = ? AND table_name = ? AND column_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
2004 " ORDER BY column_name, privilege" );
2006 m_getColumnPrivs_stmt
= m_origin
->prepareStatement( sSQL
.makeStringAndClear() );
2009 css::uno::Reference
< XResultSet
> DatabaseMetaData::getImportedExportedKeys(
2010 const Any
& /* primaryCatalog */,
2011 const OUString
& primarySchema
,
2012 const OUString
& primaryTable
,
2013 const Any
& /* foreignCatalog */,
2014 const OUString
& foreignSchema
,
2015 const OUString
& foreignTable
)
2018 if ( ! primarySchema
.isEmpty() )
2020 if ( ! primaryTable
.isEmpty() )
2022 if ( ! foreignSchema
.isEmpty() )
2024 if ( ! foreignTable
.isEmpty() )
2027 Reference
< XPreparedStatement
> stmt
= m_getReferences_stmt
[i
];
2028 Reference
< XParameters
> param ( stmt
, UNO_QUERY_THROW
);
2032 param
->setString( j
++, primarySchema
);
2034 param
->setString( j
++, primaryTable
);
2036 param
->setString( j
++, foreignSchema
);
2038 param
->setString( j
++, foreignTable
);
2040 Reference
< XResultSet
> rs
= stmt
->executeQuery();
2046 css::uno::Reference
< XResultSet
> DatabaseMetaData::getImportedKeys(
2047 const css::uno::Any
& catalog
,
2048 const OUString
& schema
,
2049 const OUString
& table
)
2051 return getImportedExportedKeys(Any(), OUString(), OUString(), catalog
, schema
, table
);
2054 css::uno::Reference
< XResultSet
> DatabaseMetaData::getExportedKeys(
2055 const css::uno::Any
& catalog
,
2056 const OUString
& schema
,
2057 const OUString
& table
)
2059 return getImportedExportedKeys(catalog
, schema
, table
, Any(), OUString(), OUString());
2062 css::uno::Reference
< XResultSet
> DatabaseMetaData::getCrossReference(
2063 const css::uno::Any
& primaryCatalog
,
2064 const OUString
& primarySchema
,
2065 const OUString
& primaryTable
,
2066 const css::uno::Any
& foreignCatalog
,
2067 const OUString
& foreignSchema
,
2068 const OUString
& foreignTable
)
2070 return getImportedExportedKeys( primaryCatalog
, primarySchema
, primaryTable
, foreignCatalog
, foreignSchema
, foreignTable
);
2075 struct TypeInfoByDataTypeSorter
2077 bool operator () ( const std::vector
< Any
> & a
, const std::vector
< Any
> & b
)
2081 a
[1 /*DATA_TYPE*/] >>= valueA
;
2082 b
[1 /*DATA_TYPE*/] >>= valueB
;
2083 if( valueB
.toInt32() == valueA
.toInt32() )
2087 a
[0 /*TYPE_NAME*/] >>= nameA
;
2088 b
[0 /*TYPE_NAME*/] >>= nameB
;
2089 std::u16string_view nsA
, tnA
, nsB
, tnB
;
2091 // parse typename into schema and typename
2093 nsA
= o3tl::getToken(nameA
, 0, '.', nIndex
);
2097 nsA
= std::u16string_view();
2101 tnA
= o3tl::getToken(nameA
, 0, '.', nIndex
);
2106 nsB
= o3tl::getToken(nameB
, 0, '.', nIndex
);
2110 nsB
= std::u16string_view();
2114 tnB
= o3tl::getToken(nameB
, 0, '.', nIndex
);
2118 const int ns_comp
= compare_schema(nsA
, nsB
);
2123 assert(nsB
.empty());
2124 // within each type category, sort privileged choice first
2125 if( tnA
== u
"int4" || tnA
== u
"varchar" || tnA
== u
"char" || tnA
== u
"text")
2127 if( tnB
== u
"int4" || tnB
== u
"varchar" || tnB
== u
"char" || tnB
== u
"text")
2130 return nameA
.compareTo( nameB
) < 0;
2138 return valueA
.toInt32() < valueB
.toInt32();
2142 sal_Int32
calcSearchable( sal_Int32 dataType
)
2144 sal_Int32 ret
= css::sdbc::ColumnSearch::FULL
;
2145 if( css::sdbc::DataType::BINARY
== dataType
||
2146 css::sdbc::DataType::VARBINARY
== dataType
||
2147 css::sdbc::DataType::LONGVARBINARY
== dataType
)
2148 ret
= css::sdbc::ColumnSearch::NONE
;
2153 sal_Int32
getMaxScale( sal_Int32 dataType
)
2155 // LEM TODO: review, see where used, see JDBC, ...
2157 if( dataType
== css::sdbc::DataType::NUMERIC
)
2158 ret
= 1000; // see pg-docs DataType/numeric
2159 // else if( dataType == DataType::DOUBLE )
2161 // else if( dataType == DataType::FLOAT )
2166 OUString
construct_full_typename(std::u16string_view ns
, const OUString
&tn
)
2168 if(ns
.empty() || ns
== u
"pg_catalog")
2171 return OUString::Concat(ns
) + "." + tn
;
2174 void pgTypeInfo2ResultSet(
2175 std::vector
< std::vector
<Any
> > &vec
,
2176 const Reference
< XResultSet
> &rs
)
2178 static const sal_Int32 TYPE_NAME
= 0; // string Type name
2179 static const sal_Int32 DATA_TYPE
= 1; // short SQL data type from java.sql.Types
2180 static const sal_Int32 PRECISION
= 2; // long maximum precision
2181 static const sal_Int32 CREATE_PARAMS
= 5; // string => parameters used in creating the type (may be NULL )
2182 static const sal_Int32 NULLABLE
= 6; // short ==> can you use NULL for this type?
2183 // - NO_NULLS - does not allow NULL values
2184 // - NULLABLE - allows NULL values
2185 // - NULLABLE_UNKNOWN - nullability unknown
2187 static const sal_Int32 CASE_SENSITIVE
= 7; // boolean==> is it case sensitive
2188 static const sal_Int32 SEARCHABLE
= 8; // short ==>; can you use
2189 // "WHERE" based on this type:
2190 // - NONE - No support
2191 // - CHAR - Only supported with WHERE .. LIKE
2192 // - BASIC - Supported except for WHERE .. LIKE
2193 // - FULL - Supported for all WHERE ..
2194 static const sal_Int32 UNSIGNED_ATTRIBUTE
= 9; // boolean ==> is it unsigned?
2195 // FIXED_PREC_SCALE = 10; boolean ==> can it be a money value?
2196 static const sal_Int32 AUTO_INCREMENT
= 11; // boolean ==> can it be used for
2197 // an auto-increment value?
2198 static const sal_Int32 MINIMUM_SCALE
= 13; // short ==> minimum scale supported
2199 static const sal_Int32 MAXIMUM_SCALE
= 14; // short ==> maximum scale supported
2200 static const sal_Int32 NUM_PREC_RADIX
= 17; // long ==> usually 2 or 10
2202 /* not filled so far
2203 3. LITERAL_PREFIX string ==> prefix used to quote a literal
2205 4. LITERAL_SUFFIX string ==> suffix used to quote a literal
2207 5. CREATE_PARAMS string ==> parameters used in creating the type (may be <NULL/>)
2208 12. LOCAL_TYPE_NAME string ==> localized version of type name (may be <NULL/>)
2209 15, SQL_DATA_TYPE long ==> unused
2210 16. SQL_DATETIME_SUB long ==> unused
2212 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
2215 std::vector
< Any
> row(18);
2217 sal_Int32 dataType
=typeNameToDataType(xRow
->getString(5),xRow
->getString(2));
2218 sal_Int32 precision
= xRow
->getString(3).toInt32();
2220 if( dataType
== css::sdbc::DataType::CHAR
||
2221 ( dataType
== css::sdbc::DataType::VARCHAR
&&
2222 xRow
->getString(TYPE_NAME
+1).equalsIgnoreAsciiCase("varchar") ) )
2224 // reflect varchar as varchar with upper limit !
2225 //NOTE: the sql spec requires varchar to have an upper limit, however
2226 // in postgresql the upper limit is optional, no limit means unlimited
2228 precision
= 0x40000000; // about 1 GB, see character type docs in postgresql
2229 row
[CREATE_PARAMS
] <<= u
"length"_ustr
;
2231 else if( dataType
== css::sdbc::DataType::NUMERIC
)
2234 row
[CREATE_PARAMS
] <<= u
"length, scale"_ustr
;
2237 row
[TYPE_NAME
] <<= construct_full_typename(xRow
->getString(6), xRow
->getString(1));
2238 row
[DATA_TYPE
] <<= OUString::number(dataType
);
2239 row
[PRECISION
] <<= OUString::number( precision
);
2240 sal_Int32 nullable
= xRow
->getBoolean(4) ?
2241 css::sdbc::ColumnValue::NO_NULLS
:
2242 css::sdbc::ColumnValue::NULLABLE
;
2243 row
[NULLABLE
] <<= OUString::number(nullable
);
2244 row
[CASE_SENSITIVE
] <<= OUString::number(1);
2245 row
[SEARCHABLE
] <<= OUString::number( calcSearchable( dataType
) );
2246 row
[UNSIGNED_ATTRIBUTE
] <<= u
"0"_ustr
;
2247 if( css::sdbc::DataType::INTEGER
== dataType
||
2248 css::sdbc::DataType::BIGINT
== dataType
)
2249 row
[AUTO_INCREMENT
] <<= u
"1"_ustr
; // TODO
2251 row
[AUTO_INCREMENT
] <<= u
"0"_ustr
; // TODO
2252 row
[MINIMUM_SCALE
] <<= u
"0"_ustr
; // TODO: what is this ?
2253 row
[MAXIMUM_SCALE
] <<= OUString::number( getMaxScale( dataType
) );
2254 row
[NUM_PREC_RADIX
] <<= u
"10"_ustr
; // TODO: what is this ?
2255 vec
.push_back( row
);
2261 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTypeInfo( )
2263 // Note: Indexes start at 0 (in the API doc, they start at 1)
2264 MutexGuard
guard( m_xMutex
->GetMutex() );
2266 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTypeInfo() got called");
2268 Reference
< XStatement
> statement
= m_origin
->createStatement();
2269 Reference
< XResultSet
> rs
= statement
->executeQuery(
2270 u
"SELECT pg_type.typname AS typname," //1
2271 "pg_type.typtype AS typtype," //2
2272 "pg_type.typlen AS typlen," //3
2273 "pg_type.typnotnull AS typnotnull," //4
2274 "pg_type.typname AS typname, " //5
2275 "pg_namespace.nspname as typns " //6
2276 "FROM pg_type LEFT JOIN pg_namespace ON pg_type.typnamespace=pg_namespace.oid "
2277 "WHERE pg_type.typtype = 'b' "
2278 "OR pg_type.typtype = 'p'"_ustr
2281 std::vector
< std::vector
<Any
> > vec
;
2282 pgTypeInfo2ResultSet( vec
, rs
);
2284 // check for domain types
2285 rs
= statement
->executeQuery(
2286 u
"SELECT t1.typname as typname,"
2287 "t2.typtype AS typtype,"
2288 "t2.typlen AS typlen,"
2289 "t2.typnotnull AS typnotnull,"
2290 "t2.typname as realtypname, "
2291 "pg_namespace.nspname as typns "
2292 "FROM pg_type as t1 LEFT JOIN pg_type AS t2 ON t1.typbasetype=t2.oid LEFT JOIN pg_namespace ON t1.typnamespace=pg_namespace.oid "
2293 "WHERE t1.typtype = 'd'"_ustr
);
2294 pgTypeInfo2ResultSet( vec
, rs
);
2296 std::sort( vec
.begin(), vec
.end(), TypeInfoByDataTypeSorter() );
2298 return new SequenceResultSet(
2301 std::vector(getStatics().typeinfoColumnNames
),
2304 &( getStatics().typeInfoMetaData
));
2308 css::uno::Reference
< XResultSet
> DatabaseMetaData::getIndexInfo(
2309 const css::uno::Any
& ,
2310 const OUString
& schema
,
2311 const OUString
& table
,
2316 MutexGuard
guard( m_xMutex
->GetMutex() );
2319 1. TABLE_CAT string -> table catalog (may be NULL )
2320 2. TABLE_SCHEM string -> table schema (may be NULL )
2321 3. TABLE_NAME string -> table name
2322 4. NON_UNIQUE boolean -> Can index values be non-unique?
2323 false when TYPE is tableIndexStatistic
2324 5. INDEX_QUALIFIER string -> index catalog (may be NULL );
2325 NULL when TYPE is tableIndexStatistic
2326 6. INDEX_NAME string -> index name; NULL when TYPE is tableIndexStatistic
2327 7. TYPE short -> index type:
2328 * 0 - this identifies table statistics that are returned
2329 in conjunction with a table's index descriptions
2330 * CLUSTERED - this is a clustered index
2331 * HASHED - this is a hashed index
2332 * OTHER - this is some other style of index
2333 8. ORDINAL_POSITION short -> column sequence number within index;
2334 zero when TYPE is tableIndexStatistic
2335 9. COLUMN_NAME string -> column name; NULL when TYPE is tableIndexStatistic
2336 10. ASC_OR_DESC string -> column sort sequence, "A"= ascending,
2337 "D" = descending, may be NULL if sort sequence
2338 is not supported; NULL when TYPE is tableIndexStatistic
2339 11. CARDINALITY long -> When TYPE is tableIndexStatistic, then this is
2340 the number of rows in the table; otherwise, it
2341 is the number of unique values in the index.
2342 12. PAGES long -> When TYPE is tableIndexStatistic then this is
2343 the number of pages used for the table, otherwise
2344 it is the number of pages used for the current index.
2345 13. FILTER_CONDITION string -> Filter condition, if any. (may be NULL )
2348 static const sal_Int32 C_SCHEMA
= 1;
2349 static const sal_Int32 C_TABLENAME
= 2;
2350 static const sal_Int32 C_INDEXNAME
= 3;
2351 static const sal_Int32 C_IS_CLUSTERED
= 4;
2352 static const sal_Int32 C_IS_UNIQUE
= 5;
2354 static const sal_Int32 C_COLUMNS
= 7;
2356 static const sal_Int32 R_TABLE_SCHEM
= 1;
2357 static const sal_Int32 R_TABLE_NAME
= 2;
2358 static const sal_Int32 R_NON_UNIQUE
= 3;
2359 static const sal_Int32 R_INDEX_NAME
= 5;
2360 static const sal_Int32 R_TYPE
= 6;
2361 static const sal_Int32 R_ORDINAL_POSITION
= 7;
2362 static const sal_Int32 R_COLUMN_NAME
= 8;
2364 Reference
< XPreparedStatement
> stmt
= m_origin
->prepareStatement(
2365 u
"SELECT nspname, " // 1
2366 "pg_class.relname, " // 2
2367 "class2.relname, " // 3
2368 "indisclustered, " // 4
2369 "indisunique, " // 5
2370 "indisprimary, " // 6
2372 "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid "
2373 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
2374 "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid "
2375 "WHERE nspname = ? AND pg_class.relname = ?"_ustr
);
2377 Reference
< XParameters
> param ( stmt
, UNO_QUERY_THROW
);
2378 param
->setString( 1, schema
);
2379 param
->setString( 2, table
);
2380 Reference
< XResultSet
> rs
= stmt
->executeQuery();
2381 Reference
< XRow
> xRow ( rs
, UNO_QUERY_THROW
);
2383 std::vector
< std::vector
<Any
> > vec
;
2386 std::vector
< sal_Int32
> columns
= parseIntArray( xRow
->getString(C_COLUMNS
) );
2387 Reference
< XPreparedStatement
> columnsStmt
= m_origin
->prepareStatement(
2388 u
"SELECT attnum, attname "
2389 "FROM pg_attribute "
2390 " INNER JOIN pg_class ON attrelid = pg_class.oid "
2391 " INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid "
2392 " WHERE pg_namespace.nspname=? AND pg_class.relname=?"_ustr
);
2393 Reference
< XParameters
> paramColumn ( columnsStmt
, UNO_QUERY_THROW
);
2394 OUString currentSchema
= xRow
->getString( C_SCHEMA
);
2395 OUString currentTable
= xRow
->getString( C_TABLENAME
);
2396 OUString currentIndexName
= xRow
->getString( C_INDEXNAME
);
2397 bool isNonUnique
= ! xRow
->getBoolean( C_IS_UNIQUE
);
2398 sal_Int32 indexType
= xRow
->getBoolean( C_IS_CLUSTERED
) ?
2399 css::sdbc::IndexType::CLUSTERED
:
2400 css::sdbc::IndexType::HASHED
;
2402 paramColumn
->setString( C_SCHEMA
, currentSchema
);
2403 paramColumn
->setString( C_TABLENAME
, currentTable
);
2405 Reference
< XResultSet
> rsColumn
= columnsStmt
->executeQuery();
2406 Reference
< XRow
> rowColumn( rsColumn
, UNO_QUERY_THROW
);
2407 while( rsColumn
->next() )
2409 auto findIt
= std::find( columns
.begin(), columns
.end(), rowColumn
->getInt( 1 ) );
2410 if( findIt
!= columns
.end() && ( ! isNonUnique
|| ! unique
) )
2412 std::vector
< Any
> result( 13 );
2413 result
[R_TABLE_SCHEM
] <<= currentSchema
;
2414 result
[R_TABLE_NAME
] <<= currentTable
;
2415 result
[R_INDEX_NAME
] <<= currentIndexName
;
2416 result
[R_NON_UNIQUE
] <<= isNonUnique
;
2417 result
[R_TYPE
] <<= indexType
;
2418 result
[R_COLUMN_NAME
] <<= rowColumn
->getString(2);
2419 sal_Int32 nPos
= static_cast<sal_Int32
>(findIt
- columns
.begin() +1); // MSVC++ nonsense
2420 result
[R_ORDINAL_POSITION
] <<= nPos
;
2421 vec
.push_back( result
);
2425 return new SequenceResultSet(
2426 m_xMutex
, *this, std::vector(getStatics().indexinfoColumnNames
),
2431 sal_Bool
DatabaseMetaData::supportsResultSetType( sal_Int32 setType
)
2433 if ( setType
== css::sdbc::ResultSetType::SCROLL_SENSITIVE
)
2439 sal_Bool
DatabaseMetaData::supportsResultSetConcurrency(
2440 sal_Int32 setType
, sal_Int32
)
2442 if ( ! supportsResultSetType( setType
) )
2448 sal_Bool
DatabaseMetaData::ownUpdatesAreVisible( sal_Int32
/* setType */ )
2453 sal_Bool
DatabaseMetaData::ownDeletesAreVisible( sal_Int32
/* setType */ )
2458 sal_Bool
DatabaseMetaData::ownInsertsAreVisible( sal_Int32
/* setType */ )
2463 sal_Bool
DatabaseMetaData::othersUpdatesAreVisible( sal_Int32
/* setType */ )
2468 sal_Bool
DatabaseMetaData::othersDeletesAreVisible( sal_Int32
/* setType */ )
2473 sal_Bool
DatabaseMetaData::othersInsertsAreVisible( sal_Int32
/* setType */ )
2478 sal_Bool
DatabaseMetaData::updatesAreDetected( sal_Int32
/* setType */ )
2483 sal_Bool
DatabaseMetaData::deletesAreDetected( sal_Int32
/* setType */ )
2487 sal_Bool
DatabaseMetaData::insertsAreDetected( sal_Int32
/* setType */ )
2492 sal_Bool
DatabaseMetaData::supportsBatchUpdates( )
2497 css::uno::Reference
< XResultSet
> DatabaseMetaData::getUDTs( const css::uno::Any
&, const OUString
&, const OUString
&, const css::uno::Sequence
< sal_Int32
>& )
2499 //LEM TODO: implement! See JDBC driver
2500 MutexGuard
guard( m_xMutex
->GetMutex() );
2501 return new SequenceResultSet(
2502 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
2505 css::uno::Reference
< css::sdbc::XConnection
> DatabaseMetaData::getConnection()
2511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */