nss: upgrade to release 3.73
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_databasemetadata.cxx
blob06d9ed1645005eb2cfcceb0cb130362e2813cbc5
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 <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 ),
119 m_origin( origin ),
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( )
128 // TODO
129 return false;
132 sal_Bool DatabaseMetaData::allTablesAreSelectable( )
134 return true;
137 OUString DatabaseMetaData::getURL( )
139 // TODO
140 // LEM TODO: implement
141 return OUString();
144 OUString DatabaseMetaData::getUserName( )
146 return m_pSettings->user;
149 sal_Bool DatabaseMetaData::isReadOnly( )
151 return false;
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
160 return true;
163 sal_Bool DatabaseMetaData::nullsAreSortedLow( )
165 return ! nullsAreSortedHigh();
168 sal_Bool DatabaseMetaData::nullsAreSortedAtStart( )
170 return false;
173 sal_Bool DatabaseMetaData::nullsAreSortedAtEnd( )
175 return false;
178 OUString DatabaseMetaData::getDatabaseProductName( )
180 return "PostgreSQL";
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( )
209 // LEM TODO:
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.
215 return false;
218 sal_Bool DatabaseMetaData::usesLocalFilePerTable( )
220 return false;
223 sal_Bool DatabaseMetaData::supportsMixedCaseIdentifiers( )
225 return false;
228 sal_Bool DatabaseMetaData::storesUpperCaseIdentifiers( )
230 return false;
233 sal_Bool DatabaseMetaData::storesLowerCaseIdentifiers( )
235 return true;
239 sal_Bool DatabaseMetaData::storesMixedCaseIdentifiers( )
241 return false;
245 sal_Bool DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
247 return true;
250 sal_Bool DatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
252 return false;
256 sal_Bool DatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
258 return false;
262 sal_Bool DatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
264 return false;
268 OUString DatabaseMetaData::getIdentifierQuoteString( )
270 return "\"";
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
280 return
281 "ANALYSE,"
282 "ANALYZE,"
283 "ARRAY," //SQL:1999
284 "ASYMMETRIC," //SQL:2003
285 "BINARY," //SQL:1999
286 "CONCURRENTLY,"
287 "CURRENT_CATALOG," //SQL:2008
288 "CURRENT_ROLE," //SQL:1999
289 "CURRENT_SCHEMA," //SQL:2008
290 "DO,"
291 "FREEZE,"
292 "ILIKE,"
293 "ISNULL,"
294 "LIMIT," //SQL:1999; non-reserved in SQL:2003
295 "LOCALTIME," //SQL:1999
296 "LOCALTIMESTAMP," //SQL:1999
297 "NOTNULL,"
298 "OFFSET," //SQL:2008
299 "OVER," //SQL:2003
300 "PLACING," //non-reserved in SQL:2003
301 "RETURNING," //non-reserved in SQL:2008
302 "SIMILAR," //SQL:2003
303 "VARIADIC,"
304 "VERBOSE,"
305 "WINDOW" //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.
316 return
317 "abs,"
318 "cbrt,"
319 "ceil,"
320 "ceiling,"
321 "degrees,"
322 "div,"
323 "exp,"
324 "floor,"
325 "ln,"
326 "log,"
327 "mod,"
328 "pi,"
329 "power,"
330 "radians,"
331 "random,"
332 "round,"
333 "setseed,"
334 "sign,"
335 "sqrt,"
336 "trunc,"
337 "width_bucket,"
338 "acos,"
339 "asin,"
340 "atan,"
341 "atan2,"
342 "cos,"
343 "cot,"
344 "sin,"
345 "tan"
349 OUString DatabaseMetaData::getStringFunctions( )
351 // See http://www.postgresql.org/docs/9.1/static/functions-string.html
352 return
353 "bit_length,"
354 "char_length,"
355 "character_length,"
356 "lower,"
357 "octet_length,"
358 "overlay,"
359 "position,"
360 "substring,"
361 "trim,"
362 "upper,"
363 "ascii,"
364 "btrim,"
365 "chr,"
366 "concat,"
367 "concat_ws,"
368 "convert,"
369 "convert_from,"
370 "convert_to,"
371 "decode,"
372 "encode,"
373 "format,"
374 "initcap,"
375 "left,"
376 "length,"
377 "lpad,"
378 "ltrim,"
379 "md5,"
380 "pg_client_encoding,"
381 "quote_ident,"
382 "quote_literal,"
383 "quote_nullable,"
384 "regexp_matches,"
385 "regexp_replace,"
386 "regexp_split_to_array,"
387 "regexp_split_to_table,"
388 "repeat,"
389 "replace,"
390 "reverse,"
391 "right,"
392 "rpad,"
393 "rtrim,"
394 "split_part,"
395 "strpos,"
396 "substr,"
397 "to_ascii,"
398 "to_hex,"
399 "translate"
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
407 return
408 "current_catalog,"
409 "current_database,"
410 "current_query,"
411 "current_schema,"
412 "current_schemas,"
413 "current_user,"
414 "inet_client_addr,"
415 "inet_client_port,"
416 "inet_server_addr,"
417 "inet_server_port,"
418 "pg_backend_pid,"
419 "pg_conf_load_time,"
420 "pg_is_other_temp_schema,"
421 "pg_listening_channels,"
422 "pg_my_temp_schema,"
423 "pg_postmaster_start_time,"
424 "session_user,"
425 "user,"
426 "version,"
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,"
440 "pg_has_role,"
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,"
452 "format_type,"
453 "pg_describe_object,"
454 "pg_get_constraintdef,"
455 "pg_get_expr,"
456 "pg_get_functiondef,"
457 "pg_get_function_arguments,"
458 "pg_get_function_identity_arguments,"
459 "pg_get_function_result,"
460 "pg_get_indexdef,"
461 "pg_get_keywords,"
462 "pg_get_ruledef,"
463 "pg_get_serial_sequence,"
464 "pg_get_triggerdef,"
465 "pg_get_userbyid,"
466 "pg_get_viewdef,"
467 "pg_options_to_table,"
468 "pg_tablespace_databases,"
469 "pg_typeof,"
470 "col_description,"
471 "obj_description,"
472 "shobj_description,"
473 "txid_current,"
474 "txid_current_snapshot,"
475 "txid_snapshot_xip,"
476 "txid_snapshot_xmax,"
477 "txid_snapshot_xmin,"
478 "txid_visible_in_snapshot,"
479 "xmin,"
480 "xmax,"
481 "xip_list,"
482 "current_setting,"
483 "set_config,"
484 "pg_cancel_backend,"
485 "pg_reload_conf,"
486 "pg_rotate_logfile,"
487 "pg_terminate_backend,"
488 "pg_create_restore_point,"
489 "pg_current_xlog_insert_location,"
490 "pg_current_xlog_location,"
491 "pg_start_backup,"
492 "pg_stop_backup,"
493 "pg_switch_xlog,"
494 "pg_xlogfile_name,"
495 "pg_xlogfile_name_offset,"
496 "pg_is_in_recovery,"
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,"
503 "pg_column_size,"
504 "pg_database_size,"
505 "pg_indexes_size,"
506 "pg_relation_size,"
507 "pg_size_pretty,"
508 "pg_table_size,"
509 "pg_tablespace_size,"
510 "pg_tablespace_size,"
511 "pg_total_relation_size,"
512 "pg_relation_filenode,"
513 "pg_relation_filepath,"
514 "pg_ls_dir,"
515 "pg_read_file,"
516 "pg_read_binary_file,"
517 "pg_stat_file,"
518 "pg_advisory_lock,"
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,"
529 "pg_sleep"
532 OUString DatabaseMetaData::getTimeDateFunctions( )
534 // TODO
535 return
536 "age,"
537 "age,"
538 "clock_timestamp,"
539 "current_date,"
540 "current_time,"
541 "current_timestamp,"
542 "date_part,"
543 "date_part,"
544 "date_trunc,"
545 "extract,"
546 "extract,"
547 "isfinite,"
548 "isfinite,"
549 "isfinite,"
550 "justify_days,"
551 "justify_hours,"
552 "justify_interval,"
553 "localtime,"
554 "localtimestamp,"
555 "now,"
556 "statement_timestamp,"
557 "timeofday,"
558 "transaction_timestamp,"
561 OUString DatabaseMetaData::getSearchStringEscape( )
563 return "\\";
565 OUString DatabaseMetaData::getExtraNameCharacters( )
567 return "$";
570 sal_Bool DatabaseMetaData::supportsAlterTableWithAddColumn( )
572 return true;
575 sal_Bool DatabaseMetaData::supportsAlterTableWithDropColumn( )
577 return true;
580 sal_Bool DatabaseMetaData::supportsColumnAliasing( )
582 return true;
585 sal_Bool DatabaseMetaData::nullPlusNonNullIsNull( )
587 return true;
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.
594 return false;
597 sal_Bool DatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 )
599 return false;
602 sal_Bool DatabaseMetaData::supportsTableCorrelationNames( )
604 // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..."
605 return true;
609 sal_Bool DatabaseMetaData::supportsDifferentTableCorrelationNames( )
611 return false;
613 sal_Bool DatabaseMetaData::supportsExpressionsInOrderBy( )
615 return true;
618 sal_Bool DatabaseMetaData::supportsOrderByUnrelated( )
620 return true;
623 sal_Bool DatabaseMetaData::supportsGroupBy( )
625 return true;
628 sal_Bool DatabaseMetaData::supportsGroupByUnrelated( )
630 return true;
633 sal_Bool DatabaseMetaData::supportsGroupByBeyondSelect( )
635 return true;
638 sal_Bool DatabaseMetaData::supportsLikeEscapeClause( )
640 return true;
643 sal_Bool DatabaseMetaData::supportsMultipleResultSets( )
645 return true;
648 sal_Bool DatabaseMetaData::supportsMultipleTransactions( )
650 // Allows multiple transactions open at once (on different connections!)
651 return true;
654 sal_Bool DatabaseMetaData::supportsNonNullableColumns( )
656 return true;
660 sal_Bool DatabaseMetaData::supportsMinimumSQLGrammar( )
662 return true;
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"
673 return true;
676 sal_Bool DatabaseMetaData::supportsExtendedSQLGrammar( )
678 return false;
681 sal_Bool DatabaseMetaData::supportsANSI92EntryLevelSQL( )
683 return true;
686 sal_Bool DatabaseMetaData::supportsANSI92IntermediateSQL( )
688 // LEM: jdbc driver says not, although the comments in it seem old
689 return false;
692 sal_Bool DatabaseMetaData::supportsANSI92FullSQL( )
694 // LEM: jdbc driver says not, although the comments in it seem old
695 return false;
698 sal_Bool DatabaseMetaData::supportsIntegrityEnhancementFacility( )
700 // LEM: jdbc driver says yes, although comment says they are not sure what this means...
701 return true;
704 sal_Bool DatabaseMetaData::supportsOuterJoins( )
706 return true;
709 sal_Bool DatabaseMetaData::supportsFullOuterJoins( )
711 return true;
714 sal_Bool DatabaseMetaData::supportsLimitedOuterJoins( )
716 return true;
720 OUString DatabaseMetaData::getSchemaTerm( )
722 return "SCHEMA";
725 OUString DatabaseMetaData::getProcedureTerm( )
727 return "function";
730 OUString DatabaseMetaData::getCatalogTerm( )
732 return "DATABASE";
735 sal_Bool DatabaseMetaData::isCatalogAtStart( )
737 return true;
740 OUString DatabaseMetaData::getCatalogSeparator( )
742 return ".";
745 sal_Bool DatabaseMetaData::supportsSchemasInDataManipulation( )
747 return true;
750 sal_Bool DatabaseMetaData::supportsSchemasInProcedureCalls( )
752 return true;
755 sal_Bool DatabaseMetaData::supportsSchemasInTableDefinitions( )
757 return true;
760 sal_Bool DatabaseMetaData::supportsSchemasInIndexDefinitions( )
762 return true;
765 sal_Bool DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
767 return true;
770 sal_Bool DatabaseMetaData::supportsCatalogsInDataManipulation( )
772 return false;
775 sal_Bool DatabaseMetaData::supportsCatalogsInProcedureCalls( )
777 return false;
780 sal_Bool DatabaseMetaData::supportsCatalogsInTableDefinitions( )
782 return false;
786 sal_Bool DatabaseMetaData::supportsCatalogsInIndexDefinitions( )
788 return false;
792 sal_Bool DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
794 return false;
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
805 return false;
808 sal_Bool DatabaseMetaData::supportsPositionedUpdate( )
810 // LEM: jdbc driver says not, although the comments in it seem old
811 return false;
815 sal_Bool DatabaseMetaData::supportsSelectForUpdate( )
817 return true;
821 sal_Bool DatabaseMetaData::supportsStoredProcedures( )
823 return true;
827 sal_Bool DatabaseMetaData::supportsSubqueriesInComparisons( )
829 return true;
832 sal_Bool DatabaseMetaData::supportsSubqueriesInExists( )
834 return true;
837 sal_Bool DatabaseMetaData::supportsSubqueriesInIns( )
839 return true;
842 sal_Bool DatabaseMetaData::supportsSubqueriesInQuantifieds( )
844 // LEM: jdbc driver says yes, although comment says they don't know what this means...
845 return true;
848 sal_Bool DatabaseMetaData::supportsCorrelatedSubqueries( )
850 return true;
852 sal_Bool DatabaseMetaData::supportsUnion( )
854 return true;
857 sal_Bool DatabaseMetaData::supportsUnionAll( )
859 return true;
862 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossCommit( )
864 return false;
867 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossRollback( )
869 return false;
872 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossCommit( )
874 return true;
876 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossRollback( )
878 return true;
881 sal_Int32 DatabaseMetaData::getMaxBinaryLiteralLength( )
883 return 0;
886 sal_Int32 DatabaseMetaData::getMaxCharLiteralLength( )
888 return 0;
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( )
929 return 0;
932 sal_Int32 DatabaseMetaData::getMaxColumnsInIndex( )
934 return getMaxIndexKeys();
937 sal_Int32 DatabaseMetaData::getMaxColumnsInOrderBy( )
939 return 0;
942 sal_Int32 DatabaseMetaData::getMaxColumnsInSelect( )
944 return 0;
947 sal_Int32 DatabaseMetaData::getMaxColumnsInTable( )
949 return 1600;
952 sal_Int32 DatabaseMetaData::getMaxConnections( )
954 // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports
955 return 0;
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
966 return 0;
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
989 return 0;
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
996 return true;
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.
1004 return 0;
1007 sal_Int32 DatabaseMetaData::getMaxStatements( ) //TODO, don't know
1009 return 0;
1012 sal_Int32 DatabaseMetaData::getMaxTableNameLength( )
1014 return getMaxNameLength();
1017 sal_Int32 DatabaseMetaData::getMaxTablesInSelect( )
1019 return 0;
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( )
1034 return true;
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)
1043 return true;
1044 else
1045 return false;
1048 sal_Bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
1050 return true;
1053 sal_Bool DatabaseMetaData::supportsDataManipulationTransactionsOnly( )
1055 return false;
1058 sal_Bool DatabaseMetaData::dataDefinitionCausesTransactionCommit( )
1060 return false;
1063 sal_Bool DatabaseMetaData::dataDefinitionIgnoredInTransactions( )
1065 return false;
1068 css::uno::Reference< XResultSet > DatabaseMetaData::getProcedures(
1069 const css::uno::Any&,
1070 const OUString&,
1071 const OUString& )
1073 // 1. PROCEDURE_CAT string =&gt; procedure catalog (may be NULL )
1074 // 2. PROCEDURE_SCHEM string =&gt; procedure schema (may be NULL )
1075 // 3. PROCEDURE_NAME string =&gt; procedure name
1076 // 4. reserved for future use
1077 // 5. reserved for future use
1078 // 6. reserved for future use
1079 // 7. REMARKS string =&gt; explanatory comment on the procedure
1080 // 8. PROCEDURE_TYPE short =&gt; 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&,
1094 const OUString&,
1095 const OUString&,
1096 const OUString& )
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(
1123 "SELECT "
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;
1142 while( rs->next() )
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);
1150 if( type == "r" )
1152 if( xRow->getString(1) == "pg_catalog" )
1154 row[3] <<= statics.SYSTEM_TABLE;
1156 else
1158 row[3] <<= statics.TABLE;
1161 else if( type == "v" )
1163 row[3] <<= statics.VIEW;
1165 else
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() )
1176 closeable->close();
1178 return new SequenceResultSet(
1179 m_xMutex, *this, statics.tablesRowNames, vec, m_pSettings->tc );
1182 namespace
1184 // sort no schema first, then "public", then normal schemas, then internal schemas
1185 int compare_schema(const OUString &nsA, const OUString &nsB)
1187 if (nsA.isEmpty())
1189 return nsB.isEmpty() ? 0 : -1;
1191 else if (nsB.isEmpty())
1193 assert(!nsA.isEmpty());
1194 return 1;
1196 else if(nsA == "public")
1198 return (nsB == "public") ? 0 : -1;
1200 else if(nsB == "public")
1202 assert(nsA != "public");
1203 return 1;
1205 else if(nsA.startsWith("pg_"))
1207 if(nsB.startsWith("pg_"))
1208 return nsA.compareTo(nsB);
1209 else
1210 return 1;
1212 else if(nsB.startsWith("pg_"))
1214 return -1;
1216 else
1218 return nsA.compareTo(nsB);
1222 struct SortInternalSchemasLastAndPublicFirst
1224 bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
1226 OUString valueA;
1227 OUString valueB;
1228 a[0] >>= valueA;
1229 b[0] >>= valueB;
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 =&amp;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;
1250 while( rs->next() )
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() )
1262 closeable->close();
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,
1282 m_pSettings->tc );
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] )
1300 // {
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;
1304 // }
1305 // base type
1306 Statics &statics = getStatics();
1307 BaseTypeMap::const_iterator ii = statics.baseTypeMap.find( typeName );
1308 if( ii != statics.baseTypeMap.end() )
1310 ret = ii->second;
1313 else if( typtype == "c" )
1315 ret = css::sdbc::DataType::STRUCT;
1317 else if( typtype == "d" )
1319 ret = css::sdbc::DataType::LONGVARCHAR;
1321 return ret;
1324 namespace {
1325 bool isSystemColumn( sal_Int16 attnum )
1327 return attnum <= 0;
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 )
1341 *precision = 0;
1342 *scale = 0;
1344 else
1346 switch( dataType )
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;
1353 break;
1355 default:
1356 *precision = atttypmod - PQ_VARHDRSZ;
1357 *scale = 0;
1362 struct DatabaseTypeDescription
1364 DatabaseTypeDescription()
1366 DatabaseTypeDescription( const OUString &name, const OUString & type ) :
1367 typeName( name ),
1368 typeType( 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;
1378 return *this;
1380 OUString typeName;
1381 OUString typeType;
1385 typedef std::unordered_map
1387 sal_Int32,
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 );
1397 int domains = 0;
1398 OUStringBuffer queryBuf(128);
1399 queryBuf.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " );
1400 while( rs->next() )
1402 if( row->getString( 9 ) == "d" && oidMap.find( row->getInt( 12 ) ) == oidMap.end() )
1404 oidMap[row->getInt(12)] = DatabaseTypeDescription();
1405 if( domains )
1406 queryBuf.append( " OR " );
1407 queryBuf.append( "oid = " );
1408 queryBuf.append( row->getInt(12 ) );
1409 domains ++;
1412 rs->beforeFirst();
1414 if( domains )
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();
1437 // continue !
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)
1449 // => not supported
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.
1466 // => 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)
1470 // => TODO ??
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
1481 // => empty
1482 // 15. SQL_DATETIME_SUB long => unused
1483 // => empty
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
1492 // nobody knows.
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
1508 "FROM pg_class, "
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#" );
1539 while( rs->next() )
1541 if( ! isSystemColumn( xRow->getShort( 12 ) ) )
1543 OUString sNewSchema( xRow->getString(1) );
1544 OUString sNewTable( xRow->getString(2) );
1545 if ( sNewSchema != sSchema || sNewTable != sTable )
1547 colNum = 1;
1548 sSchema = sNewSchema;
1549 sTable = sNewTable;
1551 else
1552 ++colNum;
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 );
1564 else
1566 type = typeNameToDataType( xRow->getString(4), xRow->getString(8) );
1568 extractPrecisionAndScale( type, xRow->getInt(5) , &precision, &scale );
1569 row[4] <<= type;
1570 row[5] <<= xRow->getString(4);
1571 row[6] <<= precision;
1572 // row[7] BUFFER_LENGTH not used
1573 row[8] <<= scale;
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;
1580 else
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() )
1598 closeable->close();
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();
1622 return rs;
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();
1641 return rs;
1644 css::uno::Reference< XResultSet > DatabaseMetaData::getBestRowIdentifier(
1645 const css::uno::Any&,
1646 const OUString&,
1647 const OUString&,
1648 sal_Int32,
1649 sal_Bool )
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&,
1659 const OUString&,
1660 const OUString& )
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 )
1673 //LEM TODO: review
1674 MutexGuard guard( m_xMutex->GetMutex() );
1676 // 1. TABLE_CAT string =&gt; table catalog (may be NULL )
1677 // 2. TABLE_SCHEM string =&gt; table schema (may be NULL )
1678 // 3. TABLE_NAME string =&gt; table name
1679 // 4. COLUMN_NAME string =&gt; column name
1680 // 5. KEY_SEQ short =&gt; sequence number within primary key
1681 // 6. PK_NAME string =&gt; 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, "
1688 "cl.relname, "
1689 "con.conkey, "
1690 "con.conname, "
1691 "con.conrelid "
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;
1704 while( rs->next() )
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);
1714 int i = 0;
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] )
1726 i++;
1727 int start = 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() )
1737 closeable->close();
1741 OUString lastTableOid;
1742 sal_Int32 index = 0;
1743 std::vector< std::vector< Any > > ret( vec.size() );
1744 int elements = 0;
1745 for (auto const& elem : vec)
1748 std::vector< Any > row = elem;
1749 OUString tableOid;
1750 OUString attnum;
1752 row[4] >>= tableOid;
1753 row[3] >>= attnum;
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 );
1765 if( rs->next() )
1767 // column name
1768 row[3] <<= xRow->getString( 1 );
1769 if( tableOid != lastTableOid )
1770 index = 1;
1771 lastTableOid = tableOid;
1772 row[4] <<= OUString::number( index );
1773 index ++;
1776 Reference< XCloseable > closeable( statement, UNO_QUERY );
1777 if( closeable.is() )
1778 closeable->close();
1780 ret[elements] = row;
1781 elements ++;
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) \
1793 " ELSE NULL "
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 " \
1801 SQL_CASE_KEYRULE \
1802 " END AS UPDATE_RULE, " \
1803 " CASE con.confdeltype " \
1804 SQL_CASE_KEYRULE \
1805 " END AS DELETE_RULE, " \
1806 " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \
1807 " CASE " \
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 " \
1812 "FROM " \
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);
1946 sSQL.append(
1947 " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable "
1948 " FROM ("
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
1955 sSQL.append(
1956 " UNION "
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"
1963 " UNION ALL"
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");
1969 sSQL.append(
1970 " ) dp,"
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() );
1977 sSQL.append(
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
1985 sSQL.append(
1986 " UNION "
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"
1993 " UNION ALL"
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");
1999 sSQL.append(
2000 " ) dp,"
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 )
2016 unsigned int i = 0;
2017 if ( ! primarySchema.isEmpty() )
2018 i |= 0x01;
2019 if ( ! primaryTable.isEmpty() )
2020 i |= 0x02;
2021 if ( ! foreignSchema.isEmpty() )
2022 i |= 0x04;
2023 if ( ! foreignTable.isEmpty() )
2024 i |= 0x08;
2026 Reference< XPreparedStatement > stmt = m_getReferences_stmt[i];
2027 Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
2029 unsigned int j = 1;
2030 if ( i & 0x01 )
2031 param->setString( j++, primarySchema );
2032 if ( i & 0x02 )
2033 param->setString( j++, primaryTable );
2034 if ( i & 0x04 )
2035 param->setString( j++, foreignSchema );
2036 if ( i & 0x08 )
2037 param->setString( j++, foreignTable );
2039 Reference< XResultSet > rs = stmt->executeQuery();
2041 return rs;
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 );
2072 namespace
2074 struct TypeInfoByDataTypeSorter
2076 bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
2078 OUString valueA;
2079 OUString valueB;
2080 a[1 /*DATA_TYPE*/] >>= valueA;
2081 b[1 /*DATA_TYPE*/] >>= valueB;
2082 if( valueB.toInt32() == valueA.toInt32() )
2084 OUString nameA;
2085 OUString nameB;
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
2091 sal_Int32 nIndex=0;
2092 nsA = nameA.getToken(0, '.', nIndex);
2093 if (nIndex<0)
2095 tnA = nsA;
2096 nsA.clear();
2098 else
2100 tnA = nameA.getToken(0, '.', nIndex);
2101 assert(nIndex < 0);
2104 nIndex=0;
2105 nsB = nameB.getToken(0, '.', nIndex);
2106 if (nIndex<0)
2108 tnB = nsB;
2109 nsB.clear();
2111 else
2113 tnB = nameB.getToken(0, '.', nIndex);
2114 assert(nIndex < 0);
2117 const int ns_comp = compare_schema(nsA, nsB);
2118 if(ns_comp == 0)
2120 if(nsA.isEmpty())
2122 assert(nsB.isEmpty());
2123 // within each type category, sort privileged choice first
2124 if( tnA == "int4" || tnA == "varchar" || tnA == "char" || tnA == "text")
2125 return true;
2126 if( tnB == "int4" || tnB == "varchar" || tnB == "char" || tnB == "text")
2127 return false;
2129 return nameA.compareTo( nameB ) < 0;
2131 else
2133 return ns_comp < 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;
2149 return ret;
2152 sal_Int32 getMaxScale( sal_Int32 dataType )
2154 // LEM TODO: review, see where used, see JDBC, ...
2155 sal_Int32 ret = 0;
2156 if( dataType == css::sdbc::DataType::NUMERIC )
2157 ret = 1000; // see pg-docs DataType/numeric
2158 // else if( dataType == DataType::DOUBLE )
2159 // ret = 308;
2160 // else if( dataType == DataType::FLOAT )
2161 // ret =
2162 return ret;
2165 OUString construct_full_typename(const OUString &ns, const OUString &tn)
2167 if(ns.isEmpty() || ns == "pg_catalog")
2168 return tn;
2169 else
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
2203 (may be <NULL/>)
2204 4. LITERAL_SUFFIX string ==> suffix used to quote a literal
2205 (may be <NULL/>)
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 );
2212 while( rs->next() )
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
2226 // length (=1GB).
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 )
2232 precision = 1000;
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
2249 else
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(
2298 m_xMutex,
2299 *this,
2300 getStatics().typeinfoColumnNames,
2301 vec,
2302 m_pSettings->tc,
2303 &( getStatics().typeInfoMetaData ));
2307 css::uno::Reference< XResultSet > DatabaseMetaData::getIndexInfo(
2308 const css::uno::Any& ,
2309 const OUString& schema,
2310 const OUString& table,
2311 sal_Bool unique,
2312 sal_Bool )
2314 //LEM TODO: review
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;
2352 // C_IS_PRIMARY = 6
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
2370 "indkey " // 7
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;
2383 while( rs->next() )
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,
2426 vec,
2427 m_pSettings->tc );
2430 sal_Bool DatabaseMetaData::supportsResultSetType( sal_Int32 setType )
2432 if ( setType == css::sdbc::ResultSetType::SCROLL_SENSITIVE )
2433 return false;
2434 else
2435 return true;
2438 sal_Bool DatabaseMetaData::supportsResultSetConcurrency(
2439 sal_Int32 setType, sal_Int32 )
2441 if ( ! supportsResultSetType( setType ) )
2442 return false;
2443 else
2444 return true;
2447 sal_Bool DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /* setType */ )
2449 return true;
2452 sal_Bool DatabaseMetaData::ownDeletesAreVisible( sal_Int32 /* setType */ )
2454 return true;
2457 sal_Bool DatabaseMetaData::ownInsertsAreVisible( sal_Int32 /* setType */ )
2459 return true;
2462 sal_Bool DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /* setType */ )
2464 return false;
2467 sal_Bool DatabaseMetaData::othersDeletesAreVisible( sal_Int32 /* setType */ )
2469 return false;
2472 sal_Bool DatabaseMetaData::othersInsertsAreVisible( sal_Int32 /* setType */ )
2474 return false;
2477 sal_Bool DatabaseMetaData::updatesAreDetected( sal_Int32 /* setType */ )
2479 return false;
2482 sal_Bool DatabaseMetaData::deletesAreDetected( sal_Int32 /* setType */ )
2484 return false;
2486 sal_Bool DatabaseMetaData::insertsAreDetected( sal_Int32 /* setType */ )
2488 return false;
2491 sal_Bool DatabaseMetaData::supportsBatchUpdates( )
2493 return true;
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()
2506 return m_origin;
2510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */