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 <sal/log.hxx>
69 #include "pq_databasemetadata.hxx"
70 #include "pq_driver.hxx"
71 #include "pq_sequenceresultset.hxx"
72 #include "pq_statics.hxx"
73 #include "pq_tools.hxx"
75 #include <rtl/ustrbuf.hxx>
76 #include <sal/macros.h>
77 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
78 #include <com/sun/star/sdbc/ResultSetType.hpp>
79 #include <com/sun/star/sdbc/XParameters.hpp>
80 #include <com/sun/star/sdbc/DataType.hpp>
81 #include <com/sun/star/sdbc/IndexType.hpp>
82 #include <com/sun/star/sdbc/ColumnValue.hpp>
83 #include <com/sun/star/sdbc/ColumnSearch.hpp>
85 using ::osl::MutexGuard
;
88 using namespace com::sun::star::sdbc
;
90 using com::sun::star::uno::Reference
;
91 using com::sun::star::uno::Sequence
;
92 using com::sun::star::uno::Any
;
93 using com::sun::star::uno::UNO_QUERY
;
94 using com::sun::star::uno::UNO_QUERY_THROW
;
96 namespace pq_sdbc_driver
98 // These are pre-processor versions of KeyRule.idl declarations
99 // These are inherited from JDBC, and thus won't change anytime soon.
100 // Having them as pre-processor definitions allows to include them
101 // into compile-time strings (through SAL_STRINGIFY), which can be passed to ASCII_STR.
102 // That is without resorting to horrendous hacks in template meta-programming.
103 #define KEYRULE_CASCADE 0
104 #define KEYRULE_RESTRICT 1
105 #define KEYRULE_SET_NULL 2
106 #define KEYRULE_NO_ACTION 4
107 #define KEYRULE_SET_DEFAULT 4
108 // Ditto for Deferrability.idl
109 #define DEFERRABILITY_INITIALLY_DEFERRED 5
110 #define DEFERRABILITY_INITIALLY_IMMEDIATE 6
111 #define DEFERRABILITY_NONE 7
113 DatabaseMetaData::DatabaseMetaData(
114 const ::rtl::Reference
< comphelper::RefCountedMutex
> & refMutex
,
115 const css::uno::Reference
< css::sdbc::XConnection
> & origin
,
116 ConnectionSettings
*pSettings
)
117 : m_xMutex( refMutex
),
118 m_pSettings( pSettings
),
120 m_getIntSetting_stmt ( m_origin
->prepareStatement("SELECT setting FROM pg_catalog.pg_settings WHERE name=?") )
122 init_getReferences_stmt();
123 init_getPrivs_stmt();
126 sal_Bool
DatabaseMetaData::allProceduresAreCallable( )
132 sal_Bool
DatabaseMetaData::allTablesAreSelectable( )
137 OUString
DatabaseMetaData::getURL( )
140 // LEM TODO: implement
144 OUString
DatabaseMetaData::getUserName( )
146 return m_pSettings
->user
;
149 sal_Bool
DatabaseMetaData::isReadOnly( )
155 sal_Bool
DatabaseMetaData::nullsAreSortedHigh( )
157 // Whether NULL values are considered, for sorting purposes, LARGER than any other value.
158 // Specification: http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#nullsAreSortedHigh()
159 // PostgreSQL behaviour: http://www.postgresql.org/docs/9.1/static/queries-order.html
163 sal_Bool
DatabaseMetaData::nullsAreSortedLow( )
165 return ! nullsAreSortedHigh();
168 sal_Bool
DatabaseMetaData::nullsAreSortedAtStart( )
173 sal_Bool
DatabaseMetaData::nullsAreSortedAtEnd( )
178 OUString
DatabaseMetaData::getDatabaseProductName( )
183 OUString
DatabaseMetaData::getDatabaseProductVersion( )
185 return OUString::createFromAscii( PQparameterStatus( m_pSettings
->pConnection
, "server_version" ) );
187 OUString
DatabaseMetaData::getDriverName( )
189 return "postgresql-sdbc";
192 OUString
DatabaseMetaData::getDriverVersion( )
194 return PQ_SDBC_DRIVER_VERSION
;
197 sal_Int32
DatabaseMetaData::getDriverMajorVersion( )
199 return PQ_SDBC_MAJOR
;
202 sal_Int32
DatabaseMetaData::getDriverMinorVersion( )
204 return PQ_SDBC_MINOR
;
207 sal_Bool
DatabaseMetaData::usesLocalFiles( )
210 // http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/XDatabaseMetaData_Interface
211 // says "Returns true when the catalog name of the
212 // database should not appear in the DatasourceBrowser
213 // of OpenOffice.org API, otherwise false is returned."
214 // So, hmmm, think about it.
218 sal_Bool
DatabaseMetaData::usesLocalFilePerTable( )
223 sal_Bool
DatabaseMetaData::supportsMixedCaseIdentifiers( )
228 sal_Bool
DatabaseMetaData::storesUpperCaseIdentifiers( )
233 sal_Bool
DatabaseMetaData::storesLowerCaseIdentifiers( )
239 sal_Bool
DatabaseMetaData::storesMixedCaseIdentifiers( )
245 sal_Bool
DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
250 sal_Bool
DatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
256 sal_Bool
DatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
262 sal_Bool
DatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
268 OUString
DatabaseMetaData::getIdentifierQuoteString( )
273 OUString
DatabaseMetaData::getSQLKeywords( )
275 // In Java 6, this is all keywords that are not SQL:2003
276 // In Java 2 v1.4 and as per LibreOffice SDK doc, this is all keywords that are not SQL92
277 // I understand this to mean "reserved keywords" only.
278 // See http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
279 // LEM TODO: consider using pg_get_keywords(), filter on catcode
284 "ASYMMETRIC," //SQL:2003
287 "CURRENT_CATALOG," //SQL:2008
288 "CURRENT_ROLE," //SQL:1999
289 "CURRENT_SCHEMA," //SQL:2008
294 "LIMIT," //SQL:1999; non-reserved in SQL:2003
295 "LOCALTIME," //SQL:1999
296 "LOCALTIMESTAMP," //SQL:1999
300 "PLACING," //non-reserved in SQL:2003
301 "RETURNING," //non-reserved in SQL:2008
302 "SIMILAR," //SQL:2003
308 OUString
DatabaseMetaData::getNumericFunctions( )
310 // See http://www.postgresql.org/docs/9.1/static/functions-math.html
311 // LEM TODO: Err... http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/Support_Scalar_Functions
312 // says this should be "Open Group CLI" names, not PostgreSQL names.
313 // Currently this is just a list of supported functions in PostgreSQL, with PostgreSQL names.
314 // And it is my job to map from Open Group CLI names/syntax to PostgreSQL names/syntax. Where? By parsing the SQL???
315 // Should look at what the JDBC driver is doing.
349 OUString
DatabaseMetaData::getStringFunctions( )
351 // See http://www.postgresql.org/docs/9.1/static/functions-string.html
380 "pg_client_encoding,"
386 "regexp_split_to_array,"
387 "regexp_split_to_table,"
403 OUString
DatabaseMetaData::getSystemFunctions( )
405 // See http://www.postgresql.org/docs/9.1/static/functions-info.html
406 // and http://www.postgresql.org/docs/9.1/static/functions-admin.html
420 "pg_is_other_temp_schema,"
421 "pg_listening_channels,"
423 "pg_postmaster_start_time,"
427 "has_any_column_privilege,"
428 "has_any_column_privilege,"
429 "has_any_column_privilege,"
430 "has_column_privilege,"
431 "has_database_privilege,"
432 "has_foreign_data_wrapper_privilege,"
433 "has_function_privilege,"
434 "has_language_privilege,"
435 "has_schema_privilege,"
436 "has_sequence_privilege,"
437 "has_server_privilege,"
438 "has_table_privilege,"
439 "has_tablespace_privilege,"
441 "pg_collation_is_visible,"
442 "pg_conversion_is_visible,"
443 "pg_function_is_visible,"
444 "pg_opclass_is_visible,"
445 "pg_operator_is_visible,"
446 "pg_table_is_visible,"
447 "pg_ts_config_is_visible,"
448 "pg_ts_dict_is_visible,"
449 "pg_ts_parser_is_visible,"
450 "pg_ts_template_is_visible,"
451 "pg_type_is_visible,"
453 "pg_describe_object,"
454 "pg_get_constraintdef,"
456 "pg_get_functiondef,"
457 "pg_get_function_arguments,"
458 "pg_get_function_identity_arguments,"
459 "pg_get_function_result,"
463 "pg_get_serial_sequence,"
467 "pg_options_to_table,"
468 "pg_tablespace_databases,"
474 "txid_current_snapshot,"
476 "txid_snapshot_xmax,"
477 "txid_snapshot_xmin,"
478 "txid_visible_in_snapshot,"
487 "pg_terminate_backend,"
488 "pg_create_restore_point,"
489 "pg_current_xlog_insert_location,"
490 "pg_current_xlog_location,"
495 "pg_xlogfile_name_offset,"
497 "pg_last_xlog_receive_location,"
498 "pg_last_xlog_replay_location,"
499 "pg_last_xact_replay_timestamp,"
500 "pg_is_xlog_replay_paused,"
501 "pg_xlog_replay_pause,"
502 "pg_xlog_replay_resume,"
509 "pg_tablespace_size,"
510 "pg_tablespace_size,"
511 "pg_total_relation_size,"
512 "pg_relation_filenode,"
513 "pg_relation_filepath,"
516 "pg_read_binary_file,"
519 "pg_advisory_lock_shared,"
520 "pg_advisory_unlock,"
521 "pg_advisory_unlock_all,"
522 "pg_advisory_unlock_shared,"
523 "pg_advisory_xact_lock,"
524 "pg_advisory_xact_lock_shared,"
525 "pg_try_advisory_lock,"
526 "pg_try_advisory_lock_shared,"
527 "pg_try_advisory_xact_lock,"
528 "pg_try_advisory_xact_lock_shared,"
532 OUString
DatabaseMetaData::getTimeDateFunctions( )
556 "statement_timestamp,"
558 "transaction_timestamp,"
561 OUString
DatabaseMetaData::getSearchStringEscape( )
565 OUString
DatabaseMetaData::getExtraNameCharacters( )
570 sal_Bool
DatabaseMetaData::supportsAlterTableWithAddColumn( )
575 sal_Bool
DatabaseMetaData::supportsAlterTableWithDropColumn( )
580 sal_Bool
DatabaseMetaData::supportsColumnAliasing( )
585 sal_Bool
DatabaseMetaData::nullPlusNonNullIsNull( )
590 sal_Bool
DatabaseMetaData::supportsTypeConversion( )
592 // LEM: this is specifically whether the "CONVERT" function is supported
593 // It seems that in PostgreSQL, that function is only for string encoding, so no.
597 sal_Bool
DatabaseMetaData::supportsConvert( sal_Int32
, sal_Int32
)
602 sal_Bool
DatabaseMetaData::supportsTableCorrelationNames( )
604 // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..."
609 sal_Bool
DatabaseMetaData::supportsDifferentTableCorrelationNames( )
613 sal_Bool
DatabaseMetaData::supportsExpressionsInOrderBy( )
618 sal_Bool
DatabaseMetaData::supportsOrderByUnrelated( )
623 sal_Bool
DatabaseMetaData::supportsGroupBy( )
628 sal_Bool
DatabaseMetaData::supportsGroupByUnrelated( )
633 sal_Bool
DatabaseMetaData::supportsGroupByBeyondSelect( )
638 sal_Bool
DatabaseMetaData::supportsLikeEscapeClause( )
643 sal_Bool
DatabaseMetaData::supportsMultipleResultSets( )
648 sal_Bool
DatabaseMetaData::supportsMultipleTransactions( )
650 // Allows multiple transactions open at once (on different connections!)
654 sal_Bool
DatabaseMetaData::supportsNonNullableColumns( )
660 sal_Bool
DatabaseMetaData::supportsMinimumSQLGrammar( )
665 sal_Bool
DatabaseMetaData::supportsCoreSQLGrammar( )
667 // LEM: jdbc driver says not, although the comments in it seem old
668 // fdo#45249 Base query design won't use any aggregate function
669 // (except COUNT(*) unless we say yes, so say yes.
670 // Actually, Base assumes *also* support for aggregate functions "collect, fusion, intersection"
671 // as soon as supportsCoreSQLGrammar() returns true.
672 // Those are *not* Core SQL, though. They are in optional feature S271 "Basic multiset support"
676 sal_Bool
DatabaseMetaData::supportsExtendedSQLGrammar( )
681 sal_Bool
DatabaseMetaData::supportsANSI92EntryLevelSQL( )
686 sal_Bool
DatabaseMetaData::supportsANSI92IntermediateSQL( )
688 // LEM: jdbc driver says not, although the comments in it seem old
692 sal_Bool
DatabaseMetaData::supportsANSI92FullSQL( )
694 // LEM: jdbc driver says not, although the comments in it seem old
698 sal_Bool
DatabaseMetaData::supportsIntegrityEnhancementFacility( )
700 // LEM: jdbc driver says yes, although comment says they are not sure what this means...
704 sal_Bool
DatabaseMetaData::supportsOuterJoins( )
709 sal_Bool
DatabaseMetaData::supportsFullOuterJoins( )
714 sal_Bool
DatabaseMetaData::supportsLimitedOuterJoins( )
720 OUString
DatabaseMetaData::getSchemaTerm( )
725 OUString
DatabaseMetaData::getProcedureTerm( )
730 OUString
DatabaseMetaData::getCatalogTerm( )
735 sal_Bool
DatabaseMetaData::isCatalogAtStart( )
740 OUString
DatabaseMetaData::getCatalogSeparator( )
745 sal_Bool
DatabaseMetaData::supportsSchemasInDataManipulation( )
750 sal_Bool
DatabaseMetaData::supportsSchemasInProcedureCalls( )
755 sal_Bool
DatabaseMetaData::supportsSchemasInTableDefinitions( )
760 sal_Bool
DatabaseMetaData::supportsSchemasInIndexDefinitions( )
765 sal_Bool
DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
770 sal_Bool
DatabaseMetaData::supportsCatalogsInDataManipulation( )
775 sal_Bool
DatabaseMetaData::supportsCatalogsInProcedureCalls( )
780 sal_Bool
DatabaseMetaData::supportsCatalogsInTableDefinitions( )
786 sal_Bool
DatabaseMetaData::supportsCatalogsInIndexDefinitions( )
792 sal_Bool
DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
798 // LEM TODO: positioned (through cursor) updates and deletes seem
799 // to be supported; see {UPDATE,DELETE} /table/ (...) WHERE CURRENT OF /cursor_name/" syntax
800 // and http://www.postgresql.org/docs/9.1/static/view-pg-cursors.html
801 // http://www.postgresql.org/docs/9.1/static/libpq-example.html actually uses a cursor :)
802 sal_Bool
DatabaseMetaData::supportsPositionedDelete( )
804 // LEM: jdbc driver says not, although the comments in it seem old
808 sal_Bool
DatabaseMetaData::supportsPositionedUpdate( )
810 // LEM: jdbc driver says not, although the comments in it seem old
815 sal_Bool
DatabaseMetaData::supportsSelectForUpdate( )
821 sal_Bool
DatabaseMetaData::supportsStoredProcedures( )
827 sal_Bool
DatabaseMetaData::supportsSubqueriesInComparisons( )
832 sal_Bool
DatabaseMetaData::supportsSubqueriesInExists( )
837 sal_Bool
DatabaseMetaData::supportsSubqueriesInIns( )
842 sal_Bool
DatabaseMetaData::supportsSubqueriesInQuantifieds( )
844 // LEM: jdbc driver says yes, although comment says they don't know what this means...
848 sal_Bool
DatabaseMetaData::supportsCorrelatedSubqueries( )
852 sal_Bool
DatabaseMetaData::supportsUnion( )
857 sal_Bool
DatabaseMetaData::supportsUnionAll( )
862 sal_Bool
DatabaseMetaData::supportsOpenCursorsAcrossCommit( )
867 sal_Bool
DatabaseMetaData::supportsOpenCursorsAcrossRollback( )
872 sal_Bool
DatabaseMetaData::supportsOpenStatementsAcrossCommit( )
876 sal_Bool
DatabaseMetaData::supportsOpenStatementsAcrossRollback( )
881 sal_Int32
DatabaseMetaData::getMaxBinaryLiteralLength( )
886 sal_Int32
DatabaseMetaData::getMaxCharLiteralLength( )
891 // Copied / adapted / simplified from JDBC driver
892 sal_Int32
DatabaseMetaData::getIntSetting(const OUString
& settingName
)
894 MutexGuard
guard( m_xMutex
->GetMutex() );
896 Reference
< XParameters
> params(m_getIntSetting_stmt
, UNO_QUERY_THROW
);
897 params
->setString(1, settingName
);
898 Reference
< XResultSet
> rs
= m_getIntSetting_stmt
->executeQuery();
899 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
900 OSL_VERIFY(rs
->next());
901 OSL_ENSURE(rs
->isFirst(), "postgresql-sdbc DatabaseMetaData getIntSetting not on first row");
902 OSL_ENSURE(rs
->isLast(), "postgresql-sdbc DatabaseMetaData getIntSetting not on last row");
903 return xRow
->getInt(1);
906 sal_Int32
DatabaseMetaData::getMaxNameLength()
908 if ( m_pSettings
->maxNameLen
== 0)
909 m_pSettings
->maxNameLen
= getIntSetting( "max_identifier_length" );
910 OSL_ENSURE(m_pSettings
->maxNameLen
, "postgresql-sdbc: maxNameLen is zero");
911 return m_pSettings
->maxNameLen
;
914 sal_Int32
DatabaseMetaData::getMaxIndexKeys()
916 if ( m_pSettings
->maxIndexKeys
== 0)
917 m_pSettings
->maxIndexKeys
= getIntSetting("max_index_keys");
918 OSL_ENSURE(m_pSettings
->maxIndexKeys
, "postgresql-sdbc: maxIndexKeys is zero");
919 return m_pSettings
->maxIndexKeys
;
922 sal_Int32
DatabaseMetaData::getMaxColumnNameLength( )
924 return getMaxNameLength();
927 sal_Int32
DatabaseMetaData::getMaxColumnsInGroupBy( )
932 sal_Int32
DatabaseMetaData::getMaxColumnsInIndex( )
934 return getMaxIndexKeys();
937 sal_Int32
DatabaseMetaData::getMaxColumnsInOrderBy( )
942 sal_Int32
DatabaseMetaData::getMaxColumnsInSelect( )
947 sal_Int32
DatabaseMetaData::getMaxColumnsInTable( )
952 sal_Int32
DatabaseMetaData::getMaxConnections( )
954 // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports
958 sal_Int32
DatabaseMetaData::getMaxCursorNameLength( ) //TODO, don't know
960 return getMaxNameLength();
963 sal_Int32
DatabaseMetaData::getMaxIndexLength( ) //TODO, don't know
965 // LEM: that's the index itself, not its name
969 sal_Int32
DatabaseMetaData::getMaxSchemaNameLength( )
971 return getMaxNameLength();
974 sal_Int32
DatabaseMetaData::getMaxProcedureNameLength( )
976 return getMaxNameLength();
979 sal_Int32
DatabaseMetaData::getMaxCatalogNameLength( )
981 return getMaxNameLength();
984 sal_Int32
DatabaseMetaData::getMaxRowSize( )
986 // jdbc driver says 1GB, but http://www.postgresql.org/about/ says 1.6TB
987 // and that 1GB is the maximum _field_ size
988 // The row limit does not fit into a sal_Int32
992 sal_Bool
DatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
994 // LEM: Err... PostgreSQL basically does not do BLOBs well
995 // In any case, BLOBs do not change the maximal row length AFAIK
999 sal_Int32
DatabaseMetaData::getMaxStatementLength( )
1001 // LEM: actually, that would be 2^sizeof(size_t)-1
1002 // on the server? on the client (because of libpq)? minimum of the two? not sure
1003 // Anyway, big, so say unlimited.
1007 sal_Int32
DatabaseMetaData::getMaxStatements( ) //TODO, don't know
1012 sal_Int32
DatabaseMetaData::getMaxTableNameLength( )
1014 return getMaxNameLength();
1017 sal_Int32
DatabaseMetaData::getMaxTablesInSelect( )
1022 sal_Int32
DatabaseMetaData::getMaxUserNameLength( )
1024 return getMaxNameLength();
1027 sal_Int32
DatabaseMetaData::getDefaultTransactionIsolation( )
1029 return css::sdbc::TransactionIsolation::READ_COMMITTED
;
1032 sal_Bool
DatabaseMetaData::supportsTransactions( )
1037 sal_Bool
DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level
)
1039 if ( level
== css::sdbc::TransactionIsolation::READ_COMMITTED
1040 || level
== css::sdbc::TransactionIsolation::SERIALIZABLE
1041 || level
== css::sdbc::TransactionIsolation::READ_UNCOMMITTED
1042 || level
== css::sdbc::TransactionIsolation::REPEATABLE_READ
)
1048 sal_Bool
DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
1053 sal_Bool
DatabaseMetaData::supportsDataManipulationTransactionsOnly( )
1058 sal_Bool
DatabaseMetaData::dataDefinitionCausesTransactionCommit( )
1063 sal_Bool
DatabaseMetaData::dataDefinitionIgnoredInTransactions( )
1068 css::uno::Reference
< XResultSet
> DatabaseMetaData::getProcedures(
1069 const css::uno::Any
&,
1073 // 1. PROCEDURE_CAT string => procedure catalog (may be NULL )
1074 // 2. PROCEDURE_SCHEM string => procedure schema (may be NULL )
1075 // 3. PROCEDURE_NAME string => procedure name
1076 // 4. reserved for future use
1077 // 5. reserved for future use
1078 // 6. reserved for future use
1079 // 7. REMARKS string => explanatory comment on the procedure
1080 // 8. PROCEDURE_TYPE short => kind of procedure:
1081 // * UNKNOWN - May return a result
1082 // * NO - Does not return a result
1083 // * RETURN - Returns a result
1085 // LEM TODO: implement
1086 // LEM TODO: at least fake the columns, even if no row.
1087 MutexGuard
guard( m_xMutex
->GetMutex() );
1088 return new SequenceResultSet(
1089 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> > (), m_pSettings
->tc
);
1092 css::uno::Reference
< XResultSet
> DatabaseMetaData::getProcedureColumns(
1093 const css::uno::Any
&,
1098 MutexGuard
guard( m_xMutex
->GetMutex() );
1099 // LEM TODO: implement
1100 // LEM TODO: at least fake the columns, even if no row.
1101 return new SequenceResultSet(
1102 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1105 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTables(
1106 const css::uno::Any
&,
1107 const OUString
& schemaPattern
,
1108 const OUString
& tableNamePattern
,
1109 const css::uno::Sequence
< OUString
>& )
1111 Statics
&statics
= getStatics();
1113 MutexGuard
guard( m_xMutex
->GetMutex() );
1115 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTables() got called with " << schemaPattern
<< "." << tableNamePattern
);
1117 // ignore catalog, as a single pq connection does not support multiple catalogs
1119 // LEM TODO: this does not give the right column names, not the right number of columns, etc.
1120 // Take "inspiration" from JDBC driver
1121 // Ah, this is used to create a XResultSet manually... Try to do it directly in SQL
1122 Reference
< XPreparedStatement
> statement
= m_origin
->prepareStatement(
1124 "DISTINCT ON (pg_namespace.nspname, relname ) " // avoid duplicates (pg_settings !)
1125 "pg_namespace.nspname, relname, relkind, pg_description.description "
1126 "FROM pg_namespace, pg_class LEFT JOIN pg_description ON pg_class.oid = pg_description.objoid "
1127 "WHERE relnamespace = pg_namespace.oid "
1128 "AND ( relkind = 'r' OR relkind = 'v') "
1129 "AND pg_namespace.nspname LIKE ? "
1130 "AND relname LIKE ? "
1131 // "ORDER BY pg_namespace.nspname || relname"
1134 Reference
< XParameters
> parameters( statement
, UNO_QUERY_THROW
);
1135 parameters
->setString( 1 , schemaPattern
);
1136 parameters
->setString( 2 , tableNamePattern
);
1138 Reference
< XResultSet
> rs
= statement
->executeQuery();
1139 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1140 std::vector
< std::vector
<Any
> > vec
;
1144 std::vector
< Any
> row( 5 );
1146 row
[0] <<= m_pSettings
->catalog
;
1147 row
[1] <<= xRow
->getString( 1 );
1148 row
[2] <<= xRow
->getString( 2 );
1149 OUString type
= xRow
->getString(3);
1152 if( xRow
->getString(1) == "pg_catalog" )
1154 row
[3] <<= statics
.SYSTEM_TABLE
;
1158 row
[3] <<= statics
.TABLE
;
1161 else if( type
== "v" )
1163 row
[3] <<= statics
.VIEW
;
1167 row
[3] <<= statics
.UNKNOWN
;
1169 row
[4] <<= xRow
->getString(4);
1171 // no description in postgresql AFAIK
1172 vec
.push_back( row
);
1174 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1175 if( closeable
.is() )
1178 return new SequenceResultSet(
1179 m_xMutex
, *this, statics
.tablesRowNames
, vec
, m_pSettings
->tc
);
1184 // sort no schema first, then "public", then normal schemas, then internal schemas
1185 int compare_schema(const OUString
&nsA
, const OUString
&nsB
)
1189 return nsB
.isEmpty() ? 0 : -1;
1191 else if (nsB
.isEmpty())
1193 assert(!nsA
.isEmpty());
1196 else if(nsA
== "public")
1198 return (nsB
== "public") ? 0 : -1;
1200 else if(nsB
== "public")
1202 assert(nsA
!= "public");
1205 else if(nsA
.startsWith("pg_"))
1207 if(nsB
.startsWith("pg_"))
1208 return nsA
.compareTo(nsB
);
1212 else if(nsB
.startsWith("pg_"))
1218 return nsA
.compareTo(nsB
);
1222 struct SortInternalSchemasLastAndPublicFirst
1224 bool operator () ( const std::vector
< Any
> & a
, const std::vector
< Any
> & b
)
1230 return compare_schema(valueA
, valueB
);
1235 css::uno::Reference
< XResultSet
> DatabaseMetaData::getSchemas( )
1237 MutexGuard
guard( m_xMutex
->GetMutex() );
1239 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getSchemas() got called");
1241 // <b>TABLE_SCHEM</b> string =&gt; schema name
1242 Reference
< XStatement
> statement
= m_origin
->createStatement();
1243 Reference
< XResultSet
> rs
= statement
->executeQuery(
1244 "SELECT nspname from pg_namespace" );
1245 // LEM TODO: look at JDBC driver and consider doing the same
1246 // in particular, excluding temporary schemas, but maybe better through pg_is_other_temp_schema(oid) OR == pg_my_temp_schema()
1248 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1249 std::vector
< std::vector
<Any
> > vec
;
1252 std::vector
<Any
> row(1);
1253 row
[0] <<= xRow
->getString(1);
1254 vec
.push_back( row
);
1257 // sort public first, sort internal schemas last, sort rest in alphabetic order
1258 std::sort( vec
.begin(), vec
.end(), SortInternalSchemasLastAndPublicFirst() );
1260 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1261 if( closeable
.is() )
1263 return new SequenceResultSet(
1264 m_xMutex
, *this, getStatics().schemaNames
, vec
, m_pSettings
->tc
);
1267 css::uno::Reference
< XResultSet
> DatabaseMetaData::getCatalogs( )
1269 // LEM TODO: return the current catalog like JDBC driver?
1270 // at least fake the columns, even if no content
1271 MutexGuard
guard( m_xMutex
->GetMutex() );
1272 return new SequenceResultSet(
1273 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1276 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTableTypes( )
1278 // LEM TODO: this can be made dynamic, see JDBC driver
1279 MutexGuard
guard( m_xMutex
->GetMutex() );
1280 return new SequenceResultSet(
1281 m_xMutex
, *this, getStatics().tableTypeNames
, getStatics().tableTypeData
,
1286 /** returns the constant from sdbc.DataType
1288 sal_Int32
typeNameToDataType( const OUString
&typeName
, const OUString
&typtype
)
1290 // sal_Int32 ret = css::sdbc::DataType::DISTINCT;
1291 // map all unknown types to memo (longvarchar). This allows to show them in
1292 // string representation. Additionally, the edit-table-type-selection-box
1293 // is not so unusable anymore.
1294 sal_Int32 ret
= css::sdbc::DataType::LONGVARCHAR
;
1295 if( typtype
== "b" )
1297 // as long as the OOo framework does not support arrays,
1298 // the user is better of with interpreting arrays as strings !
1299 // if( typeName.getLength() && '_' == typeName[0] )
1301 // it's just a naming convention, but as long as we don't have anything better,
1302 // we take it as granted
1303 // ret = css::sdbc::DataType::ARRAY;
1306 Statics
&statics
= getStatics();
1307 BaseTypeMap::const_iterator ii
= statics
.baseTypeMap
.find( typeName
);
1308 if( ii
!= statics
.baseTypeMap
.end() )
1313 else if( typtype
== "c" )
1315 ret
= css::sdbc::DataType::STRUCT
;
1317 else if( typtype
== "d" )
1319 ret
= css::sdbc::DataType::LONGVARCHAR
;
1325 bool isSystemColumn( sal_Int16 attnum
)
1330 // is not exported by the postgres header
1331 const int PQ_VARHDRSZ
= sizeof( sal_Int32
);
1333 // Oh, quelle horreur
1334 // LEM TODO: Need to severely rewrite that!
1335 // should probably just "do the same" as ODBC or JDBC drivers...
1336 void extractPrecisionAndScale(
1337 sal_Int32 dataType
, sal_Int32 atttypmod
, sal_Int32
*precision
, sal_Int32
*scale
)
1339 if( atttypmod
< PQ_VARHDRSZ
)
1348 case css::sdbc::DataType::NUMERIC
:
1349 case css::sdbc::DataType::DECIMAL
:
1351 *precision
= ( ( atttypmod
- PQ_VARHDRSZ
) >> 16 ) & 0xffff;
1352 *scale
= (atttypmod
- PQ_VARHDRSZ
) & 0xffff;
1356 *precision
= atttypmod
- PQ_VARHDRSZ
;
1362 struct DatabaseTypeDescription
1364 DatabaseTypeDescription()
1366 DatabaseTypeDescription( const OUString
&name
, const OUString
& type
) :
1370 DatabaseTypeDescription( const DatabaseTypeDescription
&source
) :
1371 typeName( source
.typeName
),
1372 typeType( source
.typeType
)
1374 DatabaseTypeDescription
& operator = ( const DatabaseTypeDescription
& source
)
1376 typeName
= source
.typeName
;
1377 typeType
= source
.typeType
;
1385 typedef std::unordered_map
1388 DatabaseTypeDescription
1389 > Oid2DatabaseTypeDescriptionMap
;
1391 static void columnMetaData2DatabaseTypeDescription(
1392 Oid2DatabaseTypeDescriptionMap
&oidMap
,
1393 const Reference
< XResultSet
> &rs
,
1394 const Reference
< XStatement
> &stmt
)
1396 Reference
< XRow
> row( rs
, UNO_QUERY_THROW
);
1398 OUStringBuffer
queryBuf(128);
1399 queryBuf
.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " );
1402 if( row
->getString( 9 ) == "d" && oidMap
.find( row
->getInt( 12 ) ) == oidMap
.end() )
1404 oidMap
[row
->getInt(12)] = DatabaseTypeDescription();
1406 queryBuf
.append( " OR " );
1407 queryBuf
.append( "oid = " );
1408 queryBuf
.append( row
->getInt(12 ) );
1416 Reference
< XResultSet
> rsDomain
= stmt
->executeQuery( queryBuf
.makeStringAndClear() );
1417 row
.set( rsDomain
, UNO_QUERY_THROW
);
1418 while( rsDomain
->next() )
1420 oidMap
[row
->getInt(1)] = DatabaseTypeDescription(row
->getString(3), row
->getString(2) );
1422 disposeNoThrow( stmt
);
1428 css::uno::Reference
< XResultSet
> DatabaseMetaData::getColumns(
1429 const css::uno::Any
&,
1430 const OUString
& schemaPattern
,
1431 const OUString
& tableNamePattern
,
1432 const OUString
& columnNamePattern
)
1434 // LEM TODO: review in comparison with JDBC driver
1435 Statics
&statics
= getStatics();
1438 MutexGuard
guard( m_xMutex
->GetMutex() );
1440 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumns() got called with "
1441 << schemaPattern
<< "." << tableNamePattern
<< "." << columnNamePattern
);
1443 // ignore catalog, as a single pq connection
1444 // does not support multiple catalogs anyway
1445 // We don't use information_schema.columns because it contains
1446 // only the columns the current user has any privilege over.
1448 // 1. TABLE_CAT string => table catalog (may be NULL)
1450 // 2. TABLE_SCHEM string => table schema (may be NULL)
1451 // => pg_namespace.nspname
1452 // 3. TABLE_NAME string => table name
1453 // => pg_class.relname
1454 // 4. COLUMN_NAME string => column name
1455 // => pg_attribute.attname
1456 // 5. DATA_TYPE short => SQL type from java.sql.Types
1457 // => pg_type.typname => sdbc.DataType
1458 // 6. TYPE_NAME string => Data source dependent type name, for a UDT the
1459 // type name is fully qualified
1460 // => pg_type.typname
1461 // 7. COLUMN_SIZE long => column size. For char or date types this is
1462 // the maximum number of characters, for numeric
1463 // or decimal types this is precision.
1464 // => pg_attribute.atttypmod
1465 // 8. BUFFER_LENGTH is not used.
1467 // 9. DECIMAL_DIGITS long => the number of fractional digits
1468 // => don't know ! TODO !
1469 // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2)
1471 // 11. NULLABLE long => is NULL allowed?
1472 // NO_NULLS - might not allow NULL values
1473 // NULABLE - definitely allows NULL values
1474 // NULLABLE_UNKNOWN - nullability unknown
1475 // => pg_attribute.attnotnull
1476 // 12. REMARKS string => comment describing column (may be NULL )
1477 // => pg_description.description
1478 // 13. COLUMN_DEF string => default value (may be NULL)
1479 // => pg_type.typdefault
1480 // 14. SQL_DATA_TYPE long => unused
1482 // 15. SQL_DATETIME_SUB long => unused
1484 // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of
1485 // bytes in the column
1486 // => pg_type.typlen
1487 // 17. ORDINAL_POSITION int => index of column in table (starting at 1)
1488 // pg_attribute.attnum
1489 // 18. IS_NULLABLE string => "NO" means column definitely does not allow
1490 // NULL values; "YES" means the column might
1491 // allow NULL values. An empty string means
1493 // => pg_attribute.attnotnull
1494 OUString strDefaultValue
= getColExprForDefaultSettingVal(m_pSettings
);
1495 Reference
< XPreparedStatement
> statement
= m_origin
->prepareStatement(
1496 "SELECT pg_namespace.nspname, " // 1
1497 "pg_class.relname, " // 2
1498 "pg_attribute.attname, " // 3
1499 "pg_type.typname, " // 4
1500 "pg_attribute.atttypmod, " // 5
1501 "pg_attribute.attnotnull, " // 6
1502 "pg_type.typdefault, " // 7
1503 "pg_type.typtype, " // 8
1504 + strDefaultValue
+ // 9
1505 ",pg_description.description, " // 10
1506 "pg_type.typbasetype, " // 11
1507 "pg_attribute.attnum " // 12
1509 "pg_attribute LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum "
1510 "LEFT JOIN pg_description ON pg_attribute.attrelid = pg_description.objoid AND pg_attribute.attnum=pg_description.objsubid,"
1511 " pg_type, pg_namespace "
1512 "WHERE pg_attribute.attrelid = pg_class.oid "
1513 "AND pg_attribute.atttypid = pg_type.oid "
1514 "AND pg_class.relnamespace = pg_namespace.oid "
1515 "AND NOT pg_attribute.attisdropped "
1516 "AND pg_namespace.nspname LIKE ? "
1517 "AND pg_class.relname LIKE ? "
1518 "AND pg_attribute.attname LIKE ? "
1519 "ORDER BY pg_namespace.nspname, pg_class.relname, pg_attribute.attnum"
1522 Reference
< XParameters
> parameters( statement
, UNO_QUERY_THROW
);
1523 parameters
->setString( 1 , schemaPattern
);
1524 parameters
->setString( 2 , tableNamePattern
);
1525 parameters
->setString( 3 , columnNamePattern
);
1527 Reference
< XResultSet
> rs
= statement
->executeQuery();
1528 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1529 std::vector
< std::vector
<Any
> > vec
;
1531 Oid2DatabaseTypeDescriptionMap domainMap
;
1532 Reference
< XStatement
> domainTypeStmt
= m_origin
->createStatement();
1533 columnMetaData2DatabaseTypeDescription( domainMap
, rs
, domainTypeStmt
);
1535 sal_uInt32
colNum(0);
1536 OUString
sSchema( "#invalid#" );
1537 OUString
sTable( "#invalid#" );
1541 if( ! isSystemColumn( xRow
->getShort( 12 ) ) )
1543 OUString
sNewSchema( xRow
->getString(1) );
1544 OUString
sNewTable( xRow
->getString(2) );
1545 if ( sNewSchema
!= sSchema
|| sNewTable
!= sTable
)
1548 sSchema
= sNewSchema
;
1553 sal_Int32 precision
, scale
, type
;
1554 std::vector
< Any
> row( 18 );
1555 row
[0] <<= m_pSettings
->catalog
;
1556 row
[1] <<= sNewSchema
;
1557 row
[2] <<= sNewTable
;
1558 row
[3] <<= xRow
->getString(3);
1559 if( xRow
->getString(8) == "d" )
1561 DatabaseTypeDescription
desc( domainMap
[xRow
->getInt(11)] );
1562 type
= typeNameToDataType( desc
.typeName
, desc
.typeType
);
1566 type
= typeNameToDataType( xRow
->getString(4), xRow
->getString(8) );
1568 extractPrecisionAndScale( type
, xRow
->getInt(5) , &precision
, &scale
);
1570 row
[5] <<= xRow
->getString(4);
1571 row
[6] <<= precision
;
1572 // row[7] BUFFER_LENGTH not used
1574 // row[9] RADIX TODO
1575 if( xRow
->getBoolean( 6 ) && ! isSystemColumn(xRow
->getInt( 12 )) )
1577 row
[10] <<= OUString::number(css::sdbc::ColumnValue::NO_NULLS
);
1578 row
[17] <<= statics
.NO
;
1582 row
[10] <<= OUString::number(css::sdbc::ColumnValue::NULLABLE
);
1583 row
[17] <<= statics
.YES
;
1586 row
[11] <<= xRow
->getString( 10 ); // comment
1587 row
[12] <<= xRow
->getString( 9 ); // COLUMN_DEF = pg_type.typdefault
1588 // row[13] SQL_DATA_TYPE not used
1589 // row[14] SQL_DATETIME_SUB not used
1590 row
[15] <<= precision
;
1591 row
[16] <<= colNum
;
1593 vec
.push_back( row
);
1596 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1597 if( closeable
.is() )
1600 return new SequenceResultSet(
1601 m_xMutex
, *this, statics
.columnRowNames
, vec
, m_pSettings
->tc
);
1604 css::uno::Reference
< XResultSet
> DatabaseMetaData::getColumnPrivileges(
1605 const css::uno::Any
&,
1606 const OUString
& schema
,
1607 const OUString
& table
,
1608 const OUString
& columnNamePattern
)
1610 MutexGuard
guard( m_xMutex
->GetMutex() );
1612 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumnPrivileges() got called with "
1613 << schema
<< "." << table
<< "." << columnNamePattern
);
1615 Reference
< XParameters
> parameters( m_getColumnPrivs_stmt
, UNO_QUERY_THROW
);
1616 parameters
->setString( 1 , schema
);
1617 parameters
->setString( 2 , table
);
1618 parameters
->setString( 3 , columnNamePattern
);
1620 Reference
< XResultSet
> rs
= m_getColumnPrivs_stmt
->executeQuery();
1625 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTablePrivileges(
1626 const css::uno::Any
&,
1627 const OUString
& schemaPattern
,
1628 const OUString
& tableNamePattern
)
1630 MutexGuard
guard( m_xMutex
->GetMutex() );
1632 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTablePrivileges() got called with "
1633 << schemaPattern
<< "." << tableNamePattern
);
1635 Reference
< XParameters
> parameters( m_getTablePrivs_stmt
, UNO_QUERY_THROW
);
1636 parameters
->setString( 1 , schemaPattern
);
1637 parameters
->setString( 2 , tableNamePattern
);
1639 Reference
< XResultSet
> rs
= m_getTablePrivs_stmt
->executeQuery();
1644 css::uno::Reference
< XResultSet
> DatabaseMetaData::getBestRowIdentifier(
1645 const css::uno::Any
&,
1651 //LEM TODO: implement! See JDBC driver
1652 MutexGuard
guard( m_xMutex
->GetMutex() );
1653 return new SequenceResultSet(
1654 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1657 css::uno::Reference
< XResultSet
> DatabaseMetaData::getVersionColumns(
1658 const css::uno::Any
&,
1662 //LEM TODO: implement! See JDBC driver
1663 MutexGuard
guard( m_xMutex
->GetMutex() );
1664 return new SequenceResultSet(
1665 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
1668 css::uno::Reference
< XResultSet
> DatabaseMetaData::getPrimaryKeys(
1669 const css::uno::Any
&,
1670 const OUString
& schema
,
1671 const OUString
& table
)
1674 MutexGuard
guard( m_xMutex
->GetMutex() );
1676 // 1. TABLE_CAT string => table catalog (may be NULL )
1677 // 2. TABLE_SCHEM string => table schema (may be NULL )
1678 // 3. TABLE_NAME string => table name
1679 // 4. COLUMN_NAME string => column name
1680 // 5. KEY_SEQ short => sequence number within primary key
1681 // 6. PK_NAME string => primary key name (may be NULL )
1683 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getPrimaryKeys() got called with "
1684 << schema
<< "." << table
);
1686 Reference
< XPreparedStatement
> statement
= m_origin
->prepareStatement(
1687 "SELECT nmsp.nspname, "
1692 "FROM pg_constraint as con,pg_class as cl, pg_namespace as nmsp "
1693 "WHERE con.connamespace = nmsp.oid AND con.conrelid = cl.oid AND con.contype = 'p' "
1694 "AND nmsp.nspname LIKE ? AND cl.relname LIKE ?" );
1696 Reference
< XParameters
> parameters( statement
, UNO_QUERY_THROW
);
1697 parameters
->setString( 1 , schema
);
1698 parameters
->setString( 2 , table
);
1700 Reference
< XResultSet
> rs
= statement
->executeQuery();
1701 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
1702 std::vector
< std::vector
<Any
> > vec
;
1706 std::vector
< Any
> row( 6 );
1707 row
[0] <<= m_pSettings
->catalog
;
1708 row
[1] <<= xRow
->getString(1);
1709 row
[2] <<= xRow
->getString(2);
1710 OUString array
= xRow
->getString(3);
1711 row
[4] <<= xRow
->getString(5); // the relid
1712 row
[5] <<= xRow
->getString(4);
1715 // now retrieve the columns information
1716 // unfortunately, postgresql does not allow array of variable size in
1717 // WHERE clauses (in the default installation), so we have to choose
1718 // this expensive and somewhat ugly way
1719 // annotation: postgresql shouldn't have chosen an array here, instead they
1720 // should have multiple rows per table
1721 // LEM: to transform an array into several rows, see unnest;
1722 // it is as simple as "SELECT foo, bar, unnest(qux) FROM ..."
1723 // where qux is the column that contains an array.
1724 while( array
[i
] && '}' != array
[i
] )
1728 while( array
[i
] && array
[i
] != '}' && array
[i
] != ',' ) i
++;
1729 row
[3] <<= array
.copy(start
, i
- start
);
1730 vec
.push_back( row
);
1735 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1736 if( closeable
.is() )
1741 OUString lastTableOid
;
1742 sal_Int32 index
= 0;
1743 std::vector
< std::vector
< Any
> > ret( vec
.size() );
1745 for (auto const& elem
: vec
)
1748 std::vector
< Any
> row
= elem
;
1752 row
[4] >>= tableOid
;
1754 statement
= m_origin
->prepareStatement(
1755 "SELECT att.attname FROM "
1756 "pg_attribute AS att, pg_class AS cl WHERE "
1757 "att.attrelid = ? AND att.attnum = ?" );
1759 parameters
.set( statement
, UNO_QUERY_THROW
);
1760 parameters
->setString( 1 , tableOid
);
1761 parameters
->setString( 2 , attnum
);
1763 rs
= statement
->executeQuery();
1764 xRow
.set( rs
, UNO_QUERY_THROW
);
1768 row
[3] <<= xRow
->getString( 1 );
1769 if( tableOid
!= lastTableOid
)
1771 lastTableOid
= tableOid
;
1772 row
[4] <<= OUString::number( index
);
1776 Reference
< XCloseable
> closeable( statement
, UNO_QUERY
);
1777 if( closeable
.is() )
1780 ret
[elements
] = row
;
1783 return new SequenceResultSet(
1784 m_xMutex
, *this, getStatics().primaryKeyNames
, ret
, m_pSettings
->tc
);
1787 // Copied / adapted / simplified from JDBC driver
1788 #define SQL_CASE_KEYRULE " WHEN 'c' THEN " SAL_STRINGIFY(KEYRULE_CASCADE) \
1789 " WHEN 'n' THEN " SAL_STRINGIFY(KEYRULE_SET_NULL) \
1790 " WHEN 'd' THEN " SAL_STRINGIFY(KEYRULE_SET_DEFAULT) \
1791 " WHEN 'r' THEN " SAL_STRINGIFY(KEYRULE_RESTRICT) \
1792 " WHEN 'a' THEN " SAL_STRINGIFY(KEYRULE_NO_ACTION) \
1795 #define SQL_GET_REFERENCES \
1796 "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) " \
1797 "SELECT NULL::text AS PKTABLE_CAT, pkn.nspname AS PKTABLE_SCHEM, pkc.relname AS PKTABLE_NAME, pka.attname AS PKCOLUMN_NAME, " \
1798 " NULL::text AS FKTABLE_CAT, fkn.nspname AS FKTABLE_SCHEM, fkc.relname AS FKTABLE_NAME, fka.attname AS FKCOLUMN_NAME, " \
1799 " con.conkeyseq AS KEY_SEQ, " \
1800 " CASE con.confupdtype " \
1802 " END AS UPDATE_RULE, " \
1803 " CASE con.confdeltype " \
1805 " END AS DELETE_RULE, " \
1806 " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \
1808 " WHEN con.condeferrable AND con.condeferred THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_DEFERRED) \
1809 " WHEN con.condeferrable THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_IMMEDIATE) \
1810 " ELSE " SAL_STRINGIFY(DEFERRABILITY_NONE) \
1811 " END AS DEFERRABILITY " \
1813 " pg_catalog.pg_namespace pkn, pg_catalog.pg_class pkc, pg_catalog.pg_attribute pka, " \
1814 " pg_catalog.pg_namespace fkn, pg_catalog.pg_class fkc, pg_catalog.pg_attribute fka, " \
1815 " con, pg_catalog.pg_depend dep, pg_catalog.pg_class pkic " \
1816 "WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey AND con.confrelid = pkc.oid " \
1817 " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey AND con.conrelid = fkc.oid " \
1818 " 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 "
1820 #define SQL_GET_REFERENCES_PSCHEMA " AND pkn.nspname = ? "
1821 #define SQL_GET_REFERENCES_PTABLE " AND pkc.relname = ? "
1822 #define SQL_GET_REFERENCES_FSCHEMA " AND fkn.nspname = ? "
1823 #define SQL_GET_REFERENCES_FTABLE " AND fkc.relname = ? "
1824 #define SQL_GET_REFERENCES_ORDER_SOME_PTABLE "ORDER BY fkn.nspname, fkc.relname, conkeyseq"
1825 #define SQL_GET_REFERENCES_ORDER_NO_PTABLE "ORDER BY pkn.nspname, pkc.relname, conkeyseq"
1827 #define SQL_GET_REFERENCES_NONE_NONE_NONE_NONE \
1828 SQL_GET_REFERENCES \
1829 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1831 #define SQL_GET_REFERENCES_SOME_NONE_NONE_NONE \
1832 SQL_GET_REFERENCES \
1833 SQL_GET_REFERENCES_PSCHEMA \
1834 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1836 #define SQL_GET_REFERENCES_NONE_SOME_NONE_NONE \
1837 SQL_GET_REFERENCES \
1838 SQL_GET_REFERENCES_PTABLE \
1839 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1841 #define SQL_GET_REFERENCES_SOME_SOME_NONE_NONE \
1842 SQL_GET_REFERENCES \
1843 SQL_GET_REFERENCES_PSCHEMA \
1844 SQL_GET_REFERENCES_PTABLE \
1845 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1847 #define SQL_GET_REFERENCES_NONE_NONE_SOME_NONE \
1848 SQL_GET_REFERENCES \
1849 SQL_GET_REFERENCES_FSCHEMA \
1850 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1852 #define SQL_GET_REFERENCES_NONE_NONE_NONE_SOME \
1853 SQL_GET_REFERENCES \
1854 SQL_GET_REFERENCES_FTABLE \
1855 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1857 #define SQL_GET_REFERENCES_NONE_NONE_SOME_SOME \
1858 SQL_GET_REFERENCES \
1859 SQL_GET_REFERENCES_FSCHEMA \
1860 SQL_GET_REFERENCES_FTABLE \
1861 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1863 #define SQL_GET_REFERENCES_SOME_NONE_SOME_NONE \
1864 SQL_GET_REFERENCES \
1865 SQL_GET_REFERENCES_PSCHEMA \
1866 SQL_GET_REFERENCES_FSCHEMA \
1867 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1869 #define SQL_GET_REFERENCES_SOME_NONE_NONE_SOME \
1870 SQL_GET_REFERENCES \
1871 SQL_GET_REFERENCES_PSCHEMA \
1872 SQL_GET_REFERENCES_FTABLE \
1873 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1875 #define SQL_GET_REFERENCES_SOME_NONE_SOME_SOME \
1876 SQL_GET_REFERENCES \
1877 SQL_GET_REFERENCES_PSCHEMA \
1878 SQL_GET_REFERENCES_FSCHEMA \
1879 SQL_GET_REFERENCES_FTABLE \
1880 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1882 #define SQL_GET_REFERENCES_NONE_SOME_SOME_NONE \
1883 SQL_GET_REFERENCES \
1884 SQL_GET_REFERENCES_PTABLE \
1885 SQL_GET_REFERENCES_FSCHEMA \
1886 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1888 #define SQL_GET_REFERENCES_NONE_SOME_NONE_SOME \
1889 SQL_GET_REFERENCES \
1890 SQL_GET_REFERENCES_PTABLE \
1891 SQL_GET_REFERENCES_FTABLE \
1892 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1894 #define SQL_GET_REFERENCES_NONE_SOME_SOME_SOME \
1895 SQL_GET_REFERENCES \
1896 SQL_GET_REFERENCES_PTABLE \
1897 SQL_GET_REFERENCES_FSCHEMA \
1898 SQL_GET_REFERENCES_FTABLE \
1899 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1901 #define SQL_GET_REFERENCES_SOME_SOME_SOME_NONE \
1902 SQL_GET_REFERENCES \
1903 SQL_GET_REFERENCES_PSCHEMA \
1904 SQL_GET_REFERENCES_PTABLE \
1905 SQL_GET_REFERENCES_FSCHEMA \
1906 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1908 #define SQL_GET_REFERENCES_SOME_SOME_NONE_SOME \
1909 SQL_GET_REFERENCES \
1910 SQL_GET_REFERENCES_PSCHEMA \
1911 SQL_GET_REFERENCES_PTABLE \
1912 SQL_GET_REFERENCES_FTABLE \
1913 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1915 #define SQL_GET_REFERENCES_SOME_SOME_SOME_SOME \
1916 SQL_GET_REFERENCES \
1917 SQL_GET_REFERENCES_PSCHEMA \
1918 SQL_GET_REFERENCES_PTABLE \
1919 SQL_GET_REFERENCES_FSCHEMA \
1920 SQL_GET_REFERENCES_FTABLE \
1921 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1923 void DatabaseMetaData::init_getReferences_stmt ()
1925 m_getReferences_stmt
[0] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_NONE
);
1926 m_getReferences_stmt
[1] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_NONE
);
1927 m_getReferences_stmt
[2] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_NONE
);
1928 m_getReferences_stmt
[3] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_NONE
);
1929 m_getReferences_stmt
[4] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_NONE
);
1930 m_getReferences_stmt
[5] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_NONE
);
1931 m_getReferences_stmt
[6] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_NONE
);
1932 m_getReferences_stmt
[7] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_NONE
);
1933 m_getReferences_stmt
[8] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_SOME
);
1934 m_getReferences_stmt
[9] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_SOME
);
1935 m_getReferences_stmt
[10] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_SOME
);
1936 m_getReferences_stmt
[11] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_SOME
);
1937 m_getReferences_stmt
[12] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_SOME
);
1938 m_getReferences_stmt
[13] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_SOME
);
1939 m_getReferences_stmt
[14] = m_origin
->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_SOME
);
1940 m_getReferences_stmt
[15] = m_origin
->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_SOME
);
1943 void DatabaseMetaData::init_getPrivs_stmt ()
1945 OUStringBuffer
sSQL(300);
1947 " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable "
1949 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name,"
1950 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
1951 " FROM information_schema.table_privileges");
1952 if ( PQserverVersion( m_pSettings
->pConnection
) < 90200 )
1953 // information_schema.table_privileges does not fill in default ACLs when no ACL
1954 // assume default ACL is "owner has all privileges" and add it
1957 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME,"
1958 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
1959 " FROM pg_catalog.pg_class c,"
1960 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) p (privilege),"
1961 " pg_catalog.pg_roles ro,"
1962 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
1964 " VALUES (0::oid, 'PUBLIC')"
1965 " ) AS rg (oid, rolname),"
1966 " pg_catalog.pg_namespace pn"
1967 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
1968 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid");
1971 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
1972 " WHERE table_schem LIKE ? AND table_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
1973 " ORDER BY table_schem, table_name, privilege" );
1975 m_getTablePrivs_stmt
= m_origin
->prepareStatement( sSQL
.makeStringAndClear() );
1978 " 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 ("
1979 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name, column_name,"
1980 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
1981 " FROM information_schema.column_privileges");
1982 if ( PQserverVersion( m_pSettings
->pConnection
) < 90200 )
1983 // information_schema.table_privileges does not fill in default ACLs when no ACL
1984 // assume default ACL is "owner has all privileges" and add it
1987 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, a.attname AS column_name,"
1988 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
1989 " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a,"
1990 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) p (privilege),"
1991 " pg_catalog.pg_roles ro,"
1992 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
1994 " VALUES (0::oid, 'PUBLIC')"
1995 " ) AS rg (oid, rolname),"
1996 " pg_catalog.pg_namespace pn"
1997 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
1998 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid AND a.attrelid = c.oid AND a.attnum > 0");
2001 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
2002 " WHERE table_schem = ? AND table_name = ? AND column_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
2003 " ORDER BY column_name, privilege" );
2005 m_getColumnPrivs_stmt
= m_origin
->prepareStatement( sSQL
.makeStringAndClear() );
2008 css::uno::Reference
< XResultSet
> DatabaseMetaData::getImportedExportedKeys(
2009 const Any
& /* primaryCatalog */,
2010 const OUString
& primarySchema
,
2011 const OUString
& primaryTable
,
2012 const Any
& /* foreignCatalog */,
2013 const OUString
& foreignSchema
,
2014 const OUString
& foreignTable
)
2017 if ( ! primarySchema
.isEmpty() )
2019 if ( ! primaryTable
.isEmpty() )
2021 if ( ! foreignSchema
.isEmpty() )
2023 if ( ! foreignTable
.isEmpty() )
2026 Reference
< XPreparedStatement
> stmt
= m_getReferences_stmt
[i
];
2027 Reference
< XParameters
> param ( stmt
, UNO_QUERY_THROW
);
2031 param
->setString( j
++, primarySchema
);
2033 param
->setString( j
++, primaryTable
);
2035 param
->setString( j
++, foreignSchema
);
2037 param
->setString( j
++, foreignTable
);
2039 Reference
< XResultSet
> rs
= stmt
->executeQuery();
2045 css::uno::Reference
< XResultSet
> DatabaseMetaData::getImportedKeys(
2046 const css::uno::Any
& catalog
,
2047 const OUString
& schema
,
2048 const OUString
& table
)
2050 return getImportedExportedKeys(Any(), OUString(), OUString(), catalog
, schema
, table
);
2053 css::uno::Reference
< XResultSet
> DatabaseMetaData::getExportedKeys(
2054 const css::uno::Any
& catalog
,
2055 const OUString
& schema
,
2056 const OUString
& table
)
2058 return getImportedExportedKeys(catalog
, schema
, table
, Any(), OUString(), OUString());
2061 css::uno::Reference
< XResultSet
> DatabaseMetaData::getCrossReference(
2062 const css::uno::Any
& primaryCatalog
,
2063 const OUString
& primarySchema
,
2064 const OUString
& primaryTable
,
2065 const css::uno::Any
& foreignCatalog
,
2066 const OUString
& foreignSchema
,
2067 const OUString
& foreignTable
)
2069 return getImportedExportedKeys( primaryCatalog
, primarySchema
, primaryTable
, foreignCatalog
, foreignSchema
, foreignTable
);
2074 struct TypeInfoByDataTypeSorter
2076 bool operator () ( const std::vector
< Any
> & a
, const std::vector
< Any
> & b
)
2080 a
[1 /*DATA_TYPE*/] >>= valueA
;
2081 b
[1 /*DATA_TYPE*/] >>= valueB
;
2082 if( valueB
.toInt32() == valueA
.toInt32() )
2086 a
[0 /*TYPE_NAME*/] >>= nameA
;
2087 b
[0 /*TYPE_NAME*/] >>= nameB
;
2088 OUString nsA
, tnA
, nsB
, tnB
;
2090 // parse typename into schema and typename
2092 nsA
= nameA
.getToken(0, '.', nIndex
);
2100 tnA
= nameA
.getToken(0, '.', nIndex
);
2105 nsB
= nameB
.getToken(0, '.', nIndex
);
2113 tnB
= nameB
.getToken(0, '.', nIndex
);
2117 const int ns_comp
= compare_schema(nsA
, nsB
);
2122 assert(nsB
.isEmpty());
2123 // within each type category, sort privileged choice first
2124 if( tnA
== "int4" || tnA
== "varchar" || tnA
== "char" || tnA
== "text")
2126 if( tnB
== "int4" || tnB
== "varchar" || tnB
== "char" || tnB
== "text")
2129 return nameA
.compareTo( nameB
) < 0;
2137 return valueA
.toInt32() < valueB
.toInt32();
2141 sal_Int32
calcSearchable( sal_Int32 dataType
)
2143 sal_Int32 ret
= css::sdbc::ColumnSearch::FULL
;
2144 if( css::sdbc::DataType::BINARY
== dataType
||
2145 css::sdbc::DataType::VARBINARY
== dataType
||
2146 css::sdbc::DataType::LONGVARBINARY
== dataType
)
2147 ret
= css::sdbc::ColumnSearch::NONE
;
2152 sal_Int32
getMaxScale( sal_Int32 dataType
)
2154 // LEM TODO: review, see where used, see JDBC, ...
2156 if( dataType
== css::sdbc::DataType::NUMERIC
)
2157 ret
= 1000; // see pg-docs DataType/numeric
2158 // else if( dataType == DataType::DOUBLE )
2160 // else if( dataType == DataType::FLOAT )
2165 OUString
construct_full_typename(const OUString
&ns
, const OUString
&tn
)
2167 if(ns
.isEmpty() || ns
== "pg_catalog")
2170 return ns
+ "." + tn
;
2173 void pgTypeInfo2ResultSet(
2174 std::vector
< std::vector
<Any
> > &vec
,
2175 const Reference
< XResultSet
> &rs
)
2177 static const sal_Int32 TYPE_NAME
= 0; // string Type name
2178 static const sal_Int32 DATA_TYPE
= 1; // short SQL data type from java.sql.Types
2179 static const sal_Int32 PRECISION
= 2; // long maximum precision
2180 static const sal_Int32 CREATE_PARAMS
= 5; // string => parameters used in creating the type (may be NULL )
2181 static const sal_Int32 NULLABLE
= 6; // short ==> can you use NULL for this type?
2182 // - NO_NULLS - does not allow NULL values
2183 // - NULLABLE - allows NULL values
2184 // - NULLABLE_UNKNOWN - nullability unknown
2186 static const sal_Int32 CASE_SENSITIVE
= 7; // boolean==> is it case sensitive
2187 static const sal_Int32 SEARCHABLE
= 8; // short ==>; can you use
2188 // "WHERE" based on this type:
2189 // - NONE - No support
2190 // - CHAR - Only supported with WHERE .. LIKE
2191 // - BASIC - Supported except for WHERE .. LIKE
2192 // - FULL - Supported for all WHERE ..
2193 static const sal_Int32 UNSIGNED_ATTRIBUTE
= 9; // boolean ==> is it unsigned?
2194 // FIXED_PREC_SCALE = 10; boolean ==> can it be a money value?
2195 static const sal_Int32 AUTO_INCREMENT
= 11; // boolean ==> can it be used for
2196 // an auto-increment value?
2197 static const sal_Int32 MINIMUM_SCALE
= 13; // short ==> minimum scale supported
2198 static const sal_Int32 MAXIMUM_SCALE
= 14; // short ==> maximum scale supported
2199 static const sal_Int32 NUM_PREC_RADIX
= 17; // long ==> usually 2 or 10
2201 /* not filled so far
2202 3. LITERAL_PREFIX string ==> prefix used to quote a literal
2204 4. LITERAL_SUFFIX string ==> suffix used to quote a literal
2206 5. CREATE_PARAMS string ==> parameters used in creating the type (may be <NULL/>)
2207 12. LOCAL_TYPE_NAME string ==> localized version of type name (may be <NULL/>)
2208 15, SQL_DATA_TYPE long ==> unused
2209 16. SQL_DATETIME_SUB long ==> unused
2211 Reference
< XRow
> xRow( rs
, UNO_QUERY_THROW
);
2214 std::vector
< Any
> row(18);
2216 sal_Int32 dataType
=typeNameToDataType(xRow
->getString(5),xRow
->getString(2));
2217 sal_Int32 precision
= xRow
->getString(3).toInt32();
2219 if( dataType
== css::sdbc::DataType::CHAR
||
2220 ( dataType
== css::sdbc::DataType::VARCHAR
&&
2221 xRow
->getString(TYPE_NAME
+1).equalsIgnoreAsciiCase("varchar") ) )
2223 // reflect varchar as varchar with upper limit !
2224 //NOTE: the sql spec requires varchar to have an upper limit, however
2225 // in postgresql the upper limit is optional, no limit means unlimited
2227 precision
= 0x40000000; // about 1 GB, see character type docs in postgresql
2228 row
[CREATE_PARAMS
] <<= OUString("length");
2230 else if( dataType
== css::sdbc::DataType::NUMERIC
)
2233 row
[CREATE_PARAMS
] <<= OUString("length, scale");
2236 row
[TYPE_NAME
] <<= construct_full_typename(xRow
->getString(6), xRow
->getString(1));
2237 row
[DATA_TYPE
] <<= OUString::number(dataType
);
2238 row
[PRECISION
] <<= OUString::number( precision
);
2239 sal_Int32 nullable
= xRow
->getBoolean(4) ?
2240 css::sdbc::ColumnValue::NO_NULLS
:
2241 css::sdbc::ColumnValue::NULLABLE
;
2242 row
[NULLABLE
] <<= OUString::number(nullable
);
2243 row
[CASE_SENSITIVE
] <<= OUString::number(1);
2244 row
[SEARCHABLE
] <<= OUString::number( calcSearchable( dataType
) );
2245 row
[UNSIGNED_ATTRIBUTE
] <<= OUString("0");
2246 if( css::sdbc::DataType::INTEGER
== dataType
||
2247 css::sdbc::DataType::BIGINT
== dataType
)
2248 row
[AUTO_INCREMENT
] <<= OUString("1"); // TODO
2250 row
[AUTO_INCREMENT
] <<= OUString("0"); // TODO
2251 row
[MINIMUM_SCALE
] <<= OUString("0"); // TODO: what is this ?
2252 row
[MAXIMUM_SCALE
] <<= OUString::number( getMaxScale( dataType
) );
2253 row
[NUM_PREC_RADIX
] <<= OUString("10"); // TODO: what is this ?
2254 vec
.push_back( row
);
2260 css::uno::Reference
< XResultSet
> DatabaseMetaData::getTypeInfo( )
2262 // Note: Indexes start at 0 (in the API doc, they start at 1)
2263 MutexGuard
guard( m_xMutex
->GetMutex() );
2265 SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTypeInfo() got called");
2267 Reference
< XStatement
> statement
= m_origin
->createStatement();
2268 Reference
< XResultSet
> rs
= statement
->executeQuery(
2269 "SELECT pg_type.typname AS typname," //1
2270 "pg_type.typtype AS typtype," //2
2271 "pg_type.typlen AS typlen," //3
2272 "pg_type.typnotnull AS typnotnull," //4
2273 "pg_type.typname AS typname, " //5
2274 "pg_namespace.nspname as typns " //6
2275 "FROM pg_type LEFT JOIN pg_namespace ON pg_type.typnamespace=pg_namespace.oid "
2276 "WHERE pg_type.typtype = 'b' "
2277 "OR pg_type.typtype = 'p'"
2280 std::vector
< std::vector
<Any
> > vec
;
2281 pgTypeInfo2ResultSet( vec
, rs
);
2283 // check for domain types
2284 rs
= statement
->executeQuery(
2285 "SELECT t1.typname as typname,"
2286 "t2.typtype AS typtype,"
2287 "t2.typlen AS typlen,"
2288 "t2.typnotnull AS typnotnull,"
2289 "t2.typname as realtypname, "
2290 "pg_namespace.nspname as typns "
2291 "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 "
2292 "WHERE t1.typtype = 'd'" );
2293 pgTypeInfo2ResultSet( vec
, rs
);
2295 std::sort( vec
.begin(), vec
.end(), TypeInfoByDataTypeSorter() );
2297 return new SequenceResultSet(
2300 getStatics().typeinfoColumnNames
,
2303 &( getStatics().typeInfoMetaData
));
2307 css::uno::Reference
< XResultSet
> DatabaseMetaData::getIndexInfo(
2308 const css::uno::Any
& ,
2309 const OUString
& schema
,
2310 const OUString
& table
,
2315 MutexGuard
guard( m_xMutex
->GetMutex() );
2318 1. TABLE_CAT string -> table catalog (may be NULL )
2319 2. TABLE_SCHEM string -> table schema (may be NULL )
2320 3. TABLE_NAME string -> table name
2321 4. NON_UNIQUE boolean -> Can index values be non-unique?
2322 false when TYPE is tableIndexStatistic
2323 5. INDEX_QUALIFIER string -> index catalog (may be NULL );
2324 NULL when TYPE is tableIndexStatistic
2325 6. INDEX_NAME string -> index name; NULL when TYPE is tableIndexStatistic
2326 7. TYPE short -> index type:
2327 * 0 - this identifies table statistics that are returned
2328 in conjunction with a table's index descriptions
2329 * CLUSTERED - this is a clustered index
2330 * HASHED - this is a hashed index
2331 * OTHER - this is some other style of index
2332 8. ORDINAL_POSITION short -> column sequence number within index;
2333 zero when TYPE is tableIndexStatistic
2334 9. COLUMN_NAME string -> column name; NULL when TYPE is tableIndexStatistic
2335 10. ASC_OR_DESC string -> column sort sequence, "A"= ascending,
2336 "D" = descending, may be NULL if sort sequence
2337 is not supported; NULL when TYPE is tableIndexStatistic
2338 11. CARDINALITY long -> When TYPE is tableIndexStatistic, then this is
2339 the number of rows in the table; otherwise, it
2340 is the number of unique values in the index.
2341 12. PAGES long -> When TYPE is tableIndexStatistic then this is
2342 the number of pages used for the table, otherwise
2343 it is the number of pages used for the current index.
2344 13. FILTER_CONDITION string -> Filter condition, if any. (may be NULL )
2347 static const sal_Int32 C_SCHEMA
= 1;
2348 static const sal_Int32 C_TABLENAME
= 2;
2349 static const sal_Int32 C_INDEXNAME
= 3;
2350 static const sal_Int32 C_IS_CLUSTERED
= 4;
2351 static const sal_Int32 C_IS_UNIQUE
= 5;
2353 static const sal_Int32 C_COLUMNS
= 7;
2355 static const sal_Int32 R_TABLE_SCHEM
= 1;
2356 static const sal_Int32 R_TABLE_NAME
= 2;
2357 static const sal_Int32 R_NON_UNIQUE
= 3;
2358 static const sal_Int32 R_INDEX_NAME
= 5;
2359 static const sal_Int32 R_TYPE
= 6;
2360 static const sal_Int32 R_ORDINAL_POSITION
= 7;
2361 static const sal_Int32 R_COLUMN_NAME
= 8;
2363 Reference
< XPreparedStatement
> stmt
= m_origin
->prepareStatement(
2364 "SELECT nspname, " // 1
2365 "pg_class.relname, " // 2
2366 "class2.relname, " // 3
2367 "indisclustered, " // 4
2368 "indisunique, " // 5
2369 "indisprimary, " // 6
2371 "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid "
2372 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
2373 "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid "
2374 "WHERE nspname = ? AND pg_class.relname = ?" );
2376 Reference
< XParameters
> param ( stmt
, UNO_QUERY_THROW
);
2377 param
->setString( 1, schema
);
2378 param
->setString( 2, table
);
2379 Reference
< XResultSet
> rs
= stmt
->executeQuery();
2380 Reference
< XRow
> xRow ( rs
, UNO_QUERY_THROW
);
2382 std::vector
< std::vector
<Any
> > vec
;
2385 std::vector
< sal_Int32
> columns
= parseIntArray( xRow
->getString(C_COLUMNS
) );
2386 Reference
< XPreparedStatement
> columnsStmt
= m_origin
->prepareStatement(
2387 "SELECT attnum, attname "
2388 "FROM pg_attribute "
2389 " INNER JOIN pg_class ON attrelid = pg_class.oid "
2390 " INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid "
2391 " WHERE pg_namespace.nspname=? AND pg_class.relname=?" );
2392 Reference
< XParameters
> paramColumn ( columnsStmt
, UNO_QUERY_THROW
);
2393 OUString currentSchema
= xRow
->getString( C_SCHEMA
);
2394 OUString currentTable
= xRow
->getString( C_TABLENAME
);
2395 OUString currentIndexName
= xRow
->getString( C_INDEXNAME
);
2396 bool isNonUnique
= ! xRow
->getBoolean( C_IS_UNIQUE
);
2397 sal_Int32 indexType
= xRow
->getBoolean( C_IS_CLUSTERED
) ?
2398 css::sdbc::IndexType::CLUSTERED
:
2399 css::sdbc::IndexType::HASHED
;
2401 paramColumn
->setString( C_SCHEMA
, currentSchema
);
2402 paramColumn
->setString( C_TABLENAME
, currentTable
);
2404 Reference
< XResultSet
> rsColumn
= columnsStmt
->executeQuery();
2405 Reference
< XRow
> rowColumn( rsColumn
, UNO_QUERY_THROW
);
2406 while( rsColumn
->next() )
2408 auto findIt
= std::find( columns
.begin(), columns
.end(), rowColumn
->getInt( 1 ) );
2409 if( findIt
!= columns
.end() && ( ! isNonUnique
|| ! unique
) )
2411 std::vector
< Any
> result( 13 );
2412 result
[R_TABLE_SCHEM
] <<= currentSchema
;
2413 result
[R_TABLE_NAME
] <<= currentTable
;
2414 result
[R_INDEX_NAME
] <<= currentIndexName
;
2415 result
[R_NON_UNIQUE
] <<= isNonUnique
;
2416 result
[R_TYPE
] <<= indexType
;
2417 result
[R_COLUMN_NAME
] <<= rowColumn
->getString(2);
2418 sal_Int32 nPos
= static_cast<sal_Int32
>(findIt
- columns
.begin() +1); // MSVC++ nonsense
2419 result
[R_ORDINAL_POSITION
] <<= nPos
;
2420 vec
.push_back( result
);
2424 return new SequenceResultSet(
2425 m_xMutex
, *this, getStatics().indexinfoColumnNames
,
2430 sal_Bool
DatabaseMetaData::supportsResultSetType( sal_Int32 setType
)
2432 if ( setType
== css::sdbc::ResultSetType::SCROLL_SENSITIVE
)
2438 sal_Bool
DatabaseMetaData::supportsResultSetConcurrency(
2439 sal_Int32 setType
, sal_Int32
)
2441 if ( ! supportsResultSetType( setType
) )
2447 sal_Bool
DatabaseMetaData::ownUpdatesAreVisible( sal_Int32
/* setType */ )
2452 sal_Bool
DatabaseMetaData::ownDeletesAreVisible( sal_Int32
/* setType */ )
2457 sal_Bool
DatabaseMetaData::ownInsertsAreVisible( sal_Int32
/* setType */ )
2462 sal_Bool
DatabaseMetaData::othersUpdatesAreVisible( sal_Int32
/* setType */ )
2467 sal_Bool
DatabaseMetaData::othersDeletesAreVisible( sal_Int32
/* setType */ )
2472 sal_Bool
DatabaseMetaData::othersInsertsAreVisible( sal_Int32
/* setType */ )
2477 sal_Bool
DatabaseMetaData::updatesAreDetected( sal_Int32
/* setType */ )
2482 sal_Bool
DatabaseMetaData::deletesAreDetected( sal_Int32
/* setType */ )
2486 sal_Bool
DatabaseMetaData::insertsAreDetected( sal_Int32
/* setType */ )
2491 sal_Bool
DatabaseMetaData::supportsBatchUpdates( )
2496 css::uno::Reference
< XResultSet
> DatabaseMetaData::getUDTs( const css::uno::Any
&, const OUString
&, const OUString
&, const css::uno::Sequence
< sal_Int32
>& )
2498 //LEM TODO: implement! See JDBC driver
2499 MutexGuard
guard( m_xMutex
->GetMutex() );
2500 return new SequenceResultSet(
2501 m_xMutex
, *this, std::vector
< OUString
>(), std::vector
< std::vector
< Any
> >(), m_pSettings
->tc
);
2504 css::uno::Reference
< css::sdbc::XConnection
> DatabaseMetaData::getConnection()
2510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */