Use correct object
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_databasemetadata.cxx
blob76157bc4c3056fe8beb5c384797f63ff14fe86f0
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,
18 * MA 02111-1307 USA
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 ************************************************************************/
67 #include <algorithm>
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>
87 #include <utility>
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( )
132 // TODO
133 return false;
136 sal_Bool DatabaseMetaData::allTablesAreSelectable( )
138 return true;
141 OUString DatabaseMetaData::getURL( )
143 // TODO
144 // LEM TODO: implement
145 return OUString();
148 OUString DatabaseMetaData::getUserName( )
150 return m_pSettings->user;
153 sal_Bool DatabaseMetaData::isReadOnly( )
155 return false;
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
164 return true;
167 sal_Bool DatabaseMetaData::nullsAreSortedLow( )
169 return ! nullsAreSortedHigh();
172 sal_Bool DatabaseMetaData::nullsAreSortedAtStart( )
174 return false;
177 sal_Bool DatabaseMetaData::nullsAreSortedAtEnd( )
179 return false;
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( )
213 // LEM TODO:
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.
219 return false;
222 sal_Bool DatabaseMetaData::usesLocalFilePerTable( )
224 return false;
227 sal_Bool DatabaseMetaData::supportsMixedCaseIdentifiers( )
229 return false;
232 sal_Bool DatabaseMetaData::storesUpperCaseIdentifiers( )
234 return false;
237 sal_Bool DatabaseMetaData::storesLowerCaseIdentifiers( )
239 return true;
243 sal_Bool DatabaseMetaData::storesMixedCaseIdentifiers( )
245 return false;
249 sal_Bool DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
251 return true;
254 sal_Bool DatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
256 return false;
260 sal_Bool DatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
262 return false;
266 sal_Bool DatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
268 return false;
272 OUString DatabaseMetaData::getIdentifierQuoteString( )
274 return u"\""_ustr;
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
284 return
285 u"ANALYSE,"
286 "ANALYZE,"
287 "ARRAY," //SQL:1999
288 "ASYMMETRIC," //SQL:2003
289 "BINARY," //SQL:1999
290 "CONCURRENTLY,"
291 "CURRENT_CATALOG," //SQL:2008
292 "CURRENT_ROLE," //SQL:1999
293 "CURRENT_SCHEMA," //SQL:2008
294 "DO,"
295 "FREEZE,"
296 "ILIKE,"
297 "ISNULL,"
298 "LIMIT," //SQL:1999; non-reserved in SQL:2003
299 "LOCALTIME," //SQL:1999
300 "LOCALTIMESTAMP," //SQL:1999
301 "NOTNULL,"
302 "OFFSET," //SQL:2008
303 "OVER," //SQL:2003
304 "PLACING," //non-reserved in SQL:2003
305 "RETURNING," //non-reserved in SQL:2008
306 "SIMILAR," //SQL:2003
307 "VARIADIC,"
308 "VERBOSE,"
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.
320 return
321 u"abs,"
322 "cbrt,"
323 "ceil,"
324 "ceiling,"
325 "degrees,"
326 "div,"
327 "exp,"
328 "floor,"
329 "ln,"
330 "log,"
331 "mod,"
332 "pi,"
333 "power,"
334 "radians,"
335 "random,"
336 "round,"
337 "setseed,"
338 "sign,"
339 "sqrt,"
340 "trunc,"
341 "width_bucket,"
342 "acos,"
343 "asin,"
344 "atan,"
345 "atan2,"
346 "cos,"
347 "cot,"
348 "sin,"
349 "tan"_ustr
353 OUString DatabaseMetaData::getStringFunctions( )
355 // See http://www.postgresql.org/docs/9.1/static/functions-string.html
356 return
357 u"bit_length,"
358 "char_length,"
359 "character_length,"
360 "lower,"
361 "octet_length,"
362 "overlay,"
363 "position,"
364 "substring,"
365 "trim,"
366 "upper,"
367 "ascii,"
368 "btrim,"
369 "chr,"
370 "concat,"
371 "concat_ws,"
372 "convert,"
373 "convert_from,"
374 "convert_to,"
375 "decode,"
376 "encode,"
377 "format,"
378 "initcap,"
379 "left,"
380 "length,"
381 "lpad,"
382 "ltrim,"
383 "md5,"
384 "pg_client_encoding,"
385 "quote_ident,"
386 "quote_literal,"
387 "quote_nullable,"
388 "regexp_matches,"
389 "regexp_replace,"
390 "regexp_split_to_array,"
391 "regexp_split_to_table,"
392 "repeat,"
393 "replace,"
394 "reverse,"
395 "right,"
396 "rpad,"
397 "rtrim,"
398 "split_part,"
399 "strpos,"
400 "substr,"
401 "to_ascii,"
402 "to_hex,"
403 "translate"_ustr
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
411 return
412 u"current_catalog,"
413 "current_database,"
414 "current_query,"
415 "current_schema,"
416 "current_schemas,"
417 "current_user,"
418 "inet_client_addr,"
419 "inet_client_port,"
420 "inet_server_addr,"
421 "inet_server_port,"
422 "pg_backend_pid,"
423 "pg_conf_load_time,"
424 "pg_is_other_temp_schema,"
425 "pg_listening_channels,"
426 "pg_my_temp_schema,"
427 "pg_postmaster_start_time,"
428 "session_user,"
429 "user,"
430 "version,"
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,"
444 "pg_has_role,"
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,"
456 "format_type,"
457 "pg_describe_object,"
458 "pg_get_constraintdef,"
459 "pg_get_expr,"
460 "pg_get_functiondef,"
461 "pg_get_function_arguments,"
462 "pg_get_function_identity_arguments,"
463 "pg_get_function_result,"
464 "pg_get_indexdef,"
465 "pg_get_keywords,"
466 "pg_get_ruledef,"
467 "pg_get_serial_sequence,"
468 "pg_get_triggerdef,"
469 "pg_get_userbyid,"
470 "pg_get_viewdef,"
471 "pg_options_to_table,"
472 "pg_tablespace_databases,"
473 "pg_typeof,"
474 "col_description,"
475 "obj_description,"
476 "shobj_description,"
477 "txid_current,"
478 "txid_current_snapshot,"
479 "txid_snapshot_xip,"
480 "txid_snapshot_xmax,"
481 "txid_snapshot_xmin,"
482 "txid_visible_in_snapshot,"
483 "xmin,"
484 "xmax,"
485 "xip_list,"
486 "current_setting,"
487 "set_config,"
488 "pg_cancel_backend,"
489 "pg_reload_conf,"
490 "pg_rotate_logfile,"
491 "pg_terminate_backend,"
492 "pg_create_restore_point,"
493 "pg_current_xlog_insert_location,"
494 "pg_current_xlog_location,"
495 "pg_start_backup,"
496 "pg_stop_backup,"
497 "pg_switch_xlog,"
498 "pg_xlogfile_name,"
499 "pg_xlogfile_name_offset,"
500 "pg_is_in_recovery,"
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,"
507 "pg_column_size,"
508 "pg_database_size,"
509 "pg_indexes_size,"
510 "pg_relation_size,"
511 "pg_size_pretty,"
512 "pg_table_size,"
513 "pg_tablespace_size,"
514 "pg_tablespace_size,"
515 "pg_total_relation_size,"
516 "pg_relation_filenode,"
517 "pg_relation_filepath,"
518 "pg_ls_dir,"
519 "pg_read_file,"
520 "pg_read_binary_file,"
521 "pg_stat_file,"
522 "pg_advisory_lock,"
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,"
533 "pg_sleep"_ustr
536 OUString DatabaseMetaData::getTimeDateFunctions( )
538 // TODO
539 return
540 u"age,"
541 "age,"
542 "clock_timestamp,"
543 "current_date,"
544 "current_time,"
545 "current_timestamp,"
546 "date_part,"
547 "date_part,"
548 "date_trunc,"
549 "extract,"
550 "extract,"
551 "isfinite,"
552 "isfinite,"
553 "isfinite,"
554 "justify_days,"
555 "justify_hours,"
556 "justify_interval,"
557 "localtime,"
558 "localtimestamp,"
559 "now,"
560 "statement_timestamp,"
561 "timeofday,"
562 "transaction_timestamp,"_ustr
565 OUString DatabaseMetaData::getSearchStringEscape( )
567 return u"\\"_ustr;
569 OUString DatabaseMetaData::getExtraNameCharacters( )
571 return u"$"_ustr;
574 sal_Bool DatabaseMetaData::supportsAlterTableWithAddColumn( )
576 return true;
579 sal_Bool DatabaseMetaData::supportsAlterTableWithDropColumn( )
581 return true;
584 sal_Bool DatabaseMetaData::supportsColumnAliasing( )
586 return true;
589 sal_Bool DatabaseMetaData::nullPlusNonNullIsNull( )
591 return true;
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.
598 return false;
601 sal_Bool DatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 )
603 return false;
606 sal_Bool DatabaseMetaData::supportsTableCorrelationNames( )
608 // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..."
609 return true;
613 sal_Bool DatabaseMetaData::supportsDifferentTableCorrelationNames( )
615 return false;
617 sal_Bool DatabaseMetaData::supportsExpressionsInOrderBy( )
619 return true;
622 sal_Bool DatabaseMetaData::supportsOrderByUnrelated( )
624 return true;
627 sal_Bool DatabaseMetaData::supportsGroupBy( )
629 return true;
632 sal_Bool DatabaseMetaData::supportsGroupByUnrelated( )
634 return true;
637 sal_Bool DatabaseMetaData::supportsGroupByBeyondSelect( )
639 return true;
642 sal_Bool DatabaseMetaData::supportsLikeEscapeClause( )
644 return true;
647 sal_Bool DatabaseMetaData::supportsMultipleResultSets( )
649 return true;
652 sal_Bool DatabaseMetaData::supportsMultipleTransactions( )
654 // Allows multiple transactions open at once (on different connections!)
655 return true;
658 sal_Bool DatabaseMetaData::supportsNonNullableColumns( )
660 return true;
664 sal_Bool DatabaseMetaData::supportsMinimumSQLGrammar( )
666 return true;
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"
677 return true;
680 sal_Bool DatabaseMetaData::supportsExtendedSQLGrammar( )
682 return false;
685 sal_Bool DatabaseMetaData::supportsANSI92EntryLevelSQL( )
687 return true;
690 sal_Bool DatabaseMetaData::supportsANSI92IntermediateSQL( )
692 // LEM: jdbc driver says not, although the comments in it seem old
693 return false;
696 sal_Bool DatabaseMetaData::supportsANSI92FullSQL( )
698 // LEM: jdbc driver says not, although the comments in it seem old
699 return false;
702 sal_Bool DatabaseMetaData::supportsIntegrityEnhancementFacility( )
704 // LEM: jdbc driver says yes, although comment says they are not sure what this means...
705 return true;
708 sal_Bool DatabaseMetaData::supportsOuterJoins( )
710 return true;
713 sal_Bool DatabaseMetaData::supportsFullOuterJoins( )
715 return true;
718 sal_Bool DatabaseMetaData::supportsLimitedOuterJoins( )
720 return true;
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( )
741 return true;
744 OUString DatabaseMetaData::getCatalogSeparator( )
746 return u"."_ustr;
749 sal_Bool DatabaseMetaData::supportsSchemasInDataManipulation( )
751 return true;
754 sal_Bool DatabaseMetaData::supportsSchemasInProcedureCalls( )
756 return true;
759 sal_Bool DatabaseMetaData::supportsSchemasInTableDefinitions( )
761 return true;
764 sal_Bool DatabaseMetaData::supportsSchemasInIndexDefinitions( )
766 return true;
769 sal_Bool DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
771 return true;
774 sal_Bool DatabaseMetaData::supportsCatalogsInDataManipulation( )
776 return false;
779 sal_Bool DatabaseMetaData::supportsCatalogsInProcedureCalls( )
781 return false;
784 sal_Bool DatabaseMetaData::supportsCatalogsInTableDefinitions( )
786 return false;
790 sal_Bool DatabaseMetaData::supportsCatalogsInIndexDefinitions( )
792 return false;
796 sal_Bool DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
798 return false;
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
809 return false;
812 sal_Bool DatabaseMetaData::supportsPositionedUpdate( )
814 // LEM: jdbc driver says not, although the comments in it seem old
815 return false;
819 sal_Bool DatabaseMetaData::supportsSelectForUpdate( )
821 return true;
825 sal_Bool DatabaseMetaData::supportsStoredProcedures( )
827 return true;
831 sal_Bool DatabaseMetaData::supportsSubqueriesInComparisons( )
833 return true;
836 sal_Bool DatabaseMetaData::supportsSubqueriesInExists( )
838 return true;
841 sal_Bool DatabaseMetaData::supportsSubqueriesInIns( )
843 return true;
846 sal_Bool DatabaseMetaData::supportsSubqueriesInQuantifieds( )
848 // LEM: jdbc driver says yes, although comment says they don't know what this means...
849 return true;
852 sal_Bool DatabaseMetaData::supportsCorrelatedSubqueries( )
854 return true;
856 sal_Bool DatabaseMetaData::supportsUnion( )
858 return true;
861 sal_Bool DatabaseMetaData::supportsUnionAll( )
863 return true;
866 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossCommit( )
868 return false;
871 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossRollback( )
873 return false;
876 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossCommit( )
878 return true;
880 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossRollback( )
882 return true;
885 sal_Int32 DatabaseMetaData::getMaxBinaryLiteralLength( )
887 return 0;
890 sal_Int32 DatabaseMetaData::getMaxCharLiteralLength( )
892 return 0;
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( )
933 return 0;
936 sal_Int32 DatabaseMetaData::getMaxColumnsInIndex( )
938 return getMaxIndexKeys();
941 sal_Int32 DatabaseMetaData::getMaxColumnsInOrderBy( )
943 return 0;
946 sal_Int32 DatabaseMetaData::getMaxColumnsInSelect( )
948 return 0;
951 sal_Int32 DatabaseMetaData::getMaxColumnsInTable( )
953 return 1600;
956 sal_Int32 DatabaseMetaData::getMaxConnections( )
958 // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports
959 return 0;
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
970 return 0;
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
993 return 0;
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
1000 return true;
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.
1008 return 0;
1011 sal_Int32 DatabaseMetaData::getMaxStatements( ) //TODO, don't know
1013 return 0;
1016 sal_Int32 DatabaseMetaData::getMaxTableNameLength( )
1018 return getMaxNameLength();
1021 sal_Int32 DatabaseMetaData::getMaxTablesInSelect( )
1023 return 0;
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( )
1038 return true;
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)
1047 return true;
1048 else
1049 return false;
1052 sal_Bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
1054 return true;
1057 sal_Bool DatabaseMetaData::supportsDataManipulationTransactionsOnly( )
1059 return false;
1062 sal_Bool DatabaseMetaData::dataDefinitionCausesTransactionCommit( )
1064 return false;
1067 sal_Bool DatabaseMetaData::dataDefinitionIgnoredInTransactions( )
1069 return false;
1072 css::uno::Reference< XResultSet > DatabaseMetaData::getProcedures(
1073 const css::uno::Any&,
1074 const OUString&,
1075 const OUString& )
1077 // 1. PROCEDURE_CAT string =&gt; procedure catalog (may be NULL )
1078 // 2. PROCEDURE_SCHEM string =&gt; procedure schema (may be NULL )
1079 // 3. PROCEDURE_NAME string =&gt; procedure name
1080 // 4. reserved for future use
1081 // 5. reserved for future use
1082 // 6. reserved for future use
1083 // 7. REMARKS string =&gt; explanatory comment on the procedure
1084 // 8. PROCEDURE_TYPE short =&gt; 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&,
1098 const OUString&,
1099 const OUString&,
1100 const OUString& )
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(
1127 u"SELECT "
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;
1146 while( rs->next() )
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);
1154 if( type == "r" )
1156 if( xRow->getString(1) == "pg_catalog" )
1158 row[3] <<= statics.SYSTEM_TABLE;
1160 else
1162 row[3] <<= statics.TABLE;
1165 else if( type == "v" )
1167 row[3] <<= statics.VIEW;
1169 else
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() )
1180 closeable->close();
1182 return new SequenceResultSet(
1183 m_xMutex, *this, std::vector(statics.tablesRowNames), std::move(vec), m_pSettings->tc );
1186 namespace
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)
1191 if (nsA.empty())
1193 return nsB.empty() ? 0 : -1;
1195 else if (nsB.empty())
1197 assert(!nsA.empty());
1198 return 1;
1200 else if(nsA == u"public")
1202 return (nsB == u"public") ? 0 : -1;
1204 else if(nsB == u"public")
1206 assert(nsA != u"public");
1207 return 1;
1209 else if(o3tl::starts_with(nsA, u"pg_"))
1211 if(o3tl::starts_with(nsB, u"pg_"))
1212 return nsA.compare(nsB);
1213 else
1214 return 1;
1216 else if(o3tl::starts_with(nsB, u"pg_"))
1218 return -1;
1220 else
1222 return nsA.compare(nsB);
1226 struct SortInternalSchemasLastAndPublicFirst
1228 bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
1230 OUString valueA;
1231 OUString valueB;
1232 a[0] >>= valueA;
1233 b[0] >>= valueB;
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 =&amp;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;
1254 while( rs->next() )
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() )
1264 closeable->close();
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),
1284 m_pSettings->tc );
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] )
1302 // {
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;
1306 // }
1307 // base type
1308 Statics &statics = getStatics();
1309 BaseTypeMap::const_iterator ii = statics.baseTypeMap.find( typeName );
1310 if( ii != statics.baseTypeMap.end() )
1312 ret = ii->second;
1315 else if( typtype == u"c" )
1317 ret = css::sdbc::DataType::STRUCT;
1319 else if( typtype == u"d" )
1321 ret = css::sdbc::DataType::LONGVARCHAR;
1323 return ret;
1326 namespace {
1327 bool isSystemColumn( sal_Int16 attnum )
1329 return attnum <= 0;
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 )
1343 *precision = 0;
1344 *scale = 0;
1346 else
1348 switch( dataType )
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;
1355 break;
1357 default:
1358 *precision = atttypmod - PQ_VARHDRSZ;
1359 *scale = 0;
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;
1380 return *this;
1382 OUString typeName;
1383 OUString typeType;
1387 typedef std::unordered_map
1389 sal_Int32,
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 );
1399 int domains = 0;
1400 OUStringBuffer queryBuf(128);
1401 queryBuf.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " );
1402 while( rs->next() )
1404 if( row->getString( 9 ) == "d" && oidMap.find( row->getInt( 12 ) ) == oidMap.end() )
1406 oidMap[row->getInt(12)] = DatabaseTypeDescription();
1407 if( domains )
1408 queryBuf.append( " OR " );
1409 queryBuf.append( "oid = " + OUString::number( row->getInt(12 ) ) );
1410 domains ++;
1413 rs->beforeFirst();
1415 if( domains )
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();
1438 // continue !
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)
1450 // => not supported
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.
1467 // => 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)
1471 // => TODO ??
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
1482 // => empty
1483 // 15. SQL_DATETIME_SUB long => unused
1484 // => empty
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
1493 // nobody knows.
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
1509 "FROM pg_class, "
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 );
1540 while( rs->next() )
1542 if( ! isSystemColumn( xRow->getShort( 12 ) ) )
1544 OUString sNewSchema( xRow->getString(1) );
1545 OUString sNewTable( xRow->getString(2) );
1546 if ( sNewSchema != sSchema || sNewTable != sTable )
1548 colNum = 1;
1549 sSchema = sNewSchema;
1550 sTable = sNewTable;
1552 else
1553 ++colNum;
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 );
1565 else
1567 type = typeNameToDataType( xRow->getString(4), xRow->getString(8) );
1569 extractPrecisionAndScale( type, xRow->getInt(5) , &precision, &scale );
1570 row[4] <<= type;
1571 row[5] <<= xRow->getString(4);
1572 row[6] <<= precision;
1573 // row[7] BUFFER_LENGTH not used
1574 row[8] <<= scale;
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;
1581 else
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() )
1599 closeable->close();
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();
1623 return rs;
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();
1642 return rs;
1645 css::uno::Reference< XResultSet > DatabaseMetaData::getBestRowIdentifier(
1646 const css::uno::Any&,
1647 const OUString&,
1648 const OUString&,
1649 sal_Int32,
1650 sal_Bool )
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&,
1660 const OUString&,
1661 const OUString& )
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 )
1674 //LEM TODO: review
1675 MutexGuard guard( m_xMutex->GetMutex() );
1677 // 1. TABLE_CAT string =&gt; table catalog (may be NULL )
1678 // 2. TABLE_SCHEM string =&gt; table schema (may be NULL )
1679 // 3. TABLE_NAME string =&gt; table name
1680 // 4. COLUMN_NAME string =&gt; column name
1681 // 5. KEY_SEQ short =&gt; sequence number within primary key
1682 // 6. PK_NAME string =&gt; 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, "
1689 "cl.relname, "
1690 "con.conkey, "
1691 "con.conname, "
1692 "con.conrelid "
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;
1705 while( rs->next() )
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);
1715 int i = 0;
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] )
1727 i++;
1728 int start = 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() )
1738 closeable->close();
1742 OUString lastTableOid;
1743 sal_Int32 index = 0;
1744 std::vector< std::vector< Any > > ret( vec.size() );
1745 int elements = 0;
1746 for (auto const& elem : vec)
1749 std::vector< Any > row = elem;
1750 OUString tableOid;
1751 OUString attnum;
1753 row[4] >>= tableOid;
1754 row[3] >>= attnum;
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 );
1766 if( rs->next() )
1768 // column name
1769 row[3] <<= xRow->getString( 1 );
1770 if( tableOid != lastTableOid )
1771 index = 1;
1772 lastTableOid = tableOid;
1773 row[4] <<= OUString::number( index );
1774 index ++;
1777 Reference< XCloseable > closeable( statement, UNO_QUERY );
1778 if( closeable.is() )
1779 closeable->close();
1781 ret[elements] = std::move(row);
1782 elements ++;
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) \
1794 " ELSE NULL "
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 " \
1802 SQL_CASE_KEYRULE \
1803 " END AS UPDATE_RULE, " \
1804 " CASE con.confdeltype " \
1805 SQL_CASE_KEYRULE \
1806 " END AS DELETE_RULE, " \
1807 " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \
1808 " CASE " \
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 " \
1813 "FROM " \
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);
1947 sSQL.append(
1948 " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable "
1949 " FROM ("
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
1956 sSQL.append(
1957 " UNION "
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"
1964 " UNION ALL"
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");
1970 sSQL.append(
1971 " ) dp,"
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() );
1978 sSQL.append(
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
1986 sSQL.append(
1987 " UNION "
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"
1994 " UNION ALL"
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");
2000 sSQL.append(
2001 " ) dp,"
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 )
2017 unsigned int i = 0;
2018 if ( ! primarySchema.isEmpty() )
2019 i |= 0x01;
2020 if ( ! primaryTable.isEmpty() )
2021 i |= 0x02;
2022 if ( ! foreignSchema.isEmpty() )
2023 i |= 0x04;
2024 if ( ! foreignTable.isEmpty() )
2025 i |= 0x08;
2027 Reference< XPreparedStatement > stmt = m_getReferences_stmt[i];
2028 Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
2030 unsigned int j = 1;
2031 if ( i & 0x01 )
2032 param->setString( j++, primarySchema );
2033 if ( i & 0x02 )
2034 param->setString( j++, primaryTable );
2035 if ( i & 0x04 )
2036 param->setString( j++, foreignSchema );
2037 if ( i & 0x08 )
2038 param->setString( j++, foreignTable );
2040 Reference< XResultSet > rs = stmt->executeQuery();
2042 return rs;
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 );
2073 namespace
2075 struct TypeInfoByDataTypeSorter
2077 bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
2079 OUString valueA;
2080 OUString valueB;
2081 a[1 /*DATA_TYPE*/] >>= valueA;
2082 b[1 /*DATA_TYPE*/] >>= valueB;
2083 if( valueB.toInt32() == valueA.toInt32() )
2085 OUString nameA;
2086 OUString nameB;
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
2092 sal_Int32 nIndex=0;
2093 nsA = o3tl::getToken(nameA, 0, '.', nIndex);
2094 if (nIndex<0)
2096 tnA = nsA;
2097 nsA = std::u16string_view();
2099 else
2101 tnA = o3tl::getToken(nameA, 0, '.', nIndex);
2102 assert(nIndex < 0);
2105 nIndex=0;
2106 nsB = o3tl::getToken(nameB, 0, '.', nIndex);
2107 if (nIndex<0)
2109 tnB = nsB;
2110 nsB = std::u16string_view();
2112 else
2114 tnB = o3tl::getToken(nameB, 0, '.', nIndex);
2115 assert(nIndex < 0);
2118 const int ns_comp = compare_schema(nsA, nsB);
2119 if(ns_comp == 0)
2121 if(nsA.empty())
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")
2126 return true;
2127 if( tnB == u"int4" || tnB == u"varchar" || tnB == u"char" || tnB == u"text")
2128 return false;
2130 return nameA.compareTo( nameB ) < 0;
2132 else
2134 return ns_comp < 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;
2150 return ret;
2153 sal_Int32 getMaxScale( sal_Int32 dataType )
2155 // LEM TODO: review, see where used, see JDBC, ...
2156 sal_Int32 ret = 0;
2157 if( dataType == css::sdbc::DataType::NUMERIC )
2158 ret = 1000; // see pg-docs DataType/numeric
2159 // else if( dataType == DataType::DOUBLE )
2160 // ret = 308;
2161 // else if( dataType == DataType::FLOAT )
2162 // ret =
2163 return ret;
2166 OUString construct_full_typename(std::u16string_view ns, const OUString &tn)
2168 if(ns.empty() || ns == u"pg_catalog")
2169 return tn;
2170 else
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
2204 (may be <NULL/>)
2205 4. LITERAL_SUFFIX string ==> suffix used to quote a literal
2206 (may be <NULL/>)
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 );
2213 while( rs->next() )
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
2227 // length (=1GB).
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 )
2233 precision = 1000;
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
2250 else
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(
2299 m_xMutex,
2300 *this,
2301 std::vector(getStatics().typeinfoColumnNames),
2302 std::move(vec),
2303 m_pSettings->tc,
2304 &( getStatics().typeInfoMetaData ));
2308 css::uno::Reference< XResultSet > DatabaseMetaData::getIndexInfo(
2309 const css::uno::Any& ,
2310 const OUString& schema,
2311 const OUString& table,
2312 sal_Bool unique,
2313 sal_Bool )
2315 //LEM TODO: review
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;
2353 // C_IS_PRIMARY = 6
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
2371 "indkey " // 7
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;
2384 while( rs->next() )
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),
2427 std::move(vec),
2428 m_pSettings->tc );
2431 sal_Bool DatabaseMetaData::supportsResultSetType( sal_Int32 setType )
2433 if ( setType == css::sdbc::ResultSetType::SCROLL_SENSITIVE )
2434 return false;
2435 else
2436 return true;
2439 sal_Bool DatabaseMetaData::supportsResultSetConcurrency(
2440 sal_Int32 setType, sal_Int32 )
2442 if ( ! supportsResultSetType( setType ) )
2443 return false;
2444 else
2445 return true;
2448 sal_Bool DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /* setType */ )
2450 return true;
2453 sal_Bool DatabaseMetaData::ownDeletesAreVisible( sal_Int32 /* setType */ )
2455 return true;
2458 sal_Bool DatabaseMetaData::ownInsertsAreVisible( sal_Int32 /* setType */ )
2460 return true;
2463 sal_Bool DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /* setType */ )
2465 return false;
2468 sal_Bool DatabaseMetaData::othersDeletesAreVisible( sal_Int32 /* setType */ )
2470 return false;
2473 sal_Bool DatabaseMetaData::othersInsertsAreVisible( sal_Int32 /* setType */ )
2475 return false;
2478 sal_Bool DatabaseMetaData::updatesAreDetected( sal_Int32 /* setType */ )
2480 return false;
2483 sal_Bool DatabaseMetaData::deletesAreDetected( sal_Int32 /* setType */ )
2485 return false;
2487 sal_Bool DatabaseMetaData::insertsAreDetected( sal_Int32 /* setType */ )
2489 return false;
2492 sal_Bool DatabaseMetaData::supportsBatchUpdates( )
2494 return true;
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()
2507 return m_origin;
2511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */