Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_databasemetadata.cxx
blob6ae2d0c71c9c87bccf59162925d6cce3885cad15
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 "pq_databasemetadata.hxx"
69 #include "pq_driver.hxx"
70 #include "pq_sequenceresultset.hxx"
71 #include "pq_statics.hxx"
72 #include "pq_tools.hxx"
74 #include <rtl/ustrbuf.hxx>
76 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
77 #include <com/sun/star/sdbc/ResultSetType.hpp>
78 #include <com/sun/star/sdbc/XPreparedStatement.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>
84 #include <com/sun/star/sdbc/KeyRule.hpp>
85 #include <com/sun/star/sdbc/Deferrability.hpp>
87 using ::osl::MutexGuard;
90 using namespace com::sun::star::sdbc;
92 using com::sun::star::uno::RuntimeException;
93 using com::sun::star::uno::Reference;
94 using com::sun::star::uno::Sequence;
95 using com::sun::star::uno::Any;
96 using com::sun::star::uno::makeAny;
97 using com::sun::star::uno::UNO_QUERY;
98 using com::sun::star::uno::UNO_QUERY_THROW;
100 namespace pq_sdbc_driver
102 typedef
103 std::vector
105 com::sun::star::uno::Sequence< com::sun::star::uno::Any >
106 > SequenceAnyVector;
109 #define QUOTEME(X) #X
110 #define STRINGIFY(X) QUOTEME(X)
112 // These are pre-processor versions of KeyRule.idl declarations
113 // These are inherited from JDBC, and thus won't change anytime soon.
114 // Having them as pre-processor definitions allows to include them
115 // into compile-time strings (through STRINGIFY), which can be passed to ASCII_STR.
116 // That is without resorting to horrendeous hacks in template meta-programming.
117 #define KEYRULE_CASCADE 0
118 #define KEYRULE_RESTRICT 1
119 #define KEYRULE_SET_NULL 2
120 #define KEYRULE_NO_ACTION 4
121 #define KEYRULE_SET_DEFAULT 4
122 // Ditto for Deferrability.idl
123 #define DEFERRABILITY_INITIALLY_DEFERRED 5
124 #define DEFERRABILITY_INITIALLY_IMMEDIATE 6
125 #define DEFERRABILITY_NONE 7
127 void DatabaseMetaData::checkClosed()
128 throw (SQLException, RuntimeException)
132 DatabaseMetaData::DatabaseMetaData(
133 const ::rtl::Reference< RefCountedMutex > & refMutex,
134 const ::com::sun::star::uno::Reference< com::sun::star::sdbc::XConnection > & origin,
135 ConnectionSettings *pSettings )
136 : m_refMutex( refMutex ),
137 m_pSettings( pSettings ),
138 m_origin( origin ),
139 m_getIntSetting_stmt ( m_origin->prepareStatement("SELECT setting FROM pg_catalog.pg_settings WHERE name=?") )
141 init_getReferences_stmt();
142 init_getPrivs_stmt();
145 sal_Bool DatabaseMetaData::allProceduresAreCallable( ) throw (SQLException, RuntimeException, std::exception)
147 // TODO
148 return sal_False;
151 sal_Bool DatabaseMetaData::allTablesAreSelectable( ) throw (SQLException, RuntimeException, std::exception)
153 return sal_True;
156 OUString DatabaseMetaData::getURL( ) throw (SQLException, RuntimeException, std::exception)
158 // TODO
159 // LEM TODO: implement
160 return OUString();
163 OUString DatabaseMetaData::getUserName( ) throw (SQLException, RuntimeException, std::exception)
165 return m_pSettings->user;
168 sal_Bool DatabaseMetaData::isReadOnly( ) throw (SQLException, RuntimeException, std::exception)
170 return sal_False;
174 sal_Bool DatabaseMetaData::nullsAreSortedHigh( ) throw (SQLException, RuntimeException, std::exception)
176 // Whether NULL values are considered, for sorting purposes, LARGER than any other value.
177 // Specification: http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#nullsAreSortedHigh()
178 // PostgreSQL behaviour: http://www.postgresql.org/docs/9.1/static/queries-order.htlm
179 return sal_True;
182 sal_Bool DatabaseMetaData::nullsAreSortedLow( ) throw (SQLException, RuntimeException, std::exception)
184 return ! nullsAreSortedHigh();
187 sal_Bool DatabaseMetaData::nullsAreSortedAtStart( ) throw (SQLException, RuntimeException, std::exception)
189 return sal_False;
192 sal_Bool DatabaseMetaData::nullsAreSortedAtEnd( ) throw (SQLException, RuntimeException, std::exception)
194 return sal_False;
197 OUString DatabaseMetaData::getDatabaseProductName( ) throw (SQLException, RuntimeException, std::exception)
199 return OUString("PostgreSQL");
202 OUString DatabaseMetaData::getDatabaseProductVersion( ) throw (SQLException, RuntimeException, std::exception)
204 return OUString::createFromAscii( PQparameterStatus( m_pSettings->pConnection, "server_version" ) );
206 OUString DatabaseMetaData::getDriverName( ) throw (SQLException, RuntimeException, std::exception)
208 return OUString("postgresql-sdbc");
211 OUString DatabaseMetaData::getDriverVersion( ) throw (SQLException, RuntimeException, std::exception)
213 return OUString(PQ_SDBC_DRIVER_VERSION);
216 sal_Int32 DatabaseMetaData::getDriverMajorVersion( ) throw (RuntimeException, std::exception)
218 return PQ_SDBC_MAJOR;
221 sal_Int32 DatabaseMetaData::getDriverMinorVersion( ) throw (RuntimeException, std::exception)
223 return PQ_SDBC_MINOR;
226 sal_Bool DatabaseMetaData::usesLocalFiles( ) throw (SQLException, RuntimeException, std::exception)
228 // LEM TODO:
229 // http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/XDatabaseMetaData_Interface
230 // says "Returns true when the catalog name of the
231 // database should not appear in the DatasourceBrowser
232 // of OpenOffice.org API, otherwise false is returned."
233 // So, hmmm, think about it.
234 return sal_False;
237 sal_Bool DatabaseMetaData::usesLocalFilePerTable( ) throw (SQLException, RuntimeException, std::exception)
239 return sal_False;
242 sal_Bool DatabaseMetaData::supportsMixedCaseIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
244 return sal_False;
247 sal_Bool DatabaseMetaData::storesUpperCaseIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
249 return sal_False;
252 sal_Bool DatabaseMetaData::storesLowerCaseIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
254 return sal_True;
258 sal_Bool DatabaseMetaData::storesMixedCaseIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
260 return sal_False;
264 sal_Bool DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
266 return sal_True;
269 sal_Bool DatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
271 return sal_False;
275 sal_Bool DatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
277 return sal_False;
281 sal_Bool DatabaseMetaData::storesMixedCaseQuotedIdentifiers( ) throw (SQLException, RuntimeException, std::exception)
283 return sal_False;
287 OUString DatabaseMetaData::getIdentifierQuoteString( ) throw (SQLException, RuntimeException, std::exception)
289 return OUString("\"");
292 OUString DatabaseMetaData::getSQLKeywords( ) throw (SQLException, RuntimeException, std::exception)
294 // In Java 6, this is all keywords that are not SQL:2003
295 // In Java 2 v1.4 and as per LibreOffice SDK doc, this is all keywords that are not SQL92
296 // I understand this to mean "reserved keywords" only.
297 // See http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
298 // LEM TODO: consider using pg_get_keywords(), filter on catcode
299 return OUString(
300 "ANALYSE,"
301 "ANALYZE,"
302 "ARRAY," //SQL:1999
303 "ASYMMETRIC," //SQL:2003
304 "BINARY," //SQL:1999
305 "CONCURRENTLY,"
306 "CURRENT_CATALOG," //SQL:2008
307 "CURRENT_ROLE," //SQL:1999
308 "CURRENT_SCHEMA," //SQL:2008
309 "DO,"
310 "FREEZE,"
311 "ILIKE,"
312 "ISNULL,"
313 "LIMIT," //SQL:1999; non-reserved in SQL:2003
314 "LOCALTIME," //SQL:1999
315 "LOCALTIMESTAMP," //SQL:1999
316 "NOTNULL,"
317 "OFFSET," //SQL:2008
318 "OVER," //SQL:2003
319 "PLACING," //non-reserved in SQL:2003
320 "RETURNING," //non-reserved in SQL:2008
321 "SIMILAR," //SQL:2003
322 "VARIADIC,"
323 "VERBOSE,"
324 "WINDOW" //SQL:2003
327 OUString DatabaseMetaData::getNumericFunctions( ) throw (SQLException, RuntimeException, std::exception)
329 // See http://www.postgresql.org/docs/9.1/static/functions-math.html
330 // LEM TODO: Err... http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/Support_Scalar_Functions
331 // says this should be "Open Group CLI" names, not PostgreSQL names.
332 // Currently this is just a list of supported functions in PostgreSQL, with PostgreSQL names.
333 // And it is my job to map from Open Group CLI names/syntax to PostgreSQL names/syntax. Where? By parsing the SQL???
334 // Should look at what the JDBC driver is doing.
335 return OUString(
336 "abs,"
337 "cbrt,"
338 "ceil,"
339 "ceiling,"
340 "degrees,"
341 "div,"
342 "exp,"
343 "floor,"
344 "ln,"
345 "log,"
346 "mod,"
347 "pi,"
348 "power,"
349 "radians,"
350 "random,"
351 "round,"
352 "setseed,"
353 "sign,"
354 "sqrt,"
355 "trunc,"
356 "width_bucket,"
357 "acos,"
358 "asin,"
359 "atan,"
360 "atan2,"
361 "cos,"
362 "cot,"
363 "sin,"
364 "tan"
368 OUString DatabaseMetaData::getStringFunctions( ) throw (SQLException, RuntimeException, std::exception)
370 // See http://www.postgresql.org/docs/9.1/static/functions-string.html
371 return OUString(
372 "bit_length,"
373 "char_length,"
374 "character_length,"
375 "lower,"
376 "octet_length,"
377 "overlay,"
378 "position,"
379 "substring,"
380 "trim,"
381 "upper,"
382 "ascii,"
383 "btrim,"
384 "chr,"
385 "concat,"
386 "concat_ws,"
387 "convert,"
388 "convert_from,"
389 "convert_to,"
390 "decode,"
391 "encode,"
392 "foramt,"
393 "initcap,"
394 "left,"
395 "length,"
396 "lpad,"
397 "ltrim,"
398 "md5,"
399 "pg_client_encoding,"
400 "quote_ident,"
401 "quote_literal,"
402 "quote_nullable,"
403 "regexp_matches,"
404 "regexp_replace,"
405 "regexp_split_to_array,"
406 "regexp_split_to_table,"
407 "repeat,"
408 "replace,"
409 "reverse,"
410 "right,"
411 "rpad,"
412 "rtrim,"
413 "split_part,"
414 "strpos,"
415 "substr,"
416 "to_ascii,"
417 "to_hex,"
418 "translate"
422 OUString DatabaseMetaData::getSystemFunctions( ) throw (SQLException, RuntimeException, std::exception)
424 // See http://www.postgresql.org/docs/9.1/static/functions-info.html
425 // and http://www.postgresql.org/docs/9.1/static/functions-admin.html
426 return OUString(
427 "current_catalog,"
428 "current_database,"
429 "current_query,"
430 "current_schema,"
431 "current_schemas,"
432 "current_user,"
433 "inet_client_addr,"
434 "inet_client_port,"
435 "inet_server_addr,"
436 "inet_server_port,"
437 "pg_backend_pid,"
438 "pg_conf_load_time,"
439 "pg_is_other_temp_schema,"
440 "pg_listening_channels,"
441 "pg_my_temp_schema,"
442 "pg_postmaster_start_time,"
443 "session_user,"
444 "user,"
445 "version,"
446 "has_any_column_privilege,"
447 "has_any_column_privilege,"
448 "has_any_column_privilege,"
449 "has_column_privilege,"
450 "has_database_privilege,"
451 "has_foreign_data_wrapper_privilege,"
452 "has_function_privilege,"
453 "has_language_privilege,"
454 "has_schema_privilege,"
455 "has_sequence_privilege,"
456 "has_server_privilege,"
457 "has_table_privilege,"
458 "has_tablespace_privilege,"
459 "pg_has_role,"
460 "pg_collation_is_visible,"
461 "pg_conversion_is_visible,"
462 "pg_function_is_visible,"
463 "pg_opclass_is_visible,"
464 "pg_operator_is_visible,"
465 "pg_table_is_visible,"
466 "pg_ts_config_is_visible,"
467 "pg_ts_dict_is_visible,"
468 "pg_ts_parser_is_visible,"
469 "pg_ts_template_is_visible,"
470 "pg_type_is_visible,"
471 "format_type,"
472 "pg_describe_object,"
473 "pg_get_constraintdef,"
474 "pg_get_expr,"
475 "pg_get_functiondef,"
476 "pg_get_function_arguments,"
477 "pg_get_function_identity_arguments,"
478 "pg_get_function_result,"
479 "pg_get_indexdef,"
480 "pg_get_keywords,"
481 "pg_get_ruledef,"
482 "pg_get_serial_sequence,"
483 "pg_get_triggerdef,"
484 "pg_get_userbyid,"
485 "pg_get_viewdef,"
486 "pg_options_to_table,"
487 "pg_tablespace_databases,"
488 "pg_typeof,"
489 "col_description,"
490 "obj_description,"
491 "shobj_description,"
492 "txid_current,"
493 "txid_current_snapshot,"
494 "txid_snapshot_xip,"
495 "txid_snapshot_xmax,"
496 "txid_snapshot_xmin,"
497 "txid_visible_in_snapshot,"
498 "xmin,"
499 "xmax,"
500 "xip_list,"
501 "current_setting,"
502 "set_config,"
503 "pg_cancel_backend,"
504 "pg_reload_conf,"
505 "pg_rotate_logfile,"
506 "pg_terminate_backend,"
507 "pg_create_restore_point,"
508 "pg_current_xlog_insert_location,"
509 "pg_current_xlog_location,"
510 "pg_start_backup,"
511 "pg_stop_backup,"
512 "pg_switch_xlog,"
513 "pg_xlogfile_name,"
514 "pg_xlogfile_name_offset,"
515 "pg_is_in_recovery,"
516 "pg_last_xlog_receive_location,"
517 "pg_last_xlog_replay_location,"
518 "pg_last_xact_replay_timestamp,"
519 "pg_is_xlog_replay_paused,"
520 "pg_xlog_replay_pause,"
521 "pg_xlog_replay_resume,"
522 "pg_column_size,"
523 "pg_database_size,"
524 "pg_indexes_size,"
525 "pg_relation_size,"
526 "pg_size_pretty,"
527 "pg_table_size,"
528 "pg_tablespace_size,"
529 "pg_tablespace_size,"
530 "pg_total_relation_size,"
531 "pg_relation_filenode,"
532 "pg_relation_filepath,"
533 "pg_ls_dir,"
534 "pg_read_file,"
535 "pg_read_binary_file,"
536 "pg_stat_file,"
537 "pg_advisory_lock,"
538 "pg_advisory_lock_shared,"
539 "pg_advisory_unlock,"
540 "pg_advisory_unlock_all,"
541 "pg_advisory_unlock_shared,"
542 "pg_advisory_xact_lock,"
543 "pg_advisory_xact_lock_shared,"
544 "pg_try_advisory_lock,"
545 "pg_try_advisory_lock_shared,"
546 "pg_try_advisory_xact_lock,"
547 "pg_try_advisory_xact_lock_shared,"
548 "pg_sleep"
551 OUString DatabaseMetaData::getTimeDateFunctions( ) throw (SQLException, RuntimeException, std::exception)
553 // TODO
554 return OUString(
555 "age,"
556 "age,"
557 "clock_timestamp,"
558 "current_date,"
559 "current_time,"
560 "current_timestamp,"
561 "date_part,"
562 "date_part,"
563 "date_trunc,"
564 "extract,"
565 "extract,"
566 "isfinite,"
567 "isfinite,"
568 "isfinite,"
569 "justify_days,"
570 "justify_hours,"
571 "justify_interval,"
572 "localtime,"
573 "localtimestamp,"
574 "now,"
575 "statement_timestamp,"
576 "timeofday,"
577 "transaction_timestamp,"
580 OUString DatabaseMetaData::getSearchStringEscape( ) throw (SQLException, RuntimeException, std::exception)
582 return OUString("\\");
584 OUString DatabaseMetaData::getExtraNameCharacters( ) throw (SQLException, RuntimeException, std::exception)
586 return OUString("$");
589 sal_Bool DatabaseMetaData::supportsAlterTableWithAddColumn( ) throw (SQLException, RuntimeException, std::exception)
591 return sal_True;
594 sal_Bool DatabaseMetaData::supportsAlterTableWithDropColumn( ) throw (SQLException, RuntimeException, std::exception)
596 return sal_True;
599 sal_Bool DatabaseMetaData::supportsColumnAliasing( ) throw (SQLException, RuntimeException, std::exception)
601 return sal_True;
604 sal_Bool DatabaseMetaData::nullPlusNonNullIsNull( ) throw (SQLException, RuntimeException, std::exception)
606 return sal_True;
609 sal_Bool DatabaseMetaData::supportsTypeConversion( ) throw (SQLException, RuntimeException, std::exception)
611 // LEM: this is specifically whether the "CONVERT" function is supported
612 // It seems that in PostgreSQL, that function is only for string encoding, so no.
613 return sal_False;
616 sal_Bool DatabaseMetaData::supportsConvert( sal_Int32 fromType, sal_Int32 toType ) throw (SQLException, RuntimeException, std::exception)
618 (void) fromType; (void) toType;
619 return sal_False;
622 sal_Bool DatabaseMetaData::supportsTableCorrelationNames( ) throw (SQLException, RuntimeException, std::exception)
624 // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..."
625 return sal_True;
629 sal_Bool DatabaseMetaData::supportsDifferentTableCorrelationNames( ) throw (SQLException, RuntimeException, std::exception)
631 return sal_False;
633 sal_Bool DatabaseMetaData::supportsExpressionsInOrderBy( ) throw (SQLException, RuntimeException, std::exception)
635 return sal_True;
638 sal_Bool DatabaseMetaData::supportsOrderByUnrelated( ) throw (SQLException, RuntimeException, std::exception)
640 return sal_True;
643 sal_Bool DatabaseMetaData::supportsGroupBy( ) throw (SQLException, RuntimeException, std::exception)
645 return sal_True;
648 sal_Bool DatabaseMetaData::supportsGroupByUnrelated( ) throw (SQLException, RuntimeException, std::exception)
650 return sal_True;
653 sal_Bool DatabaseMetaData::supportsGroupByBeyondSelect( ) throw (SQLException, RuntimeException, std::exception)
655 return sal_True;
658 sal_Bool DatabaseMetaData::supportsLikeEscapeClause( ) throw (SQLException, RuntimeException, std::exception)
660 return sal_True;
663 sal_Bool DatabaseMetaData::supportsMultipleResultSets( ) throw (SQLException, RuntimeException, std::exception)
665 return sal_True;
668 sal_Bool DatabaseMetaData::supportsMultipleTransactions( ) throw (SQLException, RuntimeException, std::exception)
670 // Allows multiple transactions open at once (on different connections!)
671 return sal_True;
674 sal_Bool DatabaseMetaData::supportsNonNullableColumns( ) throw (SQLException, RuntimeException, std::exception)
676 return sal_True;
680 sal_Bool DatabaseMetaData::supportsMinimumSQLGrammar( ) throw (SQLException, RuntimeException, std::exception)
682 return sal_True;
685 sal_Bool DatabaseMetaData::supportsCoreSQLGrammar( ) throw (SQLException, RuntimeException, std::exception)
687 // LEM: jdbc driver says not, although the comments in it seem old
688 // fdo#45249 Base query design won't use any aggregate function
689 // (except COUNT(*) unless we say yes, so say yes.
690 // Actually, Base assumes *also* support for aggregate functions "collect, fusion, intersection"
691 // as soon as supportsCoreSQLGrammar() returns true.
692 // Those are *not* Core SQL, though. They are in optional feature S271 "Basic multiset support"
693 return sal_True;
696 sal_Bool DatabaseMetaData::supportsExtendedSQLGrammar( ) throw (SQLException, RuntimeException, std::exception)
698 return sal_False;
701 sal_Bool DatabaseMetaData::supportsANSI92EntryLevelSQL( ) throw (SQLException, RuntimeException, std::exception)
703 return sal_True;
706 sal_Bool DatabaseMetaData::supportsANSI92IntermediateSQL( ) throw (SQLException, RuntimeException, std::exception)
708 // LEM: jdbc driver says not, although the comments in it seem old
709 return sal_False;
712 sal_Bool DatabaseMetaData::supportsANSI92FullSQL( ) throw (SQLException, RuntimeException, std::exception)
714 // LEM: jdbc driver says not, although the comments in it seem old
715 return sal_False;
718 sal_Bool DatabaseMetaData::supportsIntegrityEnhancementFacility( ) throw (SQLException, RuntimeException, std::exception)
720 // LEM: jdbc driver says yes, although comment says they are not sure what this means...
721 return sal_True;
724 sal_Bool DatabaseMetaData::supportsOuterJoins( ) throw (SQLException, RuntimeException, std::exception)
726 return sal_True;
729 sal_Bool DatabaseMetaData::supportsFullOuterJoins( ) throw (SQLException, RuntimeException, std::exception)
731 return sal_True;
734 sal_Bool DatabaseMetaData::supportsLimitedOuterJoins( ) throw (SQLException, RuntimeException, std::exception)
736 return sal_True;
740 OUString DatabaseMetaData::getSchemaTerm( ) throw (SQLException, RuntimeException, std::exception)
742 return OUString("SCHEMA");
745 OUString DatabaseMetaData::getProcedureTerm( ) throw (SQLException, RuntimeException, std::exception)
747 return OUString("function");
750 OUString DatabaseMetaData::getCatalogTerm( ) throw (SQLException, RuntimeException, std::exception)
752 return OUString("DATABASE");
755 sal_Bool DatabaseMetaData::isCatalogAtStart( ) throw (SQLException, RuntimeException, std::exception)
757 return sal_True;
760 OUString DatabaseMetaData::getCatalogSeparator( ) throw (SQLException, RuntimeException, std::exception)
762 return OUString(".");
765 sal_Bool DatabaseMetaData::supportsSchemasInDataManipulation( ) throw (SQLException, RuntimeException, std::exception)
767 return sal_True;
770 sal_Bool DatabaseMetaData::supportsSchemasInProcedureCalls( ) throw (SQLException, RuntimeException, std::exception)
772 return sal_True;
775 sal_Bool DatabaseMetaData::supportsSchemasInTableDefinitions( ) throw (SQLException, RuntimeException, std::exception)
777 return sal_True;
780 sal_Bool DatabaseMetaData::supportsSchemasInIndexDefinitions( ) throw (SQLException, RuntimeException, std::exception)
782 return sal_True;
785 sal_Bool DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) throw (SQLException, RuntimeException, std::exception)
787 return sal_True;
790 sal_Bool DatabaseMetaData::supportsCatalogsInDataManipulation( ) throw (SQLException, RuntimeException, std::exception)
792 return sal_False;
795 sal_Bool DatabaseMetaData::supportsCatalogsInProcedureCalls( ) throw (SQLException, RuntimeException, std::exception)
797 return sal_False;
800 sal_Bool DatabaseMetaData::supportsCatalogsInTableDefinitions( ) throw (SQLException, RuntimeException, std::exception)
802 return sal_False;
806 sal_Bool DatabaseMetaData::supportsCatalogsInIndexDefinitions( ) throw (SQLException, RuntimeException, std::exception)
808 return sal_False;
812 sal_Bool DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) throw (SQLException, RuntimeException, std::exception)
814 return sal_False;
818 // LEM TODO: positioned (through cursor) updates and deletes seem
819 // to be supported; see {UPDATE,DELETE} /table/ (...) WHERE CURRENT OF /cursor_name/" syntax
820 // and http://www.postgresql.org/docs/9.1/static/view-pg-cursors.html
821 // http://www.postgresql.org/docs/9.1/static/libpq-example.html actually uses a cursor :)
822 sal_Bool DatabaseMetaData::supportsPositionedDelete( ) throw (SQLException, RuntimeException, std::exception)
824 // LEM: jdbc driver says not, although the comments in it seem old
825 return sal_False;
828 sal_Bool DatabaseMetaData::supportsPositionedUpdate( ) throw (SQLException, RuntimeException, std::exception)
830 // LEM: jdbc driver says not, although the comments in it seem old
831 return sal_False;
835 sal_Bool DatabaseMetaData::supportsSelectForUpdate( ) throw (SQLException, RuntimeException, std::exception)
837 return sal_True;
841 sal_Bool DatabaseMetaData::supportsStoredProcedures( ) throw (SQLException, RuntimeException, std::exception)
843 return sal_True;
847 sal_Bool DatabaseMetaData::supportsSubqueriesInComparisons( ) throw (SQLException, RuntimeException, std::exception)
849 return sal_True;
852 sal_Bool DatabaseMetaData::supportsSubqueriesInExists( ) throw (SQLException, RuntimeException, std::exception)
854 return sal_True;
857 sal_Bool DatabaseMetaData::supportsSubqueriesInIns( ) throw (SQLException, RuntimeException, std::exception)
859 return sal_True;
862 sal_Bool DatabaseMetaData::supportsSubqueriesInQuantifieds( ) throw (SQLException, RuntimeException, std::exception)
864 // LEM: jdbc driver says yes, although comment says they don't know what this means...
865 return sal_True;
868 sal_Bool DatabaseMetaData::supportsCorrelatedSubqueries( ) throw (SQLException, RuntimeException, std::exception)
870 return sal_True;
872 sal_Bool DatabaseMetaData::supportsUnion( ) throw (SQLException, RuntimeException, std::exception)
874 return sal_True;
877 sal_Bool DatabaseMetaData::supportsUnionAll( ) throw (SQLException, RuntimeException, std::exception)
879 return sal_True;
882 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossCommit( ) throw (SQLException, RuntimeException, std::exception)
884 return sal_False;
887 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossRollback( ) throw (SQLException, RuntimeException, std::exception)
889 return sal_False;
892 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossCommit( ) throw (SQLException, RuntimeException, std::exception)
894 return sal_True;
896 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossRollback( ) throw (SQLException, RuntimeException, std::exception)
898 return sal_True;
901 sal_Int32 DatabaseMetaData::getMaxBinaryLiteralLength( ) throw (SQLException, RuntimeException, std::exception)
903 return 0;
906 sal_Int32 DatabaseMetaData::getMaxCharLiteralLength( ) throw (SQLException, RuntimeException, std::exception)
908 return 0;
911 // Copied / adapted / simplified from JDBC driver
912 sal_Int32 DatabaseMetaData::getIntSetting(const OUString& settingName)
913 throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
915 MutexGuard guard( m_refMutex->mutex );
917 Reference< XParameters > params(m_getIntSetting_stmt, UNO_QUERY_THROW );
918 params->setString(1, settingName );
919 Reference< XResultSet > rs = m_getIntSetting_stmt->executeQuery();
920 Reference< XRow > xRow( rs , UNO_QUERY_THROW );
921 OSL_VERIFY(rs->next());
922 OSL_ENSURE(rs->isFirst(), "postgresql-sdbc DatabaseMetaData getIntSetting not on first row");
923 OSL_ENSURE(rs->isLast(), "postgresql-sdbc DatabaseMetaData getIntSetting not on last row");
924 return xRow->getInt(1);
927 sal_Int32 DatabaseMetaData::getMaxNameLength()
928 throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
930 if ( m_pSettings->maxNameLen == 0)
931 m_pSettings->maxNameLen = getIntSetting( "max_identifier_length" );
932 OSL_ENSURE(m_pSettings->maxNameLen, "postgresql-sdbc: maxNameLen is zero");
933 return m_pSettings->maxNameLen;
936 sal_Int32 DatabaseMetaData::getMaxIndexKeys()
937 throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
939 if ( m_pSettings->maxIndexKeys == 0)
940 m_pSettings->maxIndexKeys = getIntSetting("max_index_keys");
941 OSL_ENSURE(m_pSettings->maxIndexKeys, "postgresql-sdbc: maxIndexKeys is zero");
942 return m_pSettings->maxIndexKeys;
945 sal_Int32 DatabaseMetaData::getMaxColumnNameLength( ) throw (SQLException, RuntimeException, std::exception)
947 return getMaxNameLength();
950 sal_Int32 DatabaseMetaData::getMaxColumnsInGroupBy( ) throw (SQLException, RuntimeException, std::exception)
952 return 0;
955 sal_Int32 DatabaseMetaData::getMaxColumnsInIndex( ) throw (SQLException, RuntimeException, std::exception)
957 return getMaxIndexKeys();
960 sal_Int32 DatabaseMetaData::getMaxColumnsInOrderBy( ) throw (SQLException, RuntimeException, std::exception)
962 return 0;
965 sal_Int32 DatabaseMetaData::getMaxColumnsInSelect( ) throw (SQLException, RuntimeException, std::exception)
967 return 0;
970 sal_Int32 DatabaseMetaData::getMaxColumnsInTable( ) throw (SQLException, RuntimeException, std::exception)
972 return 1600;
975 sal_Int32 DatabaseMetaData::getMaxConnections( ) throw (SQLException, RuntimeException, std::exception)
977 // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports
978 return 0;
981 sal_Int32 DatabaseMetaData::getMaxCursorNameLength( ) throw (SQLException, RuntimeException, std::exception) //TODO, don't know
983 return getMaxNameLength();
986 sal_Int32 DatabaseMetaData::getMaxIndexLength( ) throw (SQLException, RuntimeException, std::exception) //TODO, don't know
988 // LEM: that's the index itself, not its name
989 return 0;
992 sal_Int32 DatabaseMetaData::getMaxSchemaNameLength( ) throw (SQLException, RuntimeException, std::exception)
994 return getMaxNameLength();
997 sal_Int32 DatabaseMetaData::getMaxProcedureNameLength( ) throw (SQLException, RuntimeException, std::exception)
999 return getMaxNameLength();
1002 sal_Int32 DatabaseMetaData::getMaxCatalogNameLength( ) throw (SQLException, RuntimeException, std::exception)
1004 return getMaxNameLength();
1007 sal_Int32 DatabaseMetaData::getMaxRowSize( ) throw (SQLException, RuntimeException, std::exception)
1009 // jdbc driver says 1GB, but http://www.postgresql.org/about/ says 1.6TB
1010 // and that 1GB is the maximum _field_ size
1011 // The row limit does not fit into a sal_Int32
1012 return 0;
1015 sal_Bool DatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) throw (SQLException, RuntimeException, std::exception)
1017 // LEM: Err... PostgreSQL basically does not do BLOBs well
1018 // In any case, BLOBs do not change the maximal row length AFAIK
1019 return sal_True;
1022 sal_Int32 DatabaseMetaData::getMaxStatementLength( ) throw (SQLException, RuntimeException, std::exception)
1024 // LEM: actually, that would be 2^sizeof(size_t)-1
1025 // on the server? on the client (because of libpq)? minimum of the two? not sure
1026 // Anyway, big, so say unlimited.
1027 return 0;
1030 sal_Int32 DatabaseMetaData::getMaxStatements( ) throw (SQLException, RuntimeException, std::exception) //TODO, don't know
1032 return 0;
1035 sal_Int32 DatabaseMetaData::getMaxTableNameLength( ) throw (SQLException, RuntimeException, std::exception)
1037 return getMaxNameLength();
1040 sal_Int32 DatabaseMetaData::getMaxTablesInSelect( ) throw (SQLException, RuntimeException, std::exception)
1042 return 0;
1045 sal_Int32 DatabaseMetaData::getMaxUserNameLength( ) throw (SQLException, RuntimeException, std::exception)
1047 return getMaxNameLength();
1050 sal_Int32 DatabaseMetaData::getDefaultTransactionIsolation( ) throw (SQLException, RuntimeException, std::exception)
1052 return com::sun::star::sdbc::TransactionIsolation::READ_COMMITTED;
1055 sal_Bool DatabaseMetaData::supportsTransactions( ) throw (SQLException, RuntimeException, std::exception)
1057 return sal_True;
1060 sal_Bool DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level ) throw (SQLException, RuntimeException, std::exception)
1062 if ( level == com::sun::star::sdbc::TransactionIsolation::READ_COMMITTED
1063 || level == com::sun::star::sdbc::TransactionIsolation::SERIALIZABLE
1064 || level == com::sun::star::sdbc::TransactionIsolation::READ_UNCOMMITTED
1065 || level == com::sun::star::sdbc::TransactionIsolation::REPEATABLE_READ)
1066 return sal_True;
1067 else
1068 return sal_False;
1071 sal_Bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
1072 throw (SQLException, RuntimeException, std::exception)
1074 return sal_True;
1077 sal_Bool DatabaseMetaData::supportsDataManipulationTransactionsOnly( ) throw (SQLException, RuntimeException, std::exception)
1079 return sal_False;
1082 sal_Bool DatabaseMetaData::dataDefinitionCausesTransactionCommit( ) throw (SQLException, RuntimeException, std::exception)
1084 return sal_False;
1087 sal_Bool DatabaseMetaData::dataDefinitionIgnoredInTransactions( ) throw (SQLException, RuntimeException, std::exception)
1089 return sal_False;
1092 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getProcedures(
1093 const ::com::sun::star::uno::Any& catalog,
1094 const OUString& schemaPattern,
1095 const OUString& procedureNamePattern ) throw (SQLException, RuntimeException, std::exception)
1097 (void) catalog; (void) schemaPattern; (void) procedureNamePattern;
1098 // 1. PROCEDURE_CAT string =&gt; procedure catalog (may be NULL )
1099 // 2. PROCEDURE_SCHEM string =&gt; procedure schema (may be NULL )
1100 // 3. PROCEDURE_NAME string =&gt; procedure name
1101 // 4. reserved for future use
1102 // 5. reserved for future use
1103 // 6. reserved for future use
1104 // 7. REMARKS string =&gt; explanatory comment on the procedure
1105 // 8. PROCEDURE_TYPE short =&gt; kind of procedure:
1106 // * UNKNOWN - May return a result
1107 // * NO - Does not return a result
1108 // * RETURN - Returns a result
1110 // LEM TODO: implement
1111 // LEM TODO: at least fake the columns, even if no row.
1112 MutexGuard guard( m_refMutex->mutex );
1113 checkClosed();
1114 return new SequenceResultSet(
1115 m_refMutex, *this, Sequence< OUString >(), Sequence< Sequence< Any > > (), m_pSettings->tc );
1118 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getProcedureColumns(
1119 const ::com::sun::star::uno::Any& catalog,
1120 const OUString& schemaPattern,
1121 const OUString& procedureNamePattern,
1122 const OUString& columnNamePattern ) throw (SQLException, RuntimeException, std::exception)
1124 (void) catalog; (void) schemaPattern; (void) procedureNamePattern; (void) columnNamePattern;
1125 MutexGuard guard( m_refMutex->mutex );
1126 checkClosed();
1127 // LEM TODO: implement
1128 // LEM TODO: at least fake the columns, even if no row.
1129 return new SequenceResultSet(
1130 m_refMutex, *this, Sequence< OUString >(), Sequence< Sequence< Any > > (), m_pSettings->tc );
1133 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getTables(
1134 const ::com::sun::star::uno::Any& catalog,
1135 const OUString& schemaPattern,
1136 const OUString& tableNamePattern,
1137 const ::com::sun::star::uno::Sequence< OUString >& types )
1138 throw (SQLException, RuntimeException, std::exception)
1140 (void) catalog; (void) types;
1141 Statics &statics = getStatics();
1143 MutexGuard guard( m_refMutex->mutex );
1144 checkClosed();
1146 if( isLog( m_pSettings, LogLevel::INFO ) )
1148 OUStringBuffer buf( 128 );
1149 buf.appendAscii( "DatabaseMetaData::getTables got called with " );
1150 buf.append( schemaPattern );
1151 buf.appendAscii( "." );
1152 buf.append( tableNamePattern );
1153 log( m_pSettings, LogLevel::INFO, buf.makeStringAndClear() );
1155 // ignore catalog, as a single pq connection does not support multiple catalogs
1157 // LEM TODO: this does not give the right column names, not the right number of columns, etc.
1158 // Take "inspiration" from JDBC driver
1159 // Ah, this is used to create a XResultSet manually... Try to do it directly in SQL
1160 Reference< XPreparedStatement > statement = m_origin->prepareStatement(
1161 "SELECT "
1162 "DISTINCT ON (pg_namespace.nspname, relname ) " // avoid duplicates (pg_settings !)
1163 "pg_namespace.nspname, relname, relkind, pg_description.description "
1164 "FROM pg_namespace, pg_class LEFT JOIN pg_description ON pg_class.oid = pg_description.objoid "
1165 "WHERE relnamespace = pg_namespace.oid "
1166 "AND ( relkind = 'r' OR relkind = 'v') "
1167 "AND pg_namespace.nspname LIKE ? "
1168 "AND relname LIKE ? "
1169 // "ORDER BY pg_namespace.nspname || relname"
1172 Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
1173 parameters->setString( 1 , schemaPattern );
1174 parameters->setString( 2 , tableNamePattern );
1176 Reference< XResultSet > rs = statement->executeQuery();
1177 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1178 SequenceAnyVector vec;
1180 while( rs->next() )
1182 Sequence< Any > row( 5 );
1184 row[0] <<= m_pSettings->catalog;
1185 row[1] <<= xRow->getString( 1 );
1186 row[2] <<= xRow->getString( 2 );
1187 OUString type = xRow->getString(3);
1188 if( type.equalsAscii( "r" ) )
1190 if( xRow->getString(1).equalsAscii( "pg_catalog" ) )
1192 row[3] <<= statics.SYSTEM_TABLE;
1194 else
1196 row[3] <<= statics.TABLE;
1199 else if( type.equalsAscii( "v" ) )
1201 row[3] <<= statics.VIEW;
1203 else
1205 row[3] <<= statics.UNKNOWN;
1207 row[4] <<= xRow->getString(4);
1209 // no description in postgresql AFAIK
1210 vec.push_back( row );
1212 Reference< XCloseable > closeable( statement, UNO_QUERY );
1213 if( closeable.is() )
1214 closeable->close();
1216 return new SequenceResultSet(
1217 m_refMutex, *this, statics.tablesRowNames, sequence_of_vector(vec), m_pSettings->tc );
1220 struct SortInternalSchemasLastAndPublicFirst
1222 bool operator () ( const Sequence< Any > & a, const Sequence< Any > & b )
1224 OUString valueA;
1225 OUString valueB;
1226 a[0] >>= valueA;
1227 b[0] >>= valueB;
1228 bool ret = false;
1229 if( valueA.startsWith( "public" ) )
1231 ret = true;
1233 else if( valueB.startsWith( "public" ) )
1235 ret = false;
1237 else if( valueA.startsWith( "pg_" ) &&
1238 valueB.startsWith( "pg_" ) )
1240 ret = valueA.compareTo( valueB ) < 0; // sorts equal !
1242 else if( valueA.startsWith( "pg_" ))
1244 ret = false; // sorts last !
1246 else if( valueB.startsWith( "pg_" ) )
1248 ret = true; // sorts first !
1250 else
1252 ret = (valueA.compareTo( valueB ) < 0);
1254 return ret;
1258 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getSchemas( )
1259 throw (SQLException, RuntimeException, std::exception)
1261 MutexGuard guard( m_refMutex->mutex );
1262 checkClosed();
1264 if( isLog( m_pSettings, LogLevel::INFO ) )
1266 log( m_pSettings, LogLevel::INFO, "DatabaseMetaData::getSchemas() got called" );
1268 // <b>TABLE_SCHEM</b> string =&amp;gt; schema name
1269 Reference< XStatement > statement = m_origin->createStatement();
1270 Reference< XResultSet > rs = statement->executeQuery(
1271 "SELECT nspname from pg_namespace" );
1272 // LEM TODO: look at JDBC driver and consider doing the same
1273 // in particular, excluding temporary schemas, but maybe better through pg_is_other_temp_schema(oid) OR == pg_my_temp_schema()
1275 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1276 SequenceAnyVector vec;
1277 while( rs->next() )
1279 Sequence<Any> row(1);
1280 row[0] <<= xRow->getString(1);
1281 vec.push_back( row );
1284 // sort public first, sort internal schemas last, sort rest in alphabetic order
1285 std::sort( vec.begin(), vec.end(), SortInternalSchemasLastAndPublicFirst() );
1287 Reference< XCloseable > closeable( statement, UNO_QUERY );
1288 if( closeable.is() )
1289 closeable->close();
1290 return new SequenceResultSet(
1291 m_refMutex, *this, getStatics().schemaNames, sequence_of_vector(vec), m_pSettings->tc );
1294 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getCatalogs( )
1295 throw (SQLException, RuntimeException, std::exception)
1297 // LEM TODO: return the current catalog like JDBC driver?
1298 // at least fake the columns, even if no content
1299 MutexGuard guard( m_refMutex->mutex );
1300 checkClosed();
1301 return new SequenceResultSet(
1302 m_refMutex, *this, Sequence< OUString >(), Sequence< Sequence< Any > > (), m_pSettings->tc );
1305 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getTableTypes( )
1306 throw (SQLException, RuntimeException, std::exception)
1308 // LEM TODO: this can be made dynamic, see JDBC driver
1309 MutexGuard guard( m_refMutex->mutex );
1310 checkClosed();
1311 return new SequenceResultSet(
1312 m_refMutex, *this, getStatics().tableTypeNames, getStatics().tableTypeData,
1313 m_pSettings->tc );
1317 /** returns the constant from sdbc.DataType
1319 sal_Int32 typeNameToDataType( const OUString &typeName, const OUString &typtype )
1321 // sal_Int32 ret = com::sun::star::sdbc::DataType::DISTINCT;
1322 // map all unknown types to memo (longvarchar). This allows to show them in
1323 // string representation. Additionally, the edit-table-type-selection-box
1324 // is not so unuseable anymore.
1325 sal_Int32 ret = com::sun::star::sdbc::DataType::LONGVARCHAR;
1326 if( typtype.equalsAscii( "b" ) )
1328 // as long as the OOo framework does not support arrays,
1329 // the user is better of with interpreting arrays as strings !
1330 // if( typeName.getLength() && '_' == typeName[0] )
1331 // {
1332 // its just a naming convention, but as long as we don't have anything better,
1333 // we take it as granted
1334 // ret = com::sun::star::sdbc::DataType::ARRAY;
1335 // }
1336 // base type
1337 Statics &statics = getStatics();
1338 BaseTypeMap::iterator ii = statics.baseTypeMap.find( typeName );
1339 if( ii != statics.baseTypeMap.end() )
1341 ret = ii->second;
1344 else if( typtype.equalsAscii( "c" ) )
1346 ret = com::sun::star::sdbc::DataType::STRUCT;
1348 else if( typtype.equalsAscii( "d" ) )
1350 ret = com::sun::star::sdbc::DataType::LONGVARCHAR;
1352 return ret;
1355 namespace {
1356 inline bool isSystemColumn( sal_Int16 attnum )
1358 return attnum <= 0;
1362 // is not exported by the postgres header
1363 const static int PQ_VARHDRSZ = sizeof( sal_Int32 );
1365 // Oh, quelle horreur
1366 // LEM TODO: Need to severely rewrite that!
1367 // should probably just "do the same" as ODBC or JDBC drivers...
1368 static void extractPrecisionAndScale(
1369 sal_Int32 dataType, sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale )
1371 if( atttypmod < PQ_VARHDRSZ )
1373 *precision = 0;
1374 *scale = 0;
1376 else
1378 switch( dataType )
1380 case com::sun::star::sdbc::DataType::NUMERIC:
1381 case com::sun::star::sdbc::DataType::DECIMAL:
1383 *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff;
1384 *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff;
1385 break;
1387 default:
1388 *precision = atttypmod - PQ_VARHDRSZ;
1389 *scale = 0;
1394 struct DatabaseTypeDescription
1396 DatabaseTypeDescription()
1398 DatabaseTypeDescription( const OUString &name, const OUString & type ) :
1399 typeName( name ),
1400 typeType( type )
1402 DatabaseTypeDescription( const DatabaseTypeDescription &source ) :
1403 typeName( source.typeName ),
1404 typeType( source.typeType )
1406 DatabaseTypeDescription & operator = ( const DatabaseTypeDescription & source )
1408 typeName = source.typeName;
1409 typeType = source.typeType;
1410 return *this;
1412 OUString typeName;
1413 OUString typeType;
1416 typedef ::boost::unordered_map
1418 sal_Int32,
1419 DatabaseTypeDescription,
1420 ::boost::hash< sal_Int32 >,
1421 ::std::equal_to< sal_Int32 >
1422 > Oid2DatabaseTypeDescriptionMap;
1424 static void columnMetaData2DatabaseTypeDescription(
1425 Oid2DatabaseTypeDescriptionMap &oidMap,
1426 const Reference< XResultSet > &rs,
1427 const Reference< XStatement > &stmt )
1429 Reference< XRow > row( rs, UNO_QUERY_THROW );
1430 int domains = 0;
1431 OUStringBuffer queryBuf(128);
1432 queryBuf.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " );
1433 while( rs->next() )
1435 if( row->getString( 9 ) == "d" && oidMap.find( row->getInt( 12 ) ) == oidMap.end() )
1437 oidMap[row->getInt(12)] = DatabaseTypeDescription();
1438 if( domains )
1439 queryBuf.appendAscii( " OR " );
1440 queryBuf.appendAscii( "oid = " );
1441 queryBuf.append( row->getInt(12 ), 10 );
1442 domains ++;
1445 rs->beforeFirst();
1447 if( domains )
1449 Reference< XResultSet > rsDomain = stmt->executeQuery( queryBuf.makeStringAndClear() );
1450 row = Reference< XRow >( rsDomain, UNO_QUERY_THROW );
1451 while( rsDomain->next() )
1453 oidMap[row->getInt(1)] = DatabaseTypeDescription(row->getString(3), row->getString(2) );
1455 disposeNoThrow( stmt );
1462 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getColumns(
1463 const ::com::sun::star::uno::Any& catalog,
1464 const OUString& schemaPattern,
1465 const OUString& tableNamePattern,
1466 const OUString& columnNamePattern ) throw (SQLException, RuntimeException, std::exception)
1468 (void) catalog;
1469 // LEM TODO: review in comparison with JDBC driver
1470 Statics &statics = getStatics();
1472 // continue !
1473 MutexGuard guard( m_refMutex->mutex );
1474 checkClosed();
1476 if( isLog( m_pSettings, LogLevel::INFO ) )
1478 OUStringBuffer buf( 128 );
1479 buf.appendAscii( "DatabaseMetaData::getColumns got called with " );
1480 buf.append( schemaPattern );
1481 buf.appendAscii( "." );
1482 buf.append( tableNamePattern );
1483 buf.appendAscii( "." );
1484 buf.append( columnNamePattern );
1485 log( m_pSettings, LogLevel::INFO, buf.makeStringAndClear() );
1488 // ignore catalog, as a single pq connection
1489 // does not support multiple catalogs anyway
1490 // We don't use information_schema.columns because it contains
1491 // only the columns the current user has any privilege over.
1493 // 1. TABLE_CAT string => table catalog (may be NULL)
1494 // => not supported
1495 // 2. TABLE_SCHEM string => table schema (may be NULL)
1496 // => pg_namespace.nspname
1497 // 3. TABLE_NAME string => table name
1498 // => pg_class.relname
1499 // 4. COLUMN_NAME string => column name
1500 // => pg_attribure.attname
1501 // 5. DATA_TYPE short => SQL type from java.sql.Types
1502 // => pg_type.typname => sdbc.DataType
1503 // 6. TYPE_NAME string => Data source dependent type name, for a UDT the
1504 // type name is fully qualified
1505 // => pg_type.typname
1506 // 7. COLUMN_SIZE long => column size. For char or date types this is
1507 // the maximum number of characters, for numeric
1508 // or decimal types this is precision.
1509 // => pg_attribute.atttypmod
1510 // 8. BUFFER_LENGTH is not used.
1511 // => not used
1512 // 9. DECIMAL_DIGITS long => the number of fractional digits
1513 // => don't know ! TODO !
1514 // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2)
1515 // => TODO ??
1516 // 11. NULLABLE long => is NULL allowed?
1517 // NO_NULLS - might not allow NULL values
1518 // NULABLE - definitely allows NULL values
1519 // NULLABLE_UNKNOWN - nullability unknown
1520 // => pg_attribute.attnotnull
1521 // 12. REMARKS string => comment describing column (may be NULL )
1522 // => pg_description.description
1523 // 13. COLUMN_DEF string => default value (may be NULL)
1524 // => pg_type.typdefault
1525 // 14. SQL_DATA_TYPE long => unused
1526 // => empty
1527 // 15. SQL_DATETIME_SUB long => unused
1528 // => empty
1529 // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of
1530 // bytes in the column
1531 // => pg_type.typlen
1532 // 17. ORDINAL_POSITION int => index of column in table (starting at 1)
1533 // pg_attribute.attnum
1534 // 18. IS_NULLABLE string => "NO" means column definitely does not allow
1535 // NULL values; "YES" means the column might
1536 // allow NULL values. An empty string means
1537 // nobody knows.
1538 // => pg_attribute.attnotnull
1540 Reference< XPreparedStatement > statement = m_origin->prepareStatement(
1541 "SELECT pg_namespace.nspname, " // 1
1542 "pg_class.relname, " // 2
1543 "pg_attribute.attname, " // 3
1544 "pg_type.typname, " // 4
1545 "pg_attribute.atttypmod, " // 5
1546 "pg_attribute.attnotnull, " // 6
1547 "pg_type.typdefault, " // 7
1548 "pg_type.typtype, " // 8
1549 "pg_attrdef.adsrc, " // 9
1550 "pg_description.description, " // 10
1551 "pg_type.typbasetype, " // 11
1552 "pg_attribute.attnum " // 12
1553 "FROM pg_class, "
1554 "pg_attribute LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum "
1555 "LEFT JOIN pg_description ON pg_attribute.attrelid = pg_description.objoid AND pg_attribute.attnum=pg_description.objsubid,"
1556 " pg_type, pg_namespace "
1557 "WHERE pg_attribute.attrelid = pg_class.oid "
1558 "AND pg_attribute.atttypid = pg_type.oid "
1559 "AND pg_class.relnamespace = pg_namespace.oid "
1560 "AND NOT pg_attribute.attisdropped "
1561 "AND pg_namespace.nspname LIKE ? "
1562 "AND pg_class.relname LIKE ? "
1563 "AND pg_attribute.attname LIKE ? "
1564 "ORDER BY pg_namespace.nspname, pg_class.relname, pg_attribute.attnum"
1567 Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
1568 parameters->setString( 1 , schemaPattern );
1569 parameters->setString( 2 , tableNamePattern );
1570 parameters->setString( 3 , columnNamePattern );
1572 Reference< XResultSet > rs = statement->executeQuery();
1573 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1574 SequenceAnyVector vec;
1576 Oid2DatabaseTypeDescriptionMap domainMap;
1577 Reference< XStatement > domainTypeStmt = m_origin->createStatement();
1578 columnMetaData2DatabaseTypeDescription( domainMap, rs, domainTypeStmt );
1580 sal_uInt32 colNum(0);
1581 OUString sSchema( "#invalid#" );
1582 OUString sTable( "#invalid#" );
1584 while( rs->next() )
1586 if( m_pSettings->showSystemColumns || ! isSystemColumn( xRow->getShort( 12 ) ) )
1588 OUString sNewSchema( xRow->getString(1) );
1589 OUString sNewTable( xRow->getString(2) );
1590 if ( sNewSchema != sSchema || sNewTable != sTable )
1592 colNum = 1;
1593 sSchema = sNewSchema;
1594 sTable = sNewTable;
1596 else
1597 ++colNum;
1598 sal_Int32 precision, scale, type;
1599 Sequence< Any > row( 18 );
1600 row[0] <<= m_pSettings->catalog;
1601 row[1] <<= sNewSchema;
1602 row[2] <<= sNewTable;
1603 row[3] <<= xRow->getString(3);
1604 if( xRow->getString(8) == "d" )
1606 DatabaseTypeDescription desc( domainMap[xRow->getInt(11)] );
1607 type = typeNameToDataType( desc.typeName, desc.typeType );
1609 else
1611 type = typeNameToDataType( xRow->getString(4), xRow->getString(8) );
1613 extractPrecisionAndScale( type, xRow->getInt(5) , &precision, &scale );
1614 row[4] <<= type;
1615 row[5] <<= xRow->getString(4);
1616 row[6] <<= precision;
1617 // row[7] BUFFER_LENGTH not used
1618 row[8] <<= scale;
1619 // row[9] RADIX TODO
1620 if( xRow->getBoolean( 6 ) && ! isSystemColumn(xRow->getInt( 12 )) )
1622 row[10] <<= OUString::number(com::sun::star::sdbc::ColumnValue::NO_NULLS);
1623 row[17] <<= statics.NO;
1625 else
1627 row[10] <<= OUString::number(com::sun::star::sdbc::ColumnValue::NULLABLE);
1628 row[17] <<= statics.YES;
1631 row[11] <<= xRow->getString( 10 ); // comment
1632 row[12] <<= xRow->getString( 9 ); // COLUMN_DEF = pg_type.typdefault
1633 // row[13] SQL_DATA_TYPE not used
1634 // row[14] SQL_DATETIME_SUB not used
1635 row[15] <<= precision;
1636 row[16] <<= colNum ;
1638 vec.push_back( row );
1641 Reference< XCloseable > closeable( statement, UNO_QUERY );
1642 if( closeable.is() )
1643 closeable->close();
1645 return new SequenceResultSet(
1646 m_refMutex, *this, statics.columnRowNames, sequence_of_vector(vec), m_pSettings->tc );
1649 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getColumnPrivileges(
1650 const ::com::sun::star::uno::Any& catalog,
1651 const OUString& schema,
1652 const OUString& table,
1653 const OUString& columnNamePattern ) throw (SQLException, RuntimeException, std::exception)
1655 (void) catalog;
1657 MutexGuard guard( m_refMutex->mutex );
1658 checkClosed();
1660 if( isLog( m_pSettings, LogLevel::INFO ) )
1662 OUStringBuffer buf( 128 );
1663 buf.appendAscii( "DatabaseMetaData::getColumnPrivileges got called with " );
1664 buf.append( schema );
1665 buf.appendAscii( "." );
1666 buf.append( table );
1667 buf.appendAscii( "." );
1668 buf.append( columnNamePattern );
1669 log( m_pSettings, LogLevel::INFO, buf.makeStringAndClear() );
1672 Reference< XParameters > parameters( m_getColumnPrivs_stmt, UNO_QUERY_THROW );
1673 parameters->setString( 1 , schema );
1674 parameters->setString( 2 , table );
1675 parameters->setString( 3 , columnNamePattern );
1677 Reference< XResultSet > rs = m_getColumnPrivs_stmt->executeQuery();
1679 return rs;
1682 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getTablePrivileges(
1683 const ::com::sun::star::uno::Any& catalog,
1684 const OUString& schemaPattern,
1685 const OUString& tableNamePattern ) throw (SQLException, RuntimeException, std::exception)
1687 (void) catalog;
1688 MutexGuard guard( m_refMutex->mutex );
1689 checkClosed();
1691 if( isLog( m_pSettings, LogLevel::INFO ) )
1693 OUStringBuffer buf( 128 );
1694 buf.appendAscii( "DatabaseMetaData::getTablePrivileges got called with " );
1695 buf.append( schemaPattern );
1696 buf.appendAscii( "." );
1697 buf.append( tableNamePattern );
1698 log( m_pSettings, LogLevel::INFO, buf.makeStringAndClear() );
1701 Reference< XParameters > parameters( m_getTablePrivs_stmt, UNO_QUERY_THROW );
1702 parameters->setString( 1 , schemaPattern );
1703 parameters->setString( 2 , tableNamePattern );
1705 Reference< XResultSet > rs = m_getTablePrivs_stmt->executeQuery();
1707 return rs;
1710 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getBestRowIdentifier(
1711 const ::com::sun::star::uno::Any& catalog,
1712 const OUString& schema,
1713 const OUString& table,
1714 sal_Int32 scope,
1715 sal_Bool nullable ) throw (SQLException, RuntimeException, std::exception)
1717 (void) catalog; (void) schema; (void) table; (void) scope; (void) nullable;
1718 //LEM TODO: implement! See JDBC driver
1719 MutexGuard guard( m_refMutex->mutex );
1720 checkClosed();
1721 return new SequenceResultSet(
1722 m_refMutex, *this, Sequence< OUString >(), Sequence< Sequence< Any > > (), m_pSettings->tc );
1725 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getVersionColumns(
1726 const ::com::sun::star::uno::Any& catalog,
1727 const OUString& schema,
1728 const OUString& table ) throw (SQLException, RuntimeException, std::exception)
1730 (void) catalog; (void) schema; (void) table;
1731 //LEM TODO: implement! See JDBC driver
1732 MutexGuard guard( m_refMutex->mutex );
1733 checkClosed();
1734 return new SequenceResultSet(
1735 m_refMutex, *this, Sequence< OUString >(), Sequence< Sequence< Any > > (), m_pSettings->tc );
1738 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getPrimaryKeys(
1739 const ::com::sun::star::uno::Any& catalog,
1740 const OUString& schema,
1741 const OUString& table ) throw (SQLException, RuntimeException, std::exception)
1743 (void) catalog;
1744 //LEM TODO: review
1745 MutexGuard guard( m_refMutex->mutex );
1746 checkClosed();
1748 // 1. TABLE_CAT string =&gt; table catalog (may be NULL )
1749 // 2. TABLE_SCHEM string =&gt; table schema (may be NULL )
1750 // 3. TABLE_NAME string =&gt; table name
1751 // 4. COLUMN_NAME string =&gt; column name
1752 // 5. KEY_SEQ short =&gt; sequence number within primary key
1753 // 6. PK_NAME string =&gt; primary key name (may be NULL )
1755 if( isLog( m_pSettings, LogLevel::INFO ) )
1757 OUStringBuffer buf( 128 );
1758 buf.appendAscii( "DatabaseMetaData::getPrimaryKeys got called with " );
1759 buf.append( schema );
1760 buf.appendAscii( "." );
1761 buf.append( table );
1762 log( m_pSettings, LogLevel::INFO, buf.makeStringAndClear() );
1765 Reference< XPreparedStatement > statement = m_origin->prepareStatement(
1766 "SELECT nmsp.nspname, "
1767 "cl.relname, "
1768 "con.conkey, "
1769 "con.conname, "
1770 "con.conrelid "
1771 "FROM pg_constraint as con,pg_class as cl, pg_namespace as nmsp "
1772 "WHERE con.connamespace = nmsp.oid AND con.conrelid = cl.oid AND con.contype = 'p' "
1773 "AND nmsp.nspname LIKE ? AND cl.relname LIKE ?" );
1775 Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
1776 parameters->setString( 1 , schema );
1777 parameters->setString( 2 , table );
1779 Reference< XResultSet > rs = statement->executeQuery();
1780 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1781 SequenceAnyVector vec;
1783 while( rs->next() )
1785 Sequence< Any > row( 6 );
1786 row[0] <<= m_pSettings->catalog;
1787 row[1] <<= xRow->getString(1);
1788 row[2] <<= xRow->getString(2);
1789 OUString array = xRow->getString(3);
1790 row[4] <<= xRow->getString(5); // the relid
1791 row[5] <<= xRow->getString(4);
1793 int i = 0;
1794 // now retrieve the columns information
1795 // unfortunately, postgresql does not allow array of variable size in
1796 // WHERE clauses (in the default installation), so we have to choose
1797 // this expensive and somewhat ugly way
1798 // annotation: postgresql shouldn't have chosen an array here, instead they
1799 // should have multiple rows per table
1800 // LEM: to transform an array into several rows, see unnest;
1801 // it is as simple as "SELECT foo, bar, unnest(qux) FROM ..."
1802 // where qux is the column that contains an array.
1803 while( array[i] && '}' != array[i] )
1805 i++;
1806 int start = i;
1807 while( array[i] && array[i] != '}' && array[i] != ',' ) i++;
1808 row[3] <<= array.copy(start, i - start );
1809 vec.push_back( row );
1814 Reference< XCloseable > closeable( statement, UNO_QUERY );
1815 if( closeable.is() )
1816 closeable->close();
1820 SequenceAnyVector::iterator ii = vec.begin();
1821 OUString lastTableOid;
1822 sal_Int32 index = 0;
1823 Sequence< Sequence< Any > > ret( vec.size() );
1824 int elements = 0;
1825 for( ; ii != vec.end() ; ++ ii )
1828 Sequence< Any > row = *ii;
1829 OUString tableOid;
1830 OUString attnum;
1832 row[4] >>= tableOid;
1833 row[3] >>= attnum;
1834 statement = m_origin->prepareStatement(
1835 "SELECT att.attname FROM "
1836 "pg_attribute AS att, pg_class AS cl WHERE "
1837 "att.attrelid = ? AND att.attnum = ?" );
1839 parameters = Reference< XParameters >( statement, UNO_QUERY_THROW );
1840 parameters->setString( 1 , tableOid );
1841 parameters->setString( 2 , attnum );
1843 rs = statement->executeQuery();
1844 xRow = Reference< XRow >( rs, UNO_QUERY_THROW );
1845 if( rs->next() )
1847 // column name
1848 row[3] <<= xRow->getString( 1 );
1849 if( tableOid != lastTableOid )
1850 index = 1;
1851 lastTableOid = tableOid;
1852 row[4] <<= OUString::number( index );
1853 index ++;
1856 Reference< XCloseable > closeable( statement, UNO_QUERY );
1857 if( closeable.is() )
1858 closeable->close();
1860 ret[elements] = row;
1861 elements ++;
1863 return new SequenceResultSet(
1864 m_refMutex, *this, getStatics().primaryKeyNames, ret , m_pSettings->tc );
1867 // Copied / adapted / simplified from JDBC driver
1868 #define SQL_CASE_KEYRULE " WHEN 'c' THEN " STRINGIFY(KEYRULE_CASCADE) \
1869 " WHEN 'n' THEN " STRINGIFY(KEYRULE_SET_NULL) \
1870 " WHEN 'd' THEN " STRINGIFY(KEYRULE_SET_DEFAULT) \
1871 " WHEN 'r' THEN " STRINGIFY(KEYRULE_RESTRICT) \
1872 " WHEN 'a' THEN " STRINGIFY(KEYRULE_NO_ACTION) \
1873 " ELSE NULL "
1875 #define SQL_GET_REFERENCES \
1876 "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) " \
1877 "SELECT NULL::text AS PKTABLE_CAT, pkn.nspname AS PKTABLE_SCHEM, pkc.relname AS PKTABLE_NAME, pka.attname AS PKCOLUMN_NAME, " \
1878 " NULL::text AS FKTABLE_CAT, fkn.nspname AS FKTABLE_SCHEM, fkc.relname AS FKTABLE_NAME, fka.attname AS FKCOLUMN_NAME, " \
1879 " con.conkeyseq AS KEY_SEQ, " \
1880 " CASE con.confupdtype " \
1881 SQL_CASE_KEYRULE \
1882 " END AS UPDATE_RULE, " \
1883 " CASE con.confdeltype " \
1884 SQL_CASE_KEYRULE \
1885 " END AS DELETE_RULE, " \
1886 " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \
1887 " CASE " \
1888 " WHEN con.condeferrable AND con.condeferred THEN " STRINGIFY(DEFERRABILITY_INITIALLY_DEFERRED) \
1889 " WHEN con.condeferrable THEN " STRINGIFY(DEFERRABILITY_INITIALLY_IMMEDIATE) \
1890 " ELSE " STRINGIFY(DEFERRABILITY_NONE) \
1891 " END AS DEFERRABILITY " \
1892 "FROM " \
1893 " pg_catalog.pg_namespace pkn, pg_catalog.pg_class pkc, pg_catalog.pg_attribute pka, " \
1894 " pg_catalog.pg_namespace fkn, pg_catalog.pg_class fkc, pg_catalog.pg_attribute fka, " \
1895 " con, pg_catalog.pg_depend dep, pg_catalog.pg_class pkic " \
1896 "WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey AND con.confrelid = pkc.oid " \
1897 " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey AND con.conrelid = fkc.oid " \
1898 " 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 "
1900 #define SQL_GET_REFERENCES_PSCHEMA " AND pkn.nspname = ? "
1901 #define SQL_GET_REFERENCES_PTABLE " AND pkc.relname = ? "
1902 #define SQL_GET_REFERENCES_FSCHEMA " AND fkn.nspname = ? "
1903 #define SQL_GET_REFERENCES_FTABLE " AND fkc.relname = ? "
1904 #define SQL_GET_REFERENCES_ORDER_SOME_PTABLE "ORDER BY fkn.nspname, fkc.relname, conkeyseq"
1905 #define SQL_GET_REFERENCES_ORDER_NO_PTABLE "ORDER BY pkn.nspname, pkc.relname, conkeyseq"
1907 #define SQL_GET_REFERENCES_NONE_NONE_NONE_NONE \
1908 SQL_GET_REFERENCES \
1909 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1911 #define SQL_GET_REFERENCES_SOME_NONE_NONE_NONE \
1912 SQL_GET_REFERENCES \
1913 SQL_GET_REFERENCES_PSCHEMA \
1914 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1916 #define SQL_GET_REFERENCES_NONE_SOME_NONE_NONE \
1917 SQL_GET_REFERENCES \
1918 SQL_GET_REFERENCES_PTABLE \
1919 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1921 #define SQL_GET_REFERENCES_SOME_SOME_NONE_NONE \
1922 SQL_GET_REFERENCES \
1923 SQL_GET_REFERENCES_PSCHEMA \
1924 SQL_GET_REFERENCES_PTABLE \
1925 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1927 #define SQL_GET_REFERENCES_NONE_NONE_SOME_NONE \
1928 SQL_GET_REFERENCES \
1929 SQL_GET_REFERENCES_FSCHEMA \
1930 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1932 #define SQL_GET_REFERENCES_NONE_NONE_NONE_SOME \
1933 SQL_GET_REFERENCES \
1934 SQL_GET_REFERENCES_FTABLE \
1935 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1937 #define SQL_GET_REFERENCES_NONE_NONE_SOME_SOME \
1938 SQL_GET_REFERENCES \
1939 SQL_GET_REFERENCES_FSCHEMA \
1940 SQL_GET_REFERENCES_FTABLE \
1941 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1943 #define SQL_GET_REFERENCES_SOME_NONE_SOME_NONE \
1944 SQL_GET_REFERENCES \
1945 SQL_GET_REFERENCES_PSCHEMA \
1946 SQL_GET_REFERENCES_FSCHEMA \
1947 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1949 #define SQL_GET_REFERENCES_SOME_NONE_NONE_SOME \
1950 SQL_GET_REFERENCES \
1951 SQL_GET_REFERENCES_PSCHEMA \
1952 SQL_GET_REFERENCES_FTABLE \
1953 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1955 #define SQL_GET_REFERENCES_SOME_NONE_SOME_SOME \
1956 SQL_GET_REFERENCES \
1957 SQL_GET_REFERENCES_PSCHEMA \
1958 SQL_GET_REFERENCES_FSCHEMA \
1959 SQL_GET_REFERENCES_FTABLE \
1960 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1962 #define SQL_GET_REFERENCES_NONE_SOME_SOME_NONE \
1963 SQL_GET_REFERENCES \
1964 SQL_GET_REFERENCES_PTABLE \
1965 SQL_GET_REFERENCES_FSCHEMA \
1966 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1968 #define SQL_GET_REFERENCES_NONE_SOME_NONE_SOME \
1969 SQL_GET_REFERENCES \
1970 SQL_GET_REFERENCES_PTABLE \
1971 SQL_GET_REFERENCES_FTABLE \
1972 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1974 #define SQL_GET_REFERENCES_NONE_SOME_SOME_SOME \
1975 SQL_GET_REFERENCES \
1976 SQL_GET_REFERENCES_PTABLE \
1977 SQL_GET_REFERENCES_FSCHEMA \
1978 SQL_GET_REFERENCES_FTABLE \
1979 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1981 #define SQL_GET_REFERENCES_SOME_SOME_SOME_NONE \
1982 SQL_GET_REFERENCES \
1983 SQL_GET_REFERENCES_PSCHEMA \
1984 SQL_GET_REFERENCES_PTABLE \
1985 SQL_GET_REFERENCES_FSCHEMA \
1986 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1988 #define SQL_GET_REFERENCES_SOME_SOME_NONE_SOME \
1989 SQL_GET_REFERENCES \
1990 SQL_GET_REFERENCES_PSCHEMA \
1991 SQL_GET_REFERENCES_PTABLE \
1992 SQL_GET_REFERENCES_FTABLE \
1993 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1995 #define SQL_GET_REFERENCES_SOME_SOME_SOME_SOME \
1996 SQL_GET_REFERENCES \
1997 SQL_GET_REFERENCES_PSCHEMA \
1998 SQL_GET_REFERENCES_PTABLE \
1999 SQL_GET_REFERENCES_FSCHEMA \
2000 SQL_GET_REFERENCES_FTABLE \
2001 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
2003 void DatabaseMetaData::init_getReferences_stmt ()
2005 m_getReferences_stmt[0] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_NONE);
2006 m_getReferences_stmt[1] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_NONE);
2007 m_getReferences_stmt[2] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_NONE);
2008 m_getReferences_stmt[3] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_NONE);
2009 m_getReferences_stmt[4] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_NONE);
2010 m_getReferences_stmt[5] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_NONE);
2011 m_getReferences_stmt[6] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_NONE);
2012 m_getReferences_stmt[7] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_NONE);
2013 m_getReferences_stmt[8] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_SOME);
2014 m_getReferences_stmt[9] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_SOME);
2015 m_getReferences_stmt[10] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_SOME);
2016 m_getReferences_stmt[11] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_SOME);
2017 m_getReferences_stmt[12] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_SOME);
2018 m_getReferences_stmt[13] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_SOME);
2019 m_getReferences_stmt[14] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_SOME);
2020 m_getReferences_stmt[15] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_SOME);
2023 void DatabaseMetaData::init_getPrivs_stmt ()
2025 OUStringBuffer sSQL(300);
2026 sSQL.append(
2027 " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable "
2028 " FROM ("
2029 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name,"
2030 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
2031 " FROM information_schema.table_privileges");
2032 if ( PQserverVersion( m_pSettings->pConnection ) < 90200 )
2033 // information_schema.table_privileges does not fill in default ACLs when no ACL
2034 // assume default ACL is "owner has all privileges" and add it
2035 sSQL.append(
2036 " UNION "
2037 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME,"
2038 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
2039 " FROM pg_catalog.pg_class c,"
2040 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) p (privilege),"
2041 " pg_catalog.pg_roles ro,"
2042 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
2043 " UNION ALL"
2044 " VALUES (0::oid, 'PUBLIC')"
2045 " ) AS rg (oid, rolname),"
2046 " pg_catalog.pg_namespace pn"
2047 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
2048 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid");
2049 sSQL.append(
2050 " ) dp,"
2051 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
2052 " WHERE table_schem LIKE ? AND table_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
2053 " ORDER BY table_schem, table_name, privilege" );
2055 m_getTablePrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() );
2057 sSQL.append(
2058 " 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 ("
2059 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name, column_name,"
2060 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
2061 " FROM information_schema.column_privileges");
2062 if ( PQserverVersion( m_pSettings->pConnection ) < 90200 )
2063 // information_schema.table_privileges does not fill in default ACLs when no ACL
2064 // assume default ACL is "owner has all privileges" and add it
2065 sSQL.append(
2066 " UNION "
2067 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, a.attname AS column_name,"
2068 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
2069 " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a,"
2070 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) p (privilege),"
2071 " pg_catalog.pg_roles ro,"
2072 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
2073 " UNION ALL"
2074 " VALUES (0::oid, 'PUBLIC')"
2075 " ) AS rg (oid, rolname),"
2076 " pg_catalog.pg_namespace pn"
2077 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
2078 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid AND a.attrelid = c.oid AND a.attnum > 0");
2079 sSQL.append(
2080 " ) dp,"
2081 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
2082 " WHERE table_schem = ? AND table_name = ? AND column_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
2083 " ORDER BY column_name, privilege" );
2085 m_getColumnPrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() );
2088 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getImportedExportedKeys(
2089 const Any& /* primaryCatalog */,
2090 const OUString& primarySchema,
2091 const OUString& primaryTable,
2092 const Any& /* foreignCatalog */,
2093 const OUString& foreignSchema,
2094 const OUString& foreignTable ) throw (SQLException, RuntimeException)
2096 unsigned int i = 0;
2097 if ( ! primarySchema.isEmpty() )
2098 i |= 0x01;
2099 if ( ! primaryTable.isEmpty() )
2100 i |= 0x02;
2101 if ( ! foreignSchema.isEmpty() )
2102 i |= 0x04;
2103 if ( ! foreignTable.isEmpty() )
2104 i |= 0x08;
2106 Reference< XPreparedStatement > stmt = m_getReferences_stmt[i];
2107 Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
2109 unsigned int j = 1;
2110 if ( i & 0x01 )
2111 param->setString( j++, primarySchema );
2112 if ( i & 0x02 )
2113 param->setString( j++, primaryTable );
2114 if ( i & 0x04 )
2115 param->setString( j++, foreignSchema );
2116 if ( i & 0x08 )
2117 param->setString( j++, foreignTable );
2119 Reference< XResultSet > rs = stmt->executeQuery();
2121 return rs;
2125 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getImportedKeys(
2126 const ::com::sun::star::uno::Any& catalog,
2127 const OUString& schema,
2128 const OUString& table ) throw (SQLException, RuntimeException, std::exception)
2130 return getImportedExportedKeys(Any(), OUString(), OUString(), catalog, schema, table);
2133 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getExportedKeys(
2134 const ::com::sun::star::uno::Any& catalog,
2135 const OUString& schema,
2136 const OUString& table ) throw (SQLException, RuntimeException, std::exception)
2138 return getImportedExportedKeys(catalog, schema, table, Any(), OUString(), OUString());
2141 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getCrossReference(
2142 const ::com::sun::star::uno::Any& primaryCatalog,
2143 const OUString& primarySchema,
2144 const OUString& primaryTable,
2145 const ::com::sun::star::uno::Any& foreignCatalog,
2146 const OUString& foreignSchema,
2147 const OUString& foreignTable ) throw (SQLException, RuntimeException, std::exception)
2149 return getImportedExportedKeys( primaryCatalog, primarySchema, primaryTable, foreignCatalog, foreignSchema, foreignTable );
2153 struct TypeInfoByDataTypeSorter
2155 bool operator () ( const Sequence< Any > & a, const Sequence< Any > & b )
2157 OUString valueA;
2158 OUString valueB;
2159 a[1 /*DATA_TYPE*/] >>= valueA;
2160 b[1 /*DATA_TYPE*/] >>= valueB;
2161 if( valueB.toInt32() == valueA.toInt32() )
2163 OUString nameA;
2164 OUString nameB;
2165 a[0 /*TYPE_NAME*/] >>= nameA;
2166 b[0 /*TYPE_NAME*/] >>= nameB;
2167 if( nameA.startsWith( "int4" ) )
2168 return true;
2169 if( nameB.startsWith( "int4" ) )
2170 return false;
2171 return nameA.compareTo( nameB ) < 0;
2174 return valueA.toInt32() < valueB.toInt32();
2175 // sal_Int32 valueA;
2176 // sal_Int32 valueB;
2177 // a[1 /*DATA_TYPE*/] >>= valueA;
2178 // b[1 /*DATA_TYPE*/] >>= valueB;
2179 // if( valueB == valueA )
2180 // {
2181 // OUString nameA;
2182 // OUString nameB;
2183 // a[0 /*TYPE_NAME*/] >>= nameA;
2184 // b[0 /*TYPE_NAME*/] >>= nameB;
2185 // return nameA.compareTo( nameB ) < 0;
2186 // }
2188 // return valueA < valueB;
2192 static sal_Int32 calcSearchable( sal_Int32 dataType )
2194 sal_Int32 ret = com::sun::star::sdbc::ColumnSearch::FULL;
2195 if( com::sun::star::sdbc::DataType::BINARY == dataType ||
2196 com::sun::star::sdbc::DataType::VARBINARY == dataType ||
2197 com::sun::star::sdbc::DataType::LONGVARBINARY == dataType )
2198 ret = com::sun::star::sdbc::ColumnSearch::NONE;
2200 return ret;
2203 static sal_Int32 getMaxScale( sal_Int32 dataType )
2205 // LEM TODO: review, see where used, see JDBC, ...
2206 sal_Int32 ret = 0;
2207 if( dataType == com::sun::star::sdbc::DataType::NUMERIC )
2208 ret = 1000; // see pg-docs DataType/numeric
2209 // else if( dataType == DataType::DOUBLE )
2210 // ret = 308;
2211 // else if( dataType == DataType::FLOAT )
2212 // ret =
2213 return ret;
2217 struct RawType
2219 const char * typeName;
2220 const char * createParam;
2221 sal_Int32 sdbcType;
2222 sal_Int32 precision;
2223 sal_Int32 nullable;
2224 bool caseSensitive;
2225 sal_Int32 searchable;
2228 static void pgTypeInfo2ResultSet(
2229 SequenceAnyVector &vec,
2230 const Reference< XResultSet > &rs )
2232 static const sal_Int32 TYPE_NAME = 0; // string Type name
2233 static const sal_Int32 DATA_TYPE = 1; // short SQL data type from java.sql.Types
2234 static const sal_Int32 PRECISION = 2; // long maximum precision
2235 static const sal_Int32 CREATE_PARAMS = 5; // string => parameters used in creating the type (may be NULL )
2236 static const sal_Int32 NULLABLE = 6; // short ==> can you use NULL for this type?
2237 // - NO_NULLS - does not allow NULL values
2238 // - NULLABLE - allows NULL values
2239 // - NULLABLE_UNKNOWN - nullability unknown
2241 static const sal_Int32 CASE_SENSITIVE = 7; // boolean==> is it case sensitive
2242 static const sal_Int32 SEARCHABLE = 8; // short ==>; can you use
2243 // "WHERE" based on this type:
2244 // - NONE - No support
2245 // - CHAR - Only supported with WHERE .. LIKE
2246 // - BASIC - Supported except for WHERE .. LIKE
2247 // - FULL - Supported for all WHERE ..
2248 static const sal_Int32 UNSIGNED_ATTRIBUTE = 9; // boolean ==> is it unsigned?
2249 static const sal_Int32 FIXED_PREC_SCALE = 10; // boolean ==> can it be a money value?
2250 static const sal_Int32 AUTO_INCREMENT = 11; // boolean ==> can it be used for
2251 // an auto-increment value?
2252 static const sal_Int32 MINIMUM_SCALE = 13; // short ==> minimum scale supported
2253 static const sal_Int32 MAXIMUM_SCALE = 14; // short ==> maximum scale supported
2254 static const sal_Int32 NUM_PREC_RADIX = 17; // long ==> usually 2 or 10
2256 /* not filled so far
2257 3. LITERAL_PREFIX string ==> prefix used to quote a literal
2258 (may be <NULL/>)
2259 4, LITERAL_SUFFIX string ==> suffix used to quote a literal
2260 (may be <NULL/>)
2261 5. CREATE_PARAMS string ==> parameters used in creating thw type (may be <NULL/>)
2262 12. LOCAL_TYPE_NAME string ==> localized version of type name (may be <NULL/>)
2263 15, SQL_DATA_TYPE long ==> unused
2264 16. SQL_DATETIME_SUB long ==> unused
2266 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
2267 while( rs->next() )
2269 Sequence< Any > row(18);
2271 sal_Int32 dataType =typeNameToDataType(xRow->getString(5),xRow->getString(2));
2272 sal_Int32 precision = xRow->getString(3).toInt32();
2274 if( dataType == com::sun::star::sdbc::DataType::CHAR ||
2275 ( dataType == com::sun::star::sdbc::DataType::VARCHAR &&
2276 xRow->getString(TYPE_NAME+1).equalsIgnoreAsciiCase("varchar") ) )
2278 // reflect varchar as varchar with upper limit !
2279 //NOTE: the sql spec requires varchar to have an upper limit, however
2280 // in postgresql the upper limit is optional, no limit means unlimited
2281 // length (=1GB).
2282 precision = 0x40000000; // about 1 GB, see character type docs in postgresql
2283 row[CREATE_PARAMS] <<= OUString("length");
2285 else if( dataType == com::sun::star::sdbc::DataType::NUMERIC )
2287 precision = 1000;
2288 row[CREATE_PARAMS] <<= OUString("length, scale");
2291 row[TYPE_NAME] <<= xRow->getString(1);
2292 row[DATA_TYPE] <<= OUString::number(dataType);
2293 row[PRECISION] <<= OUString::number( precision );
2294 sal_Int32 nullable = xRow->getBoolean(4) ?
2295 com::sun::star::sdbc::ColumnValue::NO_NULLS :
2296 com::sun::star::sdbc::ColumnValue::NULLABLE;
2297 row[NULLABLE] <<= OUString::number(nullable);
2298 row[CASE_SENSITIVE] <<= OUString::number(1);
2299 row[SEARCHABLE] <<= OUString::number( calcSearchable( dataType ) );
2300 row[UNSIGNED_ATTRIBUTE] <<= OUString("0");
2301 if( com::sun::star::sdbc::DataType::INTEGER == dataType ||
2302 com::sun::star::sdbc::DataType::BIGINT == dataType )
2303 row[AUTO_INCREMENT] <<= OUString("1"); // TODO
2304 else
2305 row[AUTO_INCREMENT] <<= OUString("0"); // TODO
2306 row[MINIMUM_SCALE] <<= OUString("0"); // TODO: what is this ?
2307 row[MAXIMUM_SCALE] <<= OUString::number( getMaxScale( dataType ) );
2308 row[NUM_PREC_RADIX] <<= OUString("10"); // TODO: what is this ?
2309 (void)FIXED_PREC_SCALE;
2310 vec.push_back( row );
2316 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getTypeInfo( )
2317 throw (SQLException, RuntimeException, std::exception)
2319 // Note: Indexes start at 0 (in the API doc, they start at 1)
2320 MutexGuard guard( m_refMutex->mutex );
2321 checkClosed();
2323 if( isLog( m_pSettings, LogLevel::INFO ) )
2325 log( m_pSettings, LogLevel::INFO, "DatabaseMetaData::getTypeInfo() got called" );
2328 Reference< XStatement > statement = m_origin->createStatement();
2329 Reference< XResultSet > rs = statement->executeQuery(
2330 "SELECT pg_type.typname AS typname," //1
2331 "pg_type.typtype AS typtype," //2
2332 "pg_type.typlen AS typlen," //3
2333 "pg_type.typnotnull AS typnotnull," //4
2334 "pg_type.typname AS typname " //5
2335 "FROM pg_type "
2336 "WHERE pg_type.typtype = 'b' "
2337 "OR pg_type.typtype = 'p'"
2340 SequenceAnyVector vec;
2341 pgTypeInfo2ResultSet( vec, rs );
2343 // check for domain types
2344 rs = statement->executeQuery(
2345 "SELECT t1.typname as typname,"
2346 "t2.typtype AS typtype,"
2347 "t2.typlen AS typlen,"
2348 "t2.typnotnull AS typnotnull,"
2349 "t2.typname as realtypname "
2350 "FROM pg_type as t1 LEFT JOIN pg_type AS t2 ON t1.typbasetype=t2.oid "
2351 "WHERE t1.typtype = 'd'" );
2352 pgTypeInfo2ResultSet( vec, rs );
2354 std::sort( vec.begin(), vec.end(), TypeInfoByDataTypeSorter() );
2356 return new SequenceResultSet(
2357 m_refMutex,
2358 *this,
2359 getStatics().typeinfoColumnNames,
2360 sequence_of_vector(vec),
2361 m_pSettings->tc,
2362 &( getStatics().typeInfoMetaData ));
2366 static sal_Int32 seqContains( const Sequence< sal_Int32 > &seq, sal_Int32 value )
2368 sal_Int32 ret = -1;
2369 for( int i = 0; i < seq.getLength(); i ++ )
2371 if( seq[i] == value )
2373 ret = i;
2374 break;
2377 return ret;
2380 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getIndexInfo(
2381 const ::com::sun::star::uno::Any& catalog,
2382 const OUString& schema,
2383 const OUString& table,
2384 sal_Bool unique,
2385 sal_Bool approximate ) throw (SQLException, RuntimeException, std::exception)
2387 (void) catalog; (void) approximate;
2388 //LEM TODO: review
2389 MutexGuard guard( m_refMutex->mutex );
2390 checkClosed();
2393 1. TABLE_CAT string -> table catalog (may be NULL )
2394 2. TABLE_SCHEM string -> table schema (may be NULL )
2395 3. TABLE_NAME string -> table name
2396 4. NON_UNIQUE boolean -> Can index values be non-unique?
2397 false when TYPE is tableIndexStatistic
2398 5. INDEX_QUALIFIER string -> index catalog (may be NULL );
2399 NULL when TYPE is tableIndexStatistic
2400 6. INDEX_NAME string -> index name; NULL when TYPE is tableIndexStatistic
2401 7. TYPE short -> index type:
2402 * 0 - this identifies table statistics that are returned
2403 in conjuction with a table's index descriptions
2404 * CLUSTERED - this is a clustered index
2405 * HASHED - this is a hashed index
2406 * OTHER - this is some other style of index
2407 8. ORDINAL_POSITION short -> column sequence number within index;
2408 zero when TYPE is tableIndexStatistic
2409 9. COLUMN_NAME string -> column name; NULL when TYPE is tableIndexStatistic
2410 10. ASC_OR_DESC string -> column sort sequence, "A"= ascending,
2411 "D" = descending, may be NULL if sort sequence
2412 is not supported; NULL when TYPE is tableIndexStatistic
2413 11. CARDINALITY long -> When TYPE is tableIndexStatistic, then this is
2414 the number of rows in the table; otherwise, it
2415 is the number of unique values in the index.
2416 12. PAGES long -> When TYPE is tableIndexStatisic then this is
2417 the number of pages used for the table, otherwise
2418 it is the number of pages used for the current index.
2419 13. FILTER_CONDITION string -> Filter condition, if any. (may be NULL )
2422 static const sal_Int32 C_SCHEMA = 1;
2423 static const sal_Int32 C_TABLENAME = 2;
2424 static const sal_Int32 C_INDEXNAME = 3;
2425 static const sal_Int32 C_IS_CLUSTERED = 4;
2426 static const sal_Int32 C_IS_UNIQUE = 5;
2427 static const sal_Int32 C_IS_PRIMARY = 6;
2428 static const sal_Int32 C_COLUMNS = 7;
2430 static const sal_Int32 R_TABLE_SCHEM = 1;
2431 static const sal_Int32 R_TABLE_NAME = 2;
2432 static const sal_Int32 R_NON_UNIQUE = 3;
2433 static const sal_Int32 R_INDEX_NAME = 5;
2434 static const sal_Int32 R_TYPE = 6;
2435 static const sal_Int32 R_ORDINAL_POSITION = 7;
2436 static const sal_Int32 R_COLUMN_NAME = 8;
2438 Reference< XPreparedStatement > stmt = m_origin->prepareStatement(
2439 "SELECT nspname, " // 1
2440 "pg_class.relname, " // 2
2441 "class2.relname, " // 3
2442 "indisclustered, " // 4
2443 "indisunique, " // 5
2444 "indisprimary, " // 6
2445 "indkey " // 7
2446 "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid "
2447 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
2448 "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid "
2449 "WHERE nspname = ? AND pg_class.relname = ?" );
2451 Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
2452 param->setString( 1, schema );
2453 param->setString( 2, table );
2454 Reference< XResultSet > rs = stmt->executeQuery();
2455 Reference< XRow > xRow ( rs, UNO_QUERY_THROW );
2457 SequenceAnyVector vec;
2458 while( rs->next() )
2460 Sequence< sal_Int32 > columns = parseIntArray( xRow->getString(C_COLUMNS) );
2461 Reference< XPreparedStatement > columnsStmt = m_origin->prepareStatement(
2462 "SELECT attnum, attname "
2463 "FROM pg_attribute "
2464 " INNER JOIN pg_class ON attrelid = pg_class.oid "
2465 " INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid "
2466 " WHERE pg_namespace.nspname=? AND pg_class.relname=?" );
2467 Reference< XParameters > paramColumn ( columnsStmt, UNO_QUERY_THROW );
2468 OUString currentSchema = xRow->getString( C_SCHEMA );
2469 OUString currentTable = xRow->getString( C_TABLENAME );
2470 OUString currentIndexName = xRow->getString( C_INDEXNAME );
2471 sal_Bool isNonUnique = ! xRow->getBoolean( C_IS_UNIQUE );
2472 bool isPrimary = xRow->getBoolean( C_IS_PRIMARY );
2473 (void)isPrimary;
2474 sal_Int32 indexType = xRow->getBoolean( C_IS_CLUSTERED ) ?
2475 com::sun::star::sdbc::IndexType::CLUSTERED :
2476 com::sun::star::sdbc::IndexType::HASHED;
2478 paramColumn->setString( C_SCHEMA, currentSchema );
2479 paramColumn->setString( C_TABLENAME, currentTable );
2481 Reference< XResultSet > rsColumn = columnsStmt->executeQuery();
2482 Reference< XRow > rowColumn( rsColumn, UNO_QUERY_THROW );
2483 while( rsColumn->next() )
2485 sal_Int32 pos = seqContains( columns, rowColumn->getInt( 1 ) );
2486 if( pos >= 0 && ( ! isNonUnique || ! unique ) )
2488 Sequence< Any > result( 13 );
2489 result[R_TABLE_SCHEM] = makeAny(currentSchema);
2490 result[R_TABLE_NAME] = makeAny(currentTable);
2491 result[R_INDEX_NAME] = makeAny(currentIndexName);
2492 result[R_NON_UNIQUE] =
2493 Any( &isNonUnique, getBooleanCppuType() );
2494 result[R_TYPE] = makeAny( indexType );
2495 result[R_COLUMN_NAME] = makeAny( rowColumn->getString(2) );
2496 sal_Int32 nPos = ((sal_Int32)pos+1); // MSVC++ nonsense
2497 result[R_ORDINAL_POSITION] = makeAny( nPos );
2498 vec.push_back( result );
2502 return new SequenceResultSet(
2503 m_refMutex, *this, getStatics().indexinfoColumnNames,
2504 sequence_of_vector(vec),
2505 m_pSettings->tc );
2508 sal_Bool DatabaseMetaData::supportsResultSetType( sal_Int32 setType )
2509 throw (SQLException, RuntimeException, std::exception)
2511 if ( setType == com::sun::star::sdbc::ResultSetType::SCROLL_SENSITIVE )
2512 return sal_False;
2513 else
2514 return sal_True;
2517 sal_Bool DatabaseMetaData::supportsResultSetConcurrency(
2518 sal_Int32 setType, sal_Int32 concurrency ) throw (SQLException, RuntimeException, std::exception)
2520 (void) concurrency;
2521 if ( ! supportsResultSetType( setType ) )
2522 return sal_False;
2523 else
2524 return sal_True;
2527 sal_Bool DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2529 return sal_True;
2532 sal_Bool DatabaseMetaData::ownDeletesAreVisible( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2534 return sal_True;
2537 sal_Bool DatabaseMetaData::ownInsertsAreVisible( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2539 return sal_True;
2542 sal_Bool DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2544 return sal_False;
2547 sal_Bool DatabaseMetaData::othersDeletesAreVisible( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2549 return sal_False;
2552 sal_Bool DatabaseMetaData::othersInsertsAreVisible( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2554 return sal_False;
2557 sal_Bool DatabaseMetaData::updatesAreDetected( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2559 return sal_False;
2562 sal_Bool DatabaseMetaData::deletesAreDetected( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2564 return sal_False;
2566 sal_Bool DatabaseMetaData::insertsAreDetected( sal_Int32 /* setType */ ) throw (SQLException, RuntimeException, std::exception)
2568 return sal_False;
2571 sal_Bool DatabaseMetaData::supportsBatchUpdates( ) throw (SQLException, RuntimeException, std::exception)
2573 return sal_True;
2576 ::com::sun::star::uno::Reference< XResultSet > DatabaseMetaData::getUDTs( const ::com::sun::star::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const ::com::sun::star::uno::Sequence< sal_Int32 >& types ) throw (SQLException, RuntimeException, std::exception)
2578 (void) catalog; (void) schemaPattern; (void) typeNamePattern; (void) types;
2579 //LEM TODO: implement! See JDBC driver
2580 MutexGuard guard( m_refMutex->mutex );
2581 checkClosed();
2582 return new SequenceResultSet(
2583 m_refMutex, *this, Sequence< OUString >(), Sequence< Sequence< Any > > (), m_pSettings->tc );
2586 ::com::sun::star::uno::Reference< com::sun::star::sdbc::XConnection > DatabaseMetaData::getConnection()
2587 throw (SQLException, RuntimeException, std::exception)
2589 return m_origin;
2593 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */