1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3 *
4 * Effective License of whole file:
5 *
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.
9 *
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.
14 *
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
19 *
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
21 *
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
24 *
25 * Copyright: 2000 by Sun Microsystems, Inc.
26 *
27 * Contributor(s): Joerg Budischewski
28 *
29 * All parts contributed on or after August 2011:
30 *
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/.
34 *
35 * Some portions were adapted from JDBC PostgreSQL driver:
36 *
37 * Copyright (c) 2004-2008, PostgreSQL Global Development Group
38 *
39 * Licence of original JDBC driver code:
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions are met:
43 *
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.
52 *
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.
64 *
65 ************************************************************************/
66
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"
73
74 #include <rtl/ustrbuf.hxx>
75
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>
86
87 using ::osl::MutexGuard;
88
89
90 using namespace com::sun::star::sdbc;
91
92 using com::sun::star::uno::Reference;
93 using com::sun::star::uno::Sequence;
94 using com::sun::star::uno::Any;
95 using com::sun::star::uno::UNO_QUERY;
96 using com::sun::star::uno::UNO_QUERY_THROW;
97
98 namespace pq_sdbc_driver
99 {
100 #define QUOTEME(X) #X
101 #define STRINGIFY(X) QUOTEME(X)
102
103 // These are pre-processor versions of KeyRule.idl declarations
104 // These are inherited from JDBC, and thus won't change anytime soon.
105 // Having them as pre-processor definitions allows to include them
106 // into compile-time strings (through STRINGIFY), which can be passed to ASCII_STR.
107 // That is without resorting to horrendous hacks in template meta-programming.
108 #define KEYRULE_CASCADE 0
109 #define KEYRULE_RESTRICT 1
110 #define KEYRULE_SET_NULL 2
111 #define KEYRULE_NO_ACTION 4
112 #define KEYRULE_SET_DEFAULT 4
113 // Ditto for Deferrability.idl
114 #define DEFERRABILITY_INITIALLY_DEFERRED 5
115 #define DEFERRABILITY_INITIALLY_IMMEDIATE 6
116 #define DEFERRABILITY_NONE 7
117
DatabaseMetaData(const::rtl::Reference<comphelper::RefCountedMutex> & refMutex,const css::uno::Reference<css::sdbc::XConnection> & origin,ConnectionSettings * pSettings)118 DatabaseMetaData::DatabaseMetaData(
119 const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
120 const css::uno::Reference< css::sdbc::XConnection > & origin,
121 ConnectionSettings *pSettings )
122 : m_xMutex( refMutex ),
123 m_pSettings( pSettings ),
124 m_origin( origin ),
125 m_getIntSetting_stmt ( m_origin->prepareStatement("SELECT setting FROM pg_catalog.pg_settings WHERE name=?") )
126 {
127 init_getReferences_stmt();
128 init_getPrivs_stmt();
129 }
130
allProceduresAreCallable()131 sal_Bool DatabaseMetaData::allProceduresAreCallable( )
132 {
133 // TODO
134 return false;
135 }
136
allTablesAreSelectable()137 sal_Bool DatabaseMetaData::allTablesAreSelectable( )
138 {
139 return true;
140 }
141
getURL()142 OUString DatabaseMetaData::getURL( )
143 {
144 // TODO
145 // LEM TODO: implement
146 return OUString();
147 }
148
getUserName()149 OUString DatabaseMetaData::getUserName( )
150 {
151 return m_pSettings->user;
152 }
153
isReadOnly()154 sal_Bool DatabaseMetaData::isReadOnly( )
155 {
156 return false;
157 }
158
159
nullsAreSortedHigh()160 sal_Bool DatabaseMetaData::nullsAreSortedHigh( )
161 {
162 // Whether NULL values are considered, for sorting purposes, LARGER than any other value.
163 // Specification: http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#nullsAreSortedHigh()
164 // PostgreSQL behaviour: http://www.postgresql.org/docs/9.1/static/queries-order.html
165 return true;
166 }
167
nullsAreSortedLow()168 sal_Bool DatabaseMetaData::nullsAreSortedLow( )
169 {
170 return ! nullsAreSortedHigh();
171 }
172
nullsAreSortedAtStart()173 sal_Bool DatabaseMetaData::nullsAreSortedAtStart( )
174 {
175 return false;
176 }
177
nullsAreSortedAtEnd()178 sal_Bool DatabaseMetaData::nullsAreSortedAtEnd( )
179 {
180 return false;
181 }
182
getDatabaseProductName()183 OUString DatabaseMetaData::getDatabaseProductName( )
184 {
185 return "PostgreSQL";
186 }
187
getDatabaseProductVersion()188 OUString DatabaseMetaData::getDatabaseProductVersion( )
189 {
190 return OUString::createFromAscii( PQparameterStatus( m_pSettings->pConnection, "server_version" ) );
191 }
getDriverName()192 OUString DatabaseMetaData::getDriverName( )
193 {
194 return "postgresql-sdbc";
195 }
196
getDriverVersion()197 OUString DatabaseMetaData::getDriverVersion( )
198 {
199 return PQ_SDBC_DRIVER_VERSION;
200 }
201
getDriverMajorVersion()202 sal_Int32 DatabaseMetaData::getDriverMajorVersion( )
203 {
204 return PQ_SDBC_MAJOR;
205 }
206
getDriverMinorVersion()207 sal_Int32 DatabaseMetaData::getDriverMinorVersion( )
208 {
209 return PQ_SDBC_MINOR;
210 }
211
usesLocalFiles()212 sal_Bool DatabaseMetaData::usesLocalFiles( )
213 {
214 // LEM TODO:
215 // http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/XDatabaseMetaData_Interface
216 // says "Returns true when the catalog name of the
217 // database should not appear in the DatasourceBrowser
218 // of OpenOffice.org API, otherwise false is returned."
219 // So, hmmm, think about it.
220 return false;
221 }
222
usesLocalFilePerTable()223 sal_Bool DatabaseMetaData::usesLocalFilePerTable( )
224 {
225 return false;
226 }
227
supportsMixedCaseIdentifiers()228 sal_Bool DatabaseMetaData::supportsMixedCaseIdentifiers( )
229 {
230 return false;
231 }
232
storesUpperCaseIdentifiers()233 sal_Bool DatabaseMetaData::storesUpperCaseIdentifiers( )
234 {
235 return false;
236 }
237
storesLowerCaseIdentifiers()238 sal_Bool DatabaseMetaData::storesLowerCaseIdentifiers( )
239 {
240 return true;
241 }
242
243
storesMixedCaseIdentifiers()244 sal_Bool DatabaseMetaData::storesMixedCaseIdentifiers( )
245 {
246 return false;
247 }
248
249
supportsMixedCaseQuotedIdentifiers()250 sal_Bool DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( )
251 {
252 return true;
253 }
254
storesUpperCaseQuotedIdentifiers()255 sal_Bool DatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
256 {
257 return false;
258 }
259
260
storesLowerCaseQuotedIdentifiers()261 sal_Bool DatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
262 {
263 return false;
264 }
265
266
storesMixedCaseQuotedIdentifiers()267 sal_Bool DatabaseMetaData::storesMixedCaseQuotedIdentifiers( )
268 {
269 return false;
270 }
271
272
getIdentifierQuoteString()273 OUString DatabaseMetaData::getIdentifierQuoteString( )
274 {
275 return "\"";
276 }
277
getSQLKeywords()278 OUString DatabaseMetaData::getSQLKeywords( )
279 {
280 // In Java 6, this is all keywords that are not SQL:2003
281 // In Java 2 v1.4 and as per LibreOffice SDK doc, this is all keywords that are not SQL92
282 // I understand this to mean "reserved keywords" only.
283 // See http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
284 // LEM TODO: consider using pg_get_keywords(), filter on catcode
285 return
286 "ANALYSE,"
287 "ANALYZE,"
288 "ARRAY," //SQL:1999
289 "ASYMMETRIC," //SQL:2003
290 "BINARY," //SQL:1999
291 "CONCURRENTLY,"
292 "CURRENT_CATALOG," //SQL:2008
293 "CURRENT_ROLE," //SQL:1999
294 "CURRENT_SCHEMA," //SQL:2008
295 "DO,"
296 "FREEZE,"
297 "ILIKE,"
298 "ISNULL,"
299 "LIMIT," //SQL:1999; non-reserved in SQL:2003
300 "LOCALTIME," //SQL:1999
301 "LOCALTIMESTAMP," //SQL:1999
302 "NOTNULL,"
303 "OFFSET," //SQL:2008
304 "OVER," //SQL:2003
305 "PLACING," //non-reserved in SQL:2003
306 "RETURNING," //non-reserved in SQL:2008
307 "SIMILAR," //SQL:2003
308 "VARIADIC,"
309 "VERBOSE,"
310 "WINDOW" //SQL:2003
311 ;
312 }
getNumericFunctions()313 OUString DatabaseMetaData::getNumericFunctions( )
314 {
315 // See http://www.postgresql.org/docs/9.1/static/functions-math.html
316 // LEM TODO: Err... http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/Support_Scalar_Functions
317 // says this should be "Open Group CLI" names, not PostgreSQL names.
318 // Currently this is just a list of supported functions in PostgreSQL, with PostgreSQL names.
319 // And it is my job to map from Open Group CLI names/syntax to PostgreSQL names/syntax. Where? By parsing the SQL???
320 // Should look at what the JDBC driver is doing.
321 return
322 "abs,"
323 "cbrt,"
324 "ceil,"
325 "ceiling,"
326 "degrees,"
327 "div,"
328 "exp,"
329 "floor,"
330 "ln,"
331 "log,"
332 "mod,"
333 "pi,"
334 "power,"
335 "radians,"
336 "random,"
337 "round,"
338 "setseed,"
339 "sign,"
340 "sqrt,"
341 "trunc,"
342 "width_bucket,"
343 "acos,"
344 "asin,"
345 "atan,"
346 "atan2,"
347 "cos,"
348 "cot,"
349 "sin,"
350 "tan"
351 ;
352 }
353
getStringFunctions()354 OUString DatabaseMetaData::getStringFunctions( )
355 {
356 // See http://www.postgresql.org/docs/9.1/static/functions-string.html
357 return
358 "bit_length,"
359 "char_length,"
360 "character_length,"
361 "lower,"
362 "octet_length,"
363 "overlay,"
364 "position,"
365 "substring,"
366 "trim,"
367 "upper,"
368 "ascii,"
369 "btrim,"
370 "chr,"
371 "concat,"
372 "concat_ws,"
373 "convert,"
374 "convert_from,"
375 "convert_to,"
376 "decode,"
377 "encode,"
378 "format,"
379 "initcap,"
380 "left,"
381 "length,"
382 "lpad,"
383 "ltrim,"
384 "md5,"
385 "pg_client_encoding,"
386 "quote_ident,"
387 "quote_literal,"
388 "quote_nullable,"
389 "regexp_matches,"
390 "regexp_replace,"
391 "regexp_split_to_array,"
392 "regexp_split_to_table,"
393 "repeat,"
394 "replace,"
395 "reverse,"
396 "right,"
397 "rpad,"
398 "rtrim,"
399 "split_part,"
400 "strpos,"
401 "substr,"
402 "to_ascii,"
403 "to_hex,"
404 "translate"
405 ;
406 }
407
getSystemFunctions()408 OUString DatabaseMetaData::getSystemFunctions( )
409 {
410 // See http://www.postgresql.org/docs/9.1/static/functions-info.html
411 // and http://www.postgresql.org/docs/9.1/static/functions-admin.html
412 return
413 "current_catalog,"
414 "current_database,"
415 "current_query,"
416 "current_schema,"
417 "current_schemas,"
418 "current_user,"
419 "inet_client_addr,"
420 "inet_client_port,"
421 "inet_server_addr,"
422 "inet_server_port,"
423 "pg_backend_pid,"
424 "pg_conf_load_time,"
425 "pg_is_other_temp_schema,"
426 "pg_listening_channels,"
427 "pg_my_temp_schema,"
428 "pg_postmaster_start_time,"
429 "session_user,"
430 "user,"
431 "version,"
432 "has_any_column_privilege,"
433 "has_any_column_privilege,"
434 "has_any_column_privilege,"
435 "has_column_privilege,"
436 "has_database_privilege,"
437 "has_foreign_data_wrapper_privilege,"
438 "has_function_privilege,"
439 "has_language_privilege,"
440 "has_schema_privilege,"
441 "has_sequence_privilege,"
442 "has_server_privilege,"
443 "has_table_privilege,"
444 "has_tablespace_privilege,"
445 "pg_has_role,"
446 "pg_collation_is_visible,"
447 "pg_conversion_is_visible,"
448 "pg_function_is_visible,"
449 "pg_opclass_is_visible,"
450 "pg_operator_is_visible,"
451 "pg_table_is_visible,"
452 "pg_ts_config_is_visible,"
453 "pg_ts_dict_is_visible,"
454 "pg_ts_parser_is_visible,"
455 "pg_ts_template_is_visible,"
456 "pg_type_is_visible,"
457 "format_type,"
458 "pg_describe_object,"
459 "pg_get_constraintdef,"
460 "pg_get_expr,"
461 "pg_get_functiondef,"
462 "pg_get_function_arguments,"
463 "pg_get_function_identity_arguments,"
464 "pg_get_function_result,"
465 "pg_get_indexdef,"
466 "pg_get_keywords,"
467 "pg_get_ruledef,"
468 "pg_get_serial_sequence,"
469 "pg_get_triggerdef,"
470 "pg_get_userbyid,"
471 "pg_get_viewdef,"
472 "pg_options_to_table,"
473 "pg_tablespace_databases,"
474 "pg_typeof,"
475 "col_description,"
476 "obj_description,"
477 "shobj_description,"
478 "txid_current,"
479 "txid_current_snapshot,"
480 "txid_snapshot_xip,"
481 "txid_snapshot_xmax,"
482 "txid_snapshot_xmin,"
483 "txid_visible_in_snapshot,"
484 "xmin,"
485 "xmax,"
486 "xip_list,"
487 "current_setting,"
488 "set_config,"
489 "pg_cancel_backend,"
490 "pg_reload_conf,"
491 "pg_rotate_logfile,"
492 "pg_terminate_backend,"
493 "pg_create_restore_point,"
494 "pg_current_xlog_insert_location,"
495 "pg_current_xlog_location,"
496 "pg_start_backup,"
497 "pg_stop_backup,"
498 "pg_switch_xlog,"
499 "pg_xlogfile_name,"
500 "pg_xlogfile_name_offset,"
501 "pg_is_in_recovery,"
502 "pg_last_xlog_receive_location,"
503 "pg_last_xlog_replay_location,"
504 "pg_last_xact_replay_timestamp,"
505 "pg_is_xlog_replay_paused,"
506 "pg_xlog_replay_pause,"
507 "pg_xlog_replay_resume,"
508 "pg_column_size,"
509 "pg_database_size,"
510 "pg_indexes_size,"
511 "pg_relation_size,"
512 "pg_size_pretty,"
513 "pg_table_size,"
514 "pg_tablespace_size,"
515 "pg_tablespace_size,"
516 "pg_total_relation_size,"
517 "pg_relation_filenode,"
518 "pg_relation_filepath,"
519 "pg_ls_dir,"
520 "pg_read_file,"
521 "pg_read_binary_file,"
522 "pg_stat_file,"
523 "pg_advisory_lock,"
524 "pg_advisory_lock_shared,"
525 "pg_advisory_unlock,"
526 "pg_advisory_unlock_all,"
527 "pg_advisory_unlock_shared,"
528 "pg_advisory_xact_lock,"
529 "pg_advisory_xact_lock_shared,"
530 "pg_try_advisory_lock,"
531 "pg_try_advisory_lock_shared,"
532 "pg_try_advisory_xact_lock,"
533 "pg_try_advisory_xact_lock_shared,"
534 "pg_sleep"
535 ;
536 }
getTimeDateFunctions()537 OUString DatabaseMetaData::getTimeDateFunctions( )
538 {
539 // TODO
540 return
541 "age,"
542 "age,"
543 "clock_timestamp,"
544 "current_date,"
545 "current_time,"
546 "current_timestamp,"
547 "date_part,"
548 "date_part,"
549 "date_trunc,"
550 "extract,"
551 "extract,"
552 "isfinite,"
553 "isfinite,"
554 "isfinite,"
555 "justify_days,"
556 "justify_hours,"
557 "justify_interval,"
558 "localtime,"
559 "localtimestamp,"
560 "now,"
561 "statement_timestamp,"
562 "timeofday,"
563 "transaction_timestamp,"
564 ;
565 }
getSearchStringEscape()566 OUString DatabaseMetaData::getSearchStringEscape( )
567 {
568 return "\\";
569 }
getExtraNameCharacters()570 OUString DatabaseMetaData::getExtraNameCharacters( )
571 {
572 return "$";
573 }
574
supportsAlterTableWithAddColumn()575 sal_Bool DatabaseMetaData::supportsAlterTableWithAddColumn( )
576 {
577 return true;
578 }
579
supportsAlterTableWithDropColumn()580 sal_Bool DatabaseMetaData::supportsAlterTableWithDropColumn( )
581 {
582 return true;
583 }
584
supportsColumnAliasing()585 sal_Bool DatabaseMetaData::supportsColumnAliasing( )
586 {
587 return true;
588 }
589
nullPlusNonNullIsNull()590 sal_Bool DatabaseMetaData::nullPlusNonNullIsNull( )
591 {
592 return true;
593 }
594
supportsTypeConversion()595 sal_Bool DatabaseMetaData::supportsTypeConversion( )
596 {
597 // LEM: this is specifically whether the "CONVERT" function is supported
598 // It seems that in PostgreSQL, that function is only for string encoding, so no.
599 return false;
600 }
601
supportsConvert(sal_Int32,sal_Int32)602 sal_Bool DatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 )
603 {
604 return false;
605 }
606
supportsTableCorrelationNames()607 sal_Bool DatabaseMetaData::supportsTableCorrelationNames( )
608 {
609 // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..."
610 return true;
611 }
612
613
supportsDifferentTableCorrelationNames()614 sal_Bool DatabaseMetaData::supportsDifferentTableCorrelationNames( )
615 {
616 return false;
617 }
supportsExpressionsInOrderBy()618 sal_Bool DatabaseMetaData::supportsExpressionsInOrderBy( )
619 {
620 return true;
621 }
622
supportsOrderByUnrelated()623 sal_Bool DatabaseMetaData::supportsOrderByUnrelated( )
624 {
625 return true;
626 }
627
supportsGroupBy()628 sal_Bool DatabaseMetaData::supportsGroupBy( )
629 {
630 return true;
631 }
632
supportsGroupByUnrelated()633 sal_Bool DatabaseMetaData::supportsGroupByUnrelated( )
634 {
635 return true;
636 }
637
supportsGroupByBeyondSelect()638 sal_Bool DatabaseMetaData::supportsGroupByBeyondSelect( )
639 {
640 return true;
641 }
642
supportsLikeEscapeClause()643 sal_Bool DatabaseMetaData::supportsLikeEscapeClause( )
644 {
645 return true;
646 }
647
supportsMultipleResultSets()648 sal_Bool DatabaseMetaData::supportsMultipleResultSets( )
649 {
650 return true;
651 }
652
supportsMultipleTransactions()653 sal_Bool DatabaseMetaData::supportsMultipleTransactions( )
654 {
655 // Allows multiple transactions open at once (on different connections!)
656 return true;
657 }
658
supportsNonNullableColumns()659 sal_Bool DatabaseMetaData::supportsNonNullableColumns( )
660 {
661 return true;
662 }
663
664
supportsMinimumSQLGrammar()665 sal_Bool DatabaseMetaData::supportsMinimumSQLGrammar( )
666 {
667 return true;
668 }
669
supportsCoreSQLGrammar()670 sal_Bool DatabaseMetaData::supportsCoreSQLGrammar( )
671 {
672 // LEM: jdbc driver says not, although the comments in it seem old
673 // fdo#45249 Base query design won't use any aggregate function
674 // (except COUNT(*) unless we say yes, so say yes.
675 // Actually, Base assumes *also* support for aggregate functions "collect, fusion, intersection"
676 // as soon as supportsCoreSQLGrammar() returns true.
677 // Those are *not* Core SQL, though. They are in optional feature S271 "Basic multiset support"
678 return true;
679 }
680
supportsExtendedSQLGrammar()681 sal_Bool DatabaseMetaData::supportsExtendedSQLGrammar( )
682 {
683 return false;
684 }
685
supportsANSI92EntryLevelSQL()686 sal_Bool DatabaseMetaData::supportsANSI92EntryLevelSQL( )
687 {
688 return true;
689 }
690
supportsANSI92IntermediateSQL()691 sal_Bool DatabaseMetaData::supportsANSI92IntermediateSQL( )
692 {
693 // LEM: jdbc driver says not, although the comments in it seem old
694 return false;
695 }
696
supportsANSI92FullSQL()697 sal_Bool DatabaseMetaData::supportsANSI92FullSQL( )
698 {
699 // LEM: jdbc driver says not, although the comments in it seem old
700 return false;
701 }
702
supportsIntegrityEnhancementFacility()703 sal_Bool DatabaseMetaData::supportsIntegrityEnhancementFacility( )
704 {
705 // LEM: jdbc driver says yes, although comment says they are not sure what this means...
706 return true;
707 }
708
supportsOuterJoins()709 sal_Bool DatabaseMetaData::supportsOuterJoins( )
710 {
711 return true;
712 }
713
supportsFullOuterJoins()714 sal_Bool DatabaseMetaData::supportsFullOuterJoins( )
715 {
716 return true;
717 }
718
supportsLimitedOuterJoins()719 sal_Bool DatabaseMetaData::supportsLimitedOuterJoins( )
720 {
721 return true;
722 }
723
724
getSchemaTerm()725 OUString DatabaseMetaData::getSchemaTerm( )
726 {
727 return "SCHEMA";
728 }
729
getProcedureTerm()730 OUString DatabaseMetaData::getProcedureTerm( )
731 {
732 return "function";
733 }
734
getCatalogTerm()735 OUString DatabaseMetaData::getCatalogTerm( )
736 {
737 return "DATABASE";
738 }
739
isCatalogAtStart()740 sal_Bool DatabaseMetaData::isCatalogAtStart( )
741 {
742 return true;
743 }
744
getCatalogSeparator()745 OUString DatabaseMetaData::getCatalogSeparator( )
746 {
747 return ".";
748 }
749
supportsSchemasInDataManipulation()750 sal_Bool DatabaseMetaData::supportsSchemasInDataManipulation( )
751 {
752 return true;
753 }
754
supportsSchemasInProcedureCalls()755 sal_Bool DatabaseMetaData::supportsSchemasInProcedureCalls( )
756 {
757 return true;
758 }
759
supportsSchemasInTableDefinitions()760 sal_Bool DatabaseMetaData::supportsSchemasInTableDefinitions( )
761 {
762 return true;
763 }
764
supportsSchemasInIndexDefinitions()765 sal_Bool DatabaseMetaData::supportsSchemasInIndexDefinitions( )
766 {
767 return true;
768 }
769
supportsSchemasInPrivilegeDefinitions()770 sal_Bool DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
771 {
772 return true;
773 }
774
supportsCatalogsInDataManipulation()775 sal_Bool DatabaseMetaData::supportsCatalogsInDataManipulation( )
776 {
777 return false;
778 }
779
supportsCatalogsInProcedureCalls()780 sal_Bool DatabaseMetaData::supportsCatalogsInProcedureCalls( )
781 {
782 return false;
783 }
784
supportsCatalogsInTableDefinitions()785 sal_Bool DatabaseMetaData::supportsCatalogsInTableDefinitions( )
786 {
787 return false;
788 }
789
790
supportsCatalogsInIndexDefinitions()791 sal_Bool DatabaseMetaData::supportsCatalogsInIndexDefinitions( )
792 {
793 return false;
794 }
795
796
supportsCatalogsInPrivilegeDefinitions()797 sal_Bool DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
798 {
799 return false;
800 }
801
802
803 // LEM TODO: positioned (through cursor) updates and deletes seem
804 // to be supported; see {UPDATE,DELETE} /table/ (...) WHERE CURRENT OF /cursor_name/" syntax
805 // and http://www.postgresql.org/docs/9.1/static/view-pg-cursors.html
806 // http://www.postgresql.org/docs/9.1/static/libpq-example.html actually uses a cursor :)
supportsPositionedDelete()807 sal_Bool DatabaseMetaData::supportsPositionedDelete( )
808 {
809 // LEM: jdbc driver says not, although the comments in it seem old
810 return false;
811 }
812
supportsPositionedUpdate()813 sal_Bool DatabaseMetaData::supportsPositionedUpdate( )
814 {
815 // LEM: jdbc driver says not, although the comments in it seem old
816 return false;
817 }
818
819
supportsSelectForUpdate()820 sal_Bool DatabaseMetaData::supportsSelectForUpdate( )
821 {
822 return true;
823 }
824
825
supportsStoredProcedures()826 sal_Bool DatabaseMetaData::supportsStoredProcedures( )
827 {
828 return true;
829 }
830
831
supportsSubqueriesInComparisons()832 sal_Bool DatabaseMetaData::supportsSubqueriesInComparisons( )
833 {
834 return true;
835 }
836
supportsSubqueriesInExists()837 sal_Bool DatabaseMetaData::supportsSubqueriesInExists( )
838 {
839 return true;
840 }
841
supportsSubqueriesInIns()842 sal_Bool DatabaseMetaData::supportsSubqueriesInIns( )
843 {
844 return true;
845 }
846
supportsSubqueriesInQuantifieds()847 sal_Bool DatabaseMetaData::supportsSubqueriesInQuantifieds( )
848 {
849 // LEM: jdbc driver says yes, although comment says they don't know what this means...
850 return true;
851 }
852
supportsCorrelatedSubqueries()853 sal_Bool DatabaseMetaData::supportsCorrelatedSubqueries( )
854 {
855 return true;
856 }
supportsUnion()857 sal_Bool DatabaseMetaData::supportsUnion( )
858 {
859 return true;
860 }
861
supportsUnionAll()862 sal_Bool DatabaseMetaData::supportsUnionAll( )
863 {
864 return true;
865 }
866
supportsOpenCursorsAcrossCommit()867 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossCommit( )
868 {
869 return false;
870 }
871
supportsOpenCursorsAcrossRollback()872 sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossRollback( )
873 {
874 return false;
875 }
876
supportsOpenStatementsAcrossCommit()877 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossCommit( )
878 {
879 return true;
880 }
supportsOpenStatementsAcrossRollback()881 sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossRollback( )
882 {
883 return true;
884 }
885
getMaxBinaryLiteralLength()886 sal_Int32 DatabaseMetaData::getMaxBinaryLiteralLength( )
887 {
888 return 0;
889 }
890
getMaxCharLiteralLength()891 sal_Int32 DatabaseMetaData::getMaxCharLiteralLength( )
892 {
893 return 0;
894 }
895
896 // Copied / adapted / simplified from JDBC driver
getIntSetting(const OUString & settingName)897 sal_Int32 DatabaseMetaData::getIntSetting(const OUString& settingName)
898 {
899 MutexGuard guard( m_xMutex->GetMutex() );
900
901 Reference< XParameters > params(m_getIntSetting_stmt, UNO_QUERY_THROW );
902 params->setString(1, settingName );
903 Reference< XResultSet > rs = m_getIntSetting_stmt->executeQuery();
904 Reference< XRow > xRow( rs , UNO_QUERY_THROW );
905 OSL_VERIFY(rs->next());
906 OSL_ENSURE(rs->isFirst(), "postgresql-sdbc DatabaseMetaData getIntSetting not on first row");
907 OSL_ENSURE(rs->isLast(), "postgresql-sdbc DatabaseMetaData getIntSetting not on last row");
908 return xRow->getInt(1);
909 }
910
getMaxNameLength()911 sal_Int32 DatabaseMetaData::getMaxNameLength()
912 {
913 if ( m_pSettings->maxNameLen == 0)
914 m_pSettings->maxNameLen = getIntSetting( "max_identifier_length" );
915 OSL_ENSURE(m_pSettings->maxNameLen, "postgresql-sdbc: maxNameLen is zero");
916 return m_pSettings->maxNameLen;
917 }
918
getMaxIndexKeys()919 sal_Int32 DatabaseMetaData::getMaxIndexKeys()
920 {
921 if ( m_pSettings->maxIndexKeys == 0)
922 m_pSettings->maxIndexKeys = getIntSetting("max_index_keys");
923 OSL_ENSURE(m_pSettings->maxIndexKeys, "postgresql-sdbc: maxIndexKeys is zero");
924 return m_pSettings->maxIndexKeys;
925 }
926
getMaxColumnNameLength()927 sal_Int32 DatabaseMetaData::getMaxColumnNameLength( )
928 {
929 return getMaxNameLength();
930 }
931
getMaxColumnsInGroupBy()932 sal_Int32 DatabaseMetaData::getMaxColumnsInGroupBy( )
933 {
934 return 0;
935 }
936
getMaxColumnsInIndex()937 sal_Int32 DatabaseMetaData::getMaxColumnsInIndex( )
938 {
939 return getMaxIndexKeys();
940 }
941
getMaxColumnsInOrderBy()942 sal_Int32 DatabaseMetaData::getMaxColumnsInOrderBy( )
943 {
944 return 0;
945 }
946
getMaxColumnsInSelect()947 sal_Int32 DatabaseMetaData::getMaxColumnsInSelect( )
948 {
949 return 0;
950 }
951
getMaxColumnsInTable()952 sal_Int32 DatabaseMetaData::getMaxColumnsInTable( )
953 {
954 return 1600;
955 }
956
getMaxConnections()957 sal_Int32 DatabaseMetaData::getMaxConnections( )
958 {
959 // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports
960 return 0;
961 }
962
getMaxCursorNameLength()963 sal_Int32 DatabaseMetaData::getMaxCursorNameLength( ) //TODO, don't know
964 {
965 return getMaxNameLength();
966 }
967
getMaxIndexLength()968 sal_Int32 DatabaseMetaData::getMaxIndexLength( ) //TODO, don't know
969 {
970 // LEM: that's the index itself, not its name
971 return 0;
972 }
973
getMaxSchemaNameLength()974 sal_Int32 DatabaseMetaData::getMaxSchemaNameLength( )
975 {
976 return getMaxNameLength();
977 }
978
getMaxProcedureNameLength()979 sal_Int32 DatabaseMetaData::getMaxProcedureNameLength( )
980 {
981 return getMaxNameLength();
982 }
983
getMaxCatalogNameLength()984 sal_Int32 DatabaseMetaData::getMaxCatalogNameLength( )
985 {
986 return getMaxNameLength();
987 }
988
getMaxRowSize()989 sal_Int32 DatabaseMetaData::getMaxRowSize( )
990 {
991 // jdbc driver says 1GB, but http://www.postgresql.org/about/ says 1.6TB
992 // and that 1GB is the maximum _field_ size
993 // The row limit does not fit into a sal_Int32
994 return 0;
995 }
996
doesMaxRowSizeIncludeBlobs()997 sal_Bool DatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
998 {
999 // LEM: Err... PostgreSQL basically does not do BLOBs well
1000 // In any case, BLOBs do not change the maximal row length AFAIK
1001 return true;
1002 }
1003
getMaxStatementLength()1004 sal_Int32 DatabaseMetaData::getMaxStatementLength( )
1005 {
1006 // LEM: actually, that would be 2^sizeof(size_t)-1
1007 // on the server? on the client (because of libpq)? minimum of the two? not sure
1008 // Anyway, big, so say unlimited.
1009 return 0;
1010 }
1011
getMaxStatements()1012 sal_Int32 DatabaseMetaData::getMaxStatements( ) //TODO, don't know
1013 {
1014 return 0;
1015 }
1016
getMaxTableNameLength()1017 sal_Int32 DatabaseMetaData::getMaxTableNameLength( )
1018 {
1019 return getMaxNameLength();
1020 }
1021
getMaxTablesInSelect()1022 sal_Int32 DatabaseMetaData::getMaxTablesInSelect( )
1023 {
1024 return 0;
1025 }
1026
getMaxUserNameLength()1027 sal_Int32 DatabaseMetaData::getMaxUserNameLength( )
1028 {
1029 return getMaxNameLength();
1030 }
1031
getDefaultTransactionIsolation()1032 sal_Int32 DatabaseMetaData::getDefaultTransactionIsolation( )
1033 {
1034 return css::sdbc::TransactionIsolation::READ_COMMITTED;
1035 }
1036
supportsTransactions()1037 sal_Bool DatabaseMetaData::supportsTransactions( )
1038 {
1039 return true;
1040 }
1041
supportsTransactionIsolationLevel(sal_Int32 level)1042 sal_Bool DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level )
1043 {
1044 if ( level == css::sdbc::TransactionIsolation::READ_COMMITTED
1045 || level == css::sdbc::TransactionIsolation::SERIALIZABLE
1046 || level == css::sdbc::TransactionIsolation::READ_UNCOMMITTED
1047 || level == css::sdbc::TransactionIsolation::REPEATABLE_READ)
1048 return true;
1049 else
1050 return false;
1051 }
1052
supportsDataDefinitionAndDataManipulationTransactions()1053 sal_Bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
1054 {
1055 return true;
1056 }
1057
supportsDataManipulationTransactionsOnly()1058 sal_Bool DatabaseMetaData::supportsDataManipulationTransactionsOnly( )
1059 {
1060 return false;
1061 }
1062
dataDefinitionCausesTransactionCommit()1063 sal_Bool DatabaseMetaData::dataDefinitionCausesTransactionCommit( )
1064 {
1065 return false;
1066 }
1067
dataDefinitionIgnoredInTransactions()1068 sal_Bool DatabaseMetaData::dataDefinitionIgnoredInTransactions( )
1069 {
1070 return false;
1071 }
1072
getProcedures(const css::uno::Any &,const OUString &,const OUString &)1073 css::uno::Reference< XResultSet > DatabaseMetaData::getProcedures(
1074 const css::uno::Any&,
1075 const OUString&,
1076 const OUString& )
1077 {
1078 // 1. PROCEDURE_CAT string => procedure catalog (may be NULL )
1079 // 2. PROCEDURE_SCHEM string => procedure schema (may be NULL )
1080 // 3. PROCEDURE_NAME string => procedure name
1081 // 4. reserved for future use
1082 // 5. reserved for future use
1083 // 6. reserved for future use
1084 // 7. REMARKS string => explanatory comment on the procedure
1085 // 8. PROCEDURE_TYPE short => kind of procedure:
1086 // * UNKNOWN - May return a result
1087 // * NO - Does not return a result
1088 // * RETURN - Returns a result
1089
1090 // LEM TODO: implement
1091 // LEM TODO: at least fake the columns, even if no row.
1092 MutexGuard guard( m_xMutex->GetMutex() );
1093 return new SequenceResultSet(
1094 m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > > (), m_pSettings->tc );
1095 }
1096
getProcedureColumns(const css::uno::Any &,const OUString &,const OUString &,const OUString &)1097 css::uno::Reference< XResultSet > DatabaseMetaData::getProcedureColumns(
1098 const css::uno::Any&,
1099 const OUString&,
1100 const OUString&,
1101 const OUString& )
1102 {
1103 MutexGuard guard( m_xMutex->GetMutex() );
1104 // LEM TODO: implement
1105 // LEM TODO: at least fake the columns, even if no row.
1106 return new SequenceResultSet(
1107 m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
1108 }
1109
getTables(const css::uno::Any &,const OUString & schemaPattern,const OUString & tableNamePattern,const css::uno::Sequence<OUString> &)1110 css::uno::Reference< XResultSet > DatabaseMetaData::getTables(
1111 const css::uno::Any&,
1112 const OUString& schemaPattern,
1113 const OUString& tableNamePattern,
1114 const css::uno::Sequence< OUString >& )
1115 {
1116 Statics &statics = getStatics();
1117
1118 MutexGuard guard( m_xMutex->GetMutex() );
1119
1120 if (isLog(m_pSettings, LogLevel::Info))
1121 {
1122 log(m_pSettings, LogLevel::Info,
1123 ("DatabaseMetaData::getTables got called with " + schemaPattern + "."
1124 + tableNamePattern));
1125 }
1126 // ignore catalog, as a single pq connection does not support multiple catalogs
1127
1128 // LEM TODO: this does not give the right column names, not the right number of columns, etc.
1129 // Take "inspiration" from JDBC driver
1130 // Ah, this is used to create a XResultSet manually... Try to do it directly in SQL
1131 Reference< XPreparedStatement > statement = m_origin->prepareStatement(
1132 "SELECT "
1133 "DISTINCT ON (pg_namespace.nspname, relname ) " // avoid duplicates (pg_settings !)
1134 "pg_namespace.nspname, relname, relkind, pg_description.description "
1135 "FROM pg_namespace, pg_class LEFT JOIN pg_description ON pg_class.oid = pg_description.objoid "
1136 "WHERE relnamespace = pg_namespace.oid "
1137 "AND ( relkind = 'r' OR relkind = 'v') "
1138 "AND pg_namespace.nspname LIKE ? "
1139 "AND relname LIKE ? "
1140 // "ORDER BY pg_namespace.nspname || relname"
1141 );
1142
1143 Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
1144 parameters->setString( 1 , schemaPattern );
1145 parameters->setString( 2 , tableNamePattern );
1146
1147 Reference< XResultSet > rs = statement->executeQuery();
1148 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1149 std::vector< std::vector<Any> > vec;
1150
1151 while( rs->next() )
1152 {
1153 std::vector< Any > row( 5 );
1154
1155 row[0] <<= m_pSettings->catalog;
1156 row[1] <<= xRow->getString( 1 );
1157 row[2] <<= xRow->getString( 2 );
1158 OUString type = xRow->getString(3);
1159 if( type == "r" )
1160 {
1161 if( xRow->getString(1) == "pg_catalog" )
1162 {
1163 row[3] <<= statics.SYSTEM_TABLE;
1164 }
1165 else
1166 {
1167 row[3] <<= statics.TABLE;
1168 }
1169 }
1170 else if( type == "v" )
1171 {
1172 row[3] <<= statics.VIEW;
1173 }
1174 else
1175 {
1176 row[3] <<= statics.UNKNOWN;
1177 }
1178 row[4] <<= xRow->getString(4);
1179
1180 // no description in postgresql AFAIK
1181 vec.push_back( row );
1182 }
1183 Reference< XCloseable > closeable( statement, UNO_QUERY );
1184 if( closeable.is() )
1185 closeable->close();
1186
1187 return new SequenceResultSet(
1188 m_xMutex, *this, statics.tablesRowNames, vec, m_pSettings->tc );
1189 }
1190
1191 namespace
1192 {
1193 // sort no schema first, then "public", then normal schemas, then internal schemas
compare_schema(const OUString & nsA,const OUString & nsB)1194 int compare_schema(const OUString &nsA, const OUString &nsB)
1195 {
1196 if (nsA.isEmpty())
1197 {
1198 return nsB.isEmpty() ? 0 : -1;
1199 }
1200 else if (nsB.isEmpty())
1201 {
1202 assert(!nsA.isEmpty());
1203 return 1;
1204 }
1205 else if(nsA == "public")
1206 {
1207 return (nsB == "public") ? 0 : -1;
1208 }
1209 else if(nsB == "public")
1210 {
1211 assert(nsA != "public");
1212 return 1;
1213 }
1214 else if(nsA.startsWith("pg_"))
1215 {
1216 if(nsB.startsWith("pg_"))
1217 return nsA.compareTo(nsB);
1218 else
1219 return 1;
1220 }
1221 else if(nsB.startsWith("pg_"))
1222 {
1223 return -1;
1224 }
1225 else
1226 {
1227 return nsA.compareTo(nsB);
1228 }
1229 }
1230
1231 struct SortInternalSchemasLastAndPublicFirst
1232 {
operator ()pq_sdbc_driver::__anon4e7f8dfb0111::SortInternalSchemasLastAndPublicFirst1233 bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
1234 {
1235 OUString valueA;
1236 OUString valueB;
1237 a[0] >>= valueA;
1238 b[0] >>= valueB;
1239 return compare_schema(valueA, valueB);
1240 }
1241 };
1242 }
1243
getSchemas()1244 css::uno::Reference< XResultSet > DatabaseMetaData::getSchemas( )
1245 {
1246 MutexGuard guard( m_xMutex->GetMutex() );
1247
1248 if (isLog(m_pSettings, LogLevel::Info))
1249 {
1250 log(m_pSettings, LogLevel::Info, "DatabaseMetaData::getSchemas() got called");
1251 }
1252 // <b>TABLE_SCHEM</b> string =&gt; schema name
1253 Reference< XStatement > statement = m_origin->createStatement();
1254 Reference< XResultSet > rs = statement->executeQuery(
1255 "SELECT nspname from pg_namespace" );
1256 // LEM TODO: look at JDBC driver and consider doing the same
1257 // in particular, excluding temporary schemas, but maybe better through pg_is_other_temp_schema(oid) OR == pg_my_temp_schema()
1258
1259 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1260 std::vector< std::vector<Any> > vec;
1261 while( rs->next() )
1262 {
1263 std::vector<Any> row(1);
1264 row[0] <<= xRow->getString(1);
1265 vec.push_back( row );
1266 }
1267
1268 // sort public first, sort internal schemas last, sort rest in alphabetic order
1269 std::sort( vec.begin(), vec.end(), SortInternalSchemasLastAndPublicFirst() );
1270
1271 Reference< XCloseable > closeable( statement, UNO_QUERY );
1272 if( closeable.is() )
1273 closeable->close();
1274 return new SequenceResultSet(
1275 m_xMutex, *this, getStatics().schemaNames, vec, m_pSettings->tc );
1276 }
1277
getCatalogs()1278 css::uno::Reference< XResultSet > DatabaseMetaData::getCatalogs( )
1279 {
1280 // LEM TODO: return the current catalog like JDBC driver?
1281 // at least fake the columns, even if no content
1282 MutexGuard guard( m_xMutex->GetMutex() );
1283 return new SequenceResultSet(
1284 m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
1285 }
1286
getTableTypes()1287 css::uno::Reference< XResultSet > DatabaseMetaData::getTableTypes( )
1288 {
1289 // LEM TODO: this can be made dynamic, see JDBC driver
1290 MutexGuard guard( m_xMutex->GetMutex() );
1291 return new SequenceResultSet(
1292 m_xMutex, *this, getStatics().tableTypeNames, getStatics().tableTypeData,
1293 m_pSettings->tc );
1294 }
1295
1296
1297 /** returns the constant from sdbc.DataType
1298 */
typeNameToDataType(const OUString & typeName,const OUString & typtype)1299 sal_Int32 typeNameToDataType( const OUString &typeName, const OUString &typtype )
1300 {
1301 // sal_Int32 ret = css::sdbc::DataType::DISTINCT;
1302 // map all unknown types to memo (longvarchar). This allows to show them in
1303 // string representation. Additionally, the edit-table-type-selection-box
1304 // is not so unusable anymore.
1305 sal_Int32 ret = css::sdbc::DataType::LONGVARCHAR;
1306 if( typtype == "b" )
1307 {
1308 // as long as the OOo framework does not support arrays,
1309 // the user is better of with interpreting arrays as strings !
1310 // if( typeName.getLength() && '_' == typeName[0] )
1311 // {
1312 // it's just a naming convention, but as long as we don't have anything better,
1313 // we take it as granted
1314 // ret = css::sdbc::DataType::ARRAY;
1315 // }
1316 // base type
1317 Statics &statics = getStatics();
1318 BaseTypeMap::const_iterator ii = statics.baseTypeMap.find( typeName );
1319 if( ii != statics.baseTypeMap.end() )
1320 {
1321 ret = ii->second;
1322 }
1323 }
1324 else if( typtype == "c" )
1325 {
1326 ret = css::sdbc::DataType::STRUCT;
1327 }
1328 else if( typtype == "d" )
1329 {
1330 ret = css::sdbc::DataType::LONGVARCHAR;
1331 }
1332 return ret;
1333 }
1334
1335 namespace {
isSystemColumn(sal_Int16 attnum)1336 bool isSystemColumn( sal_Int16 attnum )
1337 {
1338 return attnum <= 0;
1339 }
1340
1341 // is not exported by the postgres header
1342 const int PQ_VARHDRSZ = sizeof( sal_Int32 );
1343
1344 // Oh, quelle horreur
1345 // LEM TODO: Need to severely rewrite that!
1346 // should probably just "do the same" as ODBC or JDBC drivers...
extractPrecisionAndScale(sal_Int32 dataType,sal_Int32 atttypmod,sal_Int32 * precision,sal_Int32 * scale)1347 void extractPrecisionAndScale(
1348 sal_Int32 dataType, sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale )
1349 {
1350 if( atttypmod < PQ_VARHDRSZ )
1351 {
1352 *precision = 0;
1353 *scale = 0;
1354 }
1355 else
1356 {
1357 switch( dataType )
1358 {
1359 case css::sdbc::DataType::NUMERIC:
1360 case css::sdbc::DataType::DECIMAL:
1361 {
1362 *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff;
1363 *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff;
1364 break;
1365 }
1366 default:
1367 *precision = atttypmod - PQ_VARHDRSZ;
1368 *scale = 0;
1369 }
1370 }
1371 }
1372
1373 struct DatabaseTypeDescription
1374 {
DatabaseTypeDescriptionpq_sdbc_driver::__anon4e7f8dfb0211::DatabaseTypeDescription1375 DatabaseTypeDescription()
1376 {}
DatabaseTypeDescriptionpq_sdbc_driver::__anon4e7f8dfb0211::DatabaseTypeDescription1377 DatabaseTypeDescription( const OUString &name, const OUString & type ) :
1378 typeName( name ),
1379 typeType( type )
1380 {}
DatabaseTypeDescriptionpq_sdbc_driver::__anon4e7f8dfb0211::DatabaseTypeDescription1381 DatabaseTypeDescription( const DatabaseTypeDescription &source ) :
1382 typeName( source.typeName ),
1383 typeType( source.typeType )
1384 {}
operator =pq_sdbc_driver::__anon4e7f8dfb0211::DatabaseTypeDescription1385 DatabaseTypeDescription & operator = ( const DatabaseTypeDescription & source )
1386 {
1387 typeName = source.typeName;
1388 typeType = source.typeType;
1389 return *this;
1390 }
1391 OUString typeName;
1392 OUString typeType;
1393 };
1394 }
1395
1396 typedef std::unordered_map
1397 <
1398 sal_Int32,
1399 DatabaseTypeDescription
1400 > Oid2DatabaseTypeDescriptionMap;
1401
columnMetaData2DatabaseTypeDescription(Oid2DatabaseTypeDescriptionMap & oidMap,const Reference<XResultSet> & rs,const Reference<XStatement> & stmt)1402 static void columnMetaData2DatabaseTypeDescription(
1403 Oid2DatabaseTypeDescriptionMap &oidMap,
1404 const Reference< XResultSet > &rs,
1405 const Reference< XStatement > &stmt )
1406 {
1407 Reference< XRow > row( rs, UNO_QUERY_THROW );
1408 int domains = 0;
1409 OUStringBuffer queryBuf(128);
1410 queryBuf.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " );
1411 while( rs->next() )
1412 {
1413 if( row->getString( 9 ) == "d" && oidMap.find( row->getInt( 12 ) ) == oidMap.end() )
1414 {
1415 oidMap[row->getInt(12)] = DatabaseTypeDescription();
1416 if( domains )
1417 queryBuf.append( " OR " );
1418 queryBuf.append( "oid = " );
1419 queryBuf.append( row->getInt(12 ) );
1420 domains ++;
1421 }
1422 }
1423 rs->beforeFirst();
1424
1425 if( domains )
1426 {
1427 Reference< XResultSet > rsDomain = stmt->executeQuery( queryBuf.makeStringAndClear() );
1428 row.set( rsDomain, UNO_QUERY_THROW );
1429 while( rsDomain->next() )
1430 {
1431 oidMap[row->getInt(1)] = DatabaseTypeDescription(row->getString(3), row->getString(2) );
1432 }
1433 disposeNoThrow( stmt );
1434 }
1435
1436 }
1437
1438
getColumns(const css::uno::Any &,const OUString & schemaPattern,const OUString & tableNamePattern,const OUString & columnNamePattern)1439 css::uno::Reference< XResultSet > DatabaseMetaData::getColumns(
1440 const css::uno::Any&,
1441 const OUString& schemaPattern,
1442 const OUString& tableNamePattern,
1443 const OUString& columnNamePattern )
1444 {
1445 // LEM TODO: review in comparison with JDBC driver
1446 Statics &statics = getStatics();
1447
1448 // continue !
1449 MutexGuard guard( m_xMutex->GetMutex() );
1450
1451 if (isLog(m_pSettings, LogLevel::Info))
1452 {
1453 log(m_pSettings, LogLevel::Info,
1454 ("DatabaseMetaData::getColumns got called with " + schemaPattern + "."
1455 + tableNamePattern + "." + columnNamePattern));
1456 }
1457
1458 // ignore catalog, as a single pq connection
1459 // does not support multiple catalogs anyway
1460 // We don't use information_schema.columns because it contains
1461 // only the columns the current user has any privilege over.
1462
1463 // 1. TABLE_CAT string => table catalog (may be NULL)
1464 // => not supported
1465 // 2. TABLE_SCHEM string => table schema (may be NULL)
1466 // => pg_namespace.nspname
1467 // 3. TABLE_NAME string => table name
1468 // => pg_class.relname
1469 // 4. COLUMN_NAME string => column name
1470 // => pg_attribute.attname
1471 // 5. DATA_TYPE short => SQL type from java.sql.Types
1472 // => pg_type.typname => sdbc.DataType
1473 // 6. TYPE_NAME string => Data source dependent type name, for a UDT the
1474 // type name is fully qualified
1475 // => pg_type.typname
1476 // 7. COLUMN_SIZE long => column size. For char or date types this is
1477 // the maximum number of characters, for numeric
1478 // or decimal types this is precision.
1479 // => pg_attribute.atttypmod
1480 // 8. BUFFER_LENGTH is not used.
1481 // => not used
1482 // 9. DECIMAL_DIGITS long => the number of fractional digits
1483 // => don't know ! TODO !
1484 // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2)
1485 // => TODO ??
1486 // 11. NULLABLE long => is NULL allowed?
1487 // NO_NULLS - might not allow NULL values
1488 // NULABLE - definitely allows NULL values
1489 // NULLABLE_UNKNOWN - nullability unknown
1490 // => pg_attribute.attnotnull
1491 // 12. REMARKS string => comment describing column (may be NULL )
1492 // => pg_description.description
1493 // 13. COLUMN_DEF string => default value (may be NULL)
1494 // => pg_type.typdefault
1495 // 14. SQL_DATA_TYPE long => unused
1496 // => empty
1497 // 15. SQL_DATETIME_SUB long => unused
1498 // => empty
1499 // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of
1500 // bytes in the column
1501 // => pg_type.typlen
1502 // 17. ORDINAL_POSITION int => index of column in table (starting at 1)
1503 // pg_attribute.attnum
1504 // 18. IS_NULLABLE string => "NO" means column definitely does not allow
1505 // NULL values; "YES" means the column might
1506 // allow NULL values. An empty string means
1507 // nobody knows.
1508 // => pg_attribute.attnotnull
1509 OUString strDefaultValue = getColExprForDefaultSettingVal(m_pSettings);
1510 Reference< XPreparedStatement > statement = m_origin->prepareStatement(
1511 "SELECT pg_namespace.nspname, " // 1
1512 "pg_class.relname, " // 2
1513 "pg_attribute.attname, " // 3
1514 "pg_type.typname, " // 4
1515 "pg_attribute.atttypmod, " // 5
1516 "pg_attribute.attnotnull, " // 6
1517 "pg_type.typdefault, " // 7
1518 "pg_type.typtype, " // 8
1519 + strDefaultValue + // 9
1520 ",pg_description.description, " // 10
1521 "pg_type.typbasetype, " // 11
1522 "pg_attribute.attnum " // 12
1523 "FROM pg_class, "
1524 "pg_attribute LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum "
1525 "LEFT JOIN pg_description ON pg_attribute.attrelid = pg_description.objoid AND pg_attribute.attnum=pg_description.objsubid,"
1526 " pg_type, pg_namespace "
1527 "WHERE pg_attribute.attrelid = pg_class.oid "
1528 "AND pg_attribute.atttypid = pg_type.oid "
1529 "AND pg_class.relnamespace = pg_namespace.oid "
1530 "AND NOT pg_attribute.attisdropped "
1531 "AND pg_namespace.nspname LIKE ? "
1532 "AND pg_class.relname LIKE ? "
1533 "AND pg_attribute.attname LIKE ? "
1534 "ORDER BY pg_namespace.nspname, pg_class.relname, pg_attribute.attnum"
1535 );
1536
1537 Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
1538 parameters->setString( 1 , schemaPattern );
1539 parameters->setString( 2 , tableNamePattern );
1540 parameters->setString( 3 , columnNamePattern );
1541
1542 Reference< XResultSet > rs = statement->executeQuery();
1543 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1544 std::vector< std::vector<Any> > vec;
1545
1546 Oid2DatabaseTypeDescriptionMap domainMap;
1547 Reference< XStatement > domainTypeStmt = m_origin->createStatement();
1548 columnMetaData2DatabaseTypeDescription( domainMap, rs, domainTypeStmt );
1549
1550 sal_uInt32 colNum(0);
1551 OUString sSchema( "#invalid#" );
1552 OUString sTable( "#invalid#" );
1553
1554 while( rs->next() )
1555 {
1556 if( ! isSystemColumn( xRow->getShort( 12 ) ) )
1557 {
1558 OUString sNewSchema( xRow->getString(1) );
1559 OUString sNewTable( xRow->getString(2) );
1560 if ( sNewSchema != sSchema || sNewTable != sTable )
1561 {
1562 colNum = 1;
1563 sSchema = sNewSchema;
1564 sTable = sNewTable;
1565 }
1566 else
1567 ++colNum;
1568 sal_Int32 precision, scale, type;
1569 std::vector< Any > row( 18 );
1570 row[0] <<= m_pSettings->catalog;
1571 row[1] <<= sNewSchema;
1572 row[2] <<= sNewTable;
1573 row[3] <<= xRow->getString(3);
1574 if( xRow->getString(8) == "d" )
1575 {
1576 DatabaseTypeDescription desc( domainMap[xRow->getInt(11)] );
1577 type = typeNameToDataType( desc.typeName, desc.typeType );
1578 }
1579 else
1580 {
1581 type = typeNameToDataType( xRow->getString(4), xRow->getString(8) );
1582 }
1583 extractPrecisionAndScale( type, xRow->getInt(5) , &precision, &scale );
1584 row[4] <<= type;
1585 row[5] <<= xRow->getString(4);
1586 row[6] <<= precision;
1587 // row[7] BUFFER_LENGTH not used
1588 row[8] <<= scale;
1589 // row[9] RADIX TODO
1590 if( xRow->getBoolean( 6 ) && ! isSystemColumn(xRow->getInt( 12 )) )
1591 {
1592 row[10] <<= OUString::number(css::sdbc::ColumnValue::NO_NULLS);
1593 row[17] <<= statics.NO;
1594 }
1595 else
1596 {
1597 row[10] <<= OUString::number(css::sdbc::ColumnValue::NULLABLE);
1598 row[17] <<= statics.YES;
1599 }
1600
1601 row[11] <<= xRow->getString( 10 ); // comment
1602 row[12] <<= xRow->getString( 9 ); // COLUMN_DEF = pg_type.typdefault
1603 // row[13] SQL_DATA_TYPE not used
1604 // row[14] SQL_DATETIME_SUB not used
1605 row[15] <<= precision;
1606 row[16] <<= colNum ;
1607
1608 vec.push_back( row );
1609 }
1610 }
1611 Reference< XCloseable > closeable( statement, UNO_QUERY );
1612 if( closeable.is() )
1613 closeable->close();
1614
1615 return new SequenceResultSet(
1616 m_xMutex, *this, statics.columnRowNames, vec, m_pSettings->tc );
1617 }
1618
getColumnPrivileges(const css::uno::Any &,const OUString & schema,const OUString & table,const OUString & columnNamePattern)1619 css::uno::Reference< XResultSet > DatabaseMetaData::getColumnPrivileges(
1620 const css::uno::Any&,
1621 const OUString& schema,
1622 const OUString& table,
1623 const OUString& columnNamePattern )
1624 {
1625 MutexGuard guard( m_xMutex->GetMutex() );
1626
1627 if (isLog(m_pSettings, LogLevel::Info))
1628 {
1629 log(m_pSettings, LogLevel::Info,
1630 ("DatabaseMetaData::getColumnPrivileges got called with " + schema + "." + table + "."
1631 + columnNamePattern));
1632 }
1633
1634 Reference< XParameters > parameters( m_getColumnPrivs_stmt, UNO_QUERY_THROW );
1635 parameters->setString( 1 , schema );
1636 parameters->setString( 2 , table );
1637 parameters->setString( 3 , columnNamePattern );
1638
1639 Reference< XResultSet > rs = m_getColumnPrivs_stmt->executeQuery();
1640
1641 return rs;
1642 }
1643
getTablePrivileges(const css::uno::Any &,const OUString & schemaPattern,const OUString & tableNamePattern)1644 css::uno::Reference< XResultSet > DatabaseMetaData::getTablePrivileges(
1645 const css::uno::Any&,
1646 const OUString& schemaPattern,
1647 const OUString& tableNamePattern )
1648 {
1649 MutexGuard guard( m_xMutex->GetMutex() );
1650
1651 if (isLog(m_pSettings, LogLevel::Info))
1652 {
1653 log(m_pSettings, LogLevel::Info,
1654 ("DatabaseMetaData::getTablePrivileges got called with " + schemaPattern + "."
1655 + tableNamePattern));
1656 }
1657
1658 Reference< XParameters > parameters( m_getTablePrivs_stmt, UNO_QUERY_THROW );
1659 parameters->setString( 1 , schemaPattern );
1660 parameters->setString( 2 , tableNamePattern );
1661
1662 Reference< XResultSet > rs = m_getTablePrivs_stmt->executeQuery();
1663
1664 return rs;
1665 }
1666
getBestRowIdentifier(const css::uno::Any &,const OUString &,const OUString &,sal_Int32,sal_Bool)1667 css::uno::Reference< XResultSet > DatabaseMetaData::getBestRowIdentifier(
1668 const css::uno::Any&,
1669 const OUString&,
1670 const OUString&,
1671 sal_Int32,
1672 sal_Bool )
1673 {
1674 //LEM TODO: implement! See JDBC driver
1675 MutexGuard guard( m_xMutex->GetMutex() );
1676 return new SequenceResultSet(
1677 m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
1678 }
1679
getVersionColumns(const css::uno::Any &,const OUString &,const OUString &)1680 css::uno::Reference< XResultSet > DatabaseMetaData::getVersionColumns(
1681 const css::uno::Any&,
1682 const OUString&,
1683 const OUString& )
1684 {
1685 //LEM TODO: implement! See JDBC driver
1686 MutexGuard guard( m_xMutex->GetMutex() );
1687 return new SequenceResultSet(
1688 m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
1689 }
1690
getPrimaryKeys(const css::uno::Any &,const OUString & schema,const OUString & table)1691 css::uno::Reference< XResultSet > DatabaseMetaData::getPrimaryKeys(
1692 const css::uno::Any&,
1693 const OUString& schema,
1694 const OUString& table )
1695 {
1696 //LEM TODO: review
1697 MutexGuard guard( m_xMutex->GetMutex() );
1698
1699 // 1. TABLE_CAT string => table catalog (may be NULL )
1700 // 2. TABLE_SCHEM string => table schema (may be NULL )
1701 // 3. TABLE_NAME string => table name
1702 // 4. COLUMN_NAME string => column name
1703 // 5. KEY_SEQ short => sequence number within primary key
1704 // 6. PK_NAME string => primary key name (may be NULL )
1705
1706 if (isLog(m_pSettings, LogLevel::Info))
1707 {
1708 log(m_pSettings, LogLevel::Info,
1709 "DatabaseMetaData::getPrimaryKeys got called with " + schema + "." + table);
1710 }
1711
1712 Reference< XPreparedStatement > statement = m_origin->prepareStatement(
1713 "SELECT nmsp.nspname, "
1714 "cl.relname, "
1715 "con.conkey, "
1716 "con.conname, "
1717 "con.conrelid "
1718 "FROM pg_constraint as con,pg_class as cl, pg_namespace as nmsp "
1719 "WHERE con.connamespace = nmsp.oid AND con.conrelid = cl.oid AND con.contype = 'p' "
1720 "AND nmsp.nspname LIKE ? AND cl.relname LIKE ?" );
1721
1722 Reference< XParameters > parameters( statement, UNO_QUERY_THROW );
1723 parameters->setString( 1 , schema );
1724 parameters->setString( 2 , table );
1725
1726 Reference< XResultSet > rs = statement->executeQuery();
1727 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
1728 std::vector< std::vector<Any> > vec;
1729
1730 while( rs->next() )
1731 {
1732 std::vector< Any > row( 6 );
1733 row[0] <<= m_pSettings->catalog;
1734 row[1] <<= xRow->getString(1);
1735 row[2] <<= xRow->getString(2);
1736 OUString array = xRow->getString(3);
1737 row[4] <<= xRow->getString(5); // the relid
1738 row[5] <<= xRow->getString(4);
1739
1740 int i = 0;
1741 // now retrieve the columns information
1742 // unfortunately, postgresql does not allow array of variable size in
1743 // WHERE clauses (in the default installation), so we have to choose
1744 // this expensive and somewhat ugly way
1745 // annotation: postgresql shouldn't have chosen an array here, instead they
1746 // should have multiple rows per table
1747 // LEM: to transform an array into several rows, see unnest;
1748 // it is as simple as "SELECT foo, bar, unnest(qux) FROM ..."
1749 // where qux is the column that contains an array.
1750 while( array[i] && '}' != array[i] )
1751 {
1752 i++;
1753 int start = i;
1754 while( array[i] && array[i] != '}' && array[i] != ',' ) i++;
1755 row[3] <<= array.copy(start, i - start );
1756 vec.push_back( row );
1757 }
1758 }
1759
1760 {
1761 Reference< XCloseable > closeable( statement, UNO_QUERY );
1762 if( closeable.is() )
1763 closeable->close();
1764 }
1765
1766
1767 OUString lastTableOid;
1768 sal_Int32 index = 0;
1769 std::vector< std::vector< Any > > ret( vec.size() );
1770 int elements = 0;
1771 for (auto const& elem : vec)
1772 {
1773
1774 std::vector< Any > row = elem;
1775 OUString tableOid;
1776 OUString attnum;
1777
1778 row[4] >>= tableOid;
1779 row[3] >>= attnum;
1780 statement = m_origin->prepareStatement(
1781 "SELECT att.attname FROM "
1782 "pg_attribute AS att, pg_class AS cl WHERE "
1783 "att.attrelid = ? AND att.attnum = ?" );
1784
1785 parameters.set( statement, UNO_QUERY_THROW );
1786 parameters->setString( 1 , tableOid );
1787 parameters->setString( 2 , attnum );
1788
1789 rs = statement->executeQuery();
1790 xRow.set( rs, UNO_QUERY_THROW );
1791 if( rs->next() )
1792 {
1793 // column name
1794 row[3] <<= xRow->getString( 1 );
1795 if( tableOid != lastTableOid )
1796 index = 1;
1797 lastTableOid = tableOid;
1798 row[4] <<= OUString::number( index );
1799 index ++;
1800 }
1801 {
1802 Reference< XCloseable > closeable( statement, UNO_QUERY );
1803 if( closeable.is() )
1804 closeable->close();
1805 }
1806 ret[elements] = row;
1807 elements ++;
1808 }
1809 return new SequenceResultSet(
1810 m_xMutex, *this, getStatics().primaryKeyNames, ret, m_pSettings->tc );
1811 }
1812
1813 // Copied / adapted / simplified from JDBC driver
1814 #define SQL_CASE_KEYRULE " WHEN 'c' THEN " STRINGIFY(KEYRULE_CASCADE) \
1815 " WHEN 'n' THEN " STRINGIFY(KEYRULE_SET_NULL) \
1816 " WHEN 'd' THEN " STRINGIFY(KEYRULE_SET_DEFAULT) \
1817 " WHEN 'r' THEN " STRINGIFY(KEYRULE_RESTRICT) \
1818 " WHEN 'a' THEN " STRINGIFY(KEYRULE_NO_ACTION) \
1819 " ELSE NULL "
1820
1821 #define SQL_GET_REFERENCES \
1822 "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) " \
1823 "SELECT NULL::text AS PKTABLE_CAT, pkn.nspname AS PKTABLE_SCHEM, pkc.relname AS PKTABLE_NAME, pka.attname AS PKCOLUMN_NAME, " \
1824 " NULL::text AS FKTABLE_CAT, fkn.nspname AS FKTABLE_SCHEM, fkc.relname AS FKTABLE_NAME, fka.attname AS FKCOLUMN_NAME, " \
1825 " con.conkeyseq AS KEY_SEQ, " \
1826 " CASE con.confupdtype " \
1827 SQL_CASE_KEYRULE \
1828 " END AS UPDATE_RULE, " \
1829 " CASE con.confdeltype " \
1830 SQL_CASE_KEYRULE \
1831 " END AS DELETE_RULE, " \
1832 " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \
1833 " CASE " \
1834 " WHEN con.condeferrable AND con.condeferred THEN " STRINGIFY(DEFERRABILITY_INITIALLY_DEFERRED) \
1835 " WHEN con.condeferrable THEN " STRINGIFY(DEFERRABILITY_INITIALLY_IMMEDIATE) \
1836 " ELSE " STRINGIFY(DEFERRABILITY_NONE) \
1837 " END AS DEFERRABILITY " \
1838 "FROM " \
1839 " pg_catalog.pg_namespace pkn, pg_catalog.pg_class pkc, pg_catalog.pg_attribute pka, " \
1840 " pg_catalog.pg_namespace fkn, pg_catalog.pg_class fkc, pg_catalog.pg_attribute fka, " \
1841 " con, pg_catalog.pg_depend dep, pg_catalog.pg_class pkic " \
1842 "WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey AND con.confrelid = pkc.oid " \
1843 " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey AND con.conrelid = fkc.oid " \
1844 " 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 "
1845
1846 #define SQL_GET_REFERENCES_PSCHEMA " AND pkn.nspname = ? "
1847 #define SQL_GET_REFERENCES_PTABLE " AND pkc.relname = ? "
1848 #define SQL_GET_REFERENCES_FSCHEMA " AND fkn.nspname = ? "
1849 #define SQL_GET_REFERENCES_FTABLE " AND fkc.relname = ? "
1850 #define SQL_GET_REFERENCES_ORDER_SOME_PTABLE "ORDER BY fkn.nspname, fkc.relname, conkeyseq"
1851 #define SQL_GET_REFERENCES_ORDER_NO_PTABLE "ORDER BY pkn.nspname, pkc.relname, conkeyseq"
1852
1853 #define SQL_GET_REFERENCES_NONE_NONE_NONE_NONE \
1854 SQL_GET_REFERENCES \
1855 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1856
1857 #define SQL_GET_REFERENCES_SOME_NONE_NONE_NONE \
1858 SQL_GET_REFERENCES \
1859 SQL_GET_REFERENCES_PSCHEMA \
1860 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1861
1862 #define SQL_GET_REFERENCES_NONE_SOME_NONE_NONE \
1863 SQL_GET_REFERENCES \
1864 SQL_GET_REFERENCES_PTABLE \
1865 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1866
1867 #define SQL_GET_REFERENCES_SOME_SOME_NONE_NONE \
1868 SQL_GET_REFERENCES \
1869 SQL_GET_REFERENCES_PSCHEMA \
1870 SQL_GET_REFERENCES_PTABLE \
1871 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1872
1873 #define SQL_GET_REFERENCES_NONE_NONE_SOME_NONE \
1874 SQL_GET_REFERENCES \
1875 SQL_GET_REFERENCES_FSCHEMA \
1876 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1877
1878 #define SQL_GET_REFERENCES_NONE_NONE_NONE_SOME \
1879 SQL_GET_REFERENCES \
1880 SQL_GET_REFERENCES_FTABLE \
1881 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1882
1883 #define SQL_GET_REFERENCES_NONE_NONE_SOME_SOME \
1884 SQL_GET_REFERENCES \
1885 SQL_GET_REFERENCES_FSCHEMA \
1886 SQL_GET_REFERENCES_FTABLE \
1887 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1888
1889 #define SQL_GET_REFERENCES_SOME_NONE_SOME_NONE \
1890 SQL_GET_REFERENCES \
1891 SQL_GET_REFERENCES_PSCHEMA \
1892 SQL_GET_REFERENCES_FSCHEMA \
1893 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1894
1895 #define SQL_GET_REFERENCES_SOME_NONE_NONE_SOME \
1896 SQL_GET_REFERENCES \
1897 SQL_GET_REFERENCES_PSCHEMA \
1898 SQL_GET_REFERENCES_FTABLE \
1899 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1900
1901 #define SQL_GET_REFERENCES_SOME_NONE_SOME_SOME \
1902 SQL_GET_REFERENCES \
1903 SQL_GET_REFERENCES_PSCHEMA \
1904 SQL_GET_REFERENCES_FSCHEMA \
1905 SQL_GET_REFERENCES_FTABLE \
1906 SQL_GET_REFERENCES_ORDER_NO_PTABLE
1907
1908 #define SQL_GET_REFERENCES_NONE_SOME_SOME_NONE \
1909 SQL_GET_REFERENCES \
1910 SQL_GET_REFERENCES_PTABLE \
1911 SQL_GET_REFERENCES_FSCHEMA \
1912 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1913
1914 #define SQL_GET_REFERENCES_NONE_SOME_NONE_SOME \
1915 SQL_GET_REFERENCES \
1916 SQL_GET_REFERENCES_PTABLE \
1917 SQL_GET_REFERENCES_FTABLE \
1918 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1919
1920 #define SQL_GET_REFERENCES_NONE_SOME_SOME_SOME \
1921 SQL_GET_REFERENCES \
1922 SQL_GET_REFERENCES_PTABLE \
1923 SQL_GET_REFERENCES_FSCHEMA \
1924 SQL_GET_REFERENCES_FTABLE \
1925 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1926
1927 #define SQL_GET_REFERENCES_SOME_SOME_SOME_NONE \
1928 SQL_GET_REFERENCES \
1929 SQL_GET_REFERENCES_PSCHEMA \
1930 SQL_GET_REFERENCES_PTABLE \
1931 SQL_GET_REFERENCES_FSCHEMA \
1932 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1933
1934 #define SQL_GET_REFERENCES_SOME_SOME_NONE_SOME \
1935 SQL_GET_REFERENCES \
1936 SQL_GET_REFERENCES_PSCHEMA \
1937 SQL_GET_REFERENCES_PTABLE \
1938 SQL_GET_REFERENCES_FTABLE \
1939 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1940
1941 #define SQL_GET_REFERENCES_SOME_SOME_SOME_SOME \
1942 SQL_GET_REFERENCES \
1943 SQL_GET_REFERENCES_PSCHEMA \
1944 SQL_GET_REFERENCES_PTABLE \
1945 SQL_GET_REFERENCES_FSCHEMA \
1946 SQL_GET_REFERENCES_FTABLE \
1947 SQL_GET_REFERENCES_ORDER_SOME_PTABLE
1948
init_getReferences_stmt()1949 void DatabaseMetaData::init_getReferences_stmt ()
1950 {
1951 m_getReferences_stmt[0] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_NONE);
1952 m_getReferences_stmt[1] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_NONE);
1953 m_getReferences_stmt[2] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_NONE);
1954 m_getReferences_stmt[3] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_NONE);
1955 m_getReferences_stmt[4] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_NONE);
1956 m_getReferences_stmt[5] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_NONE);
1957 m_getReferences_stmt[6] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_NONE);
1958 m_getReferences_stmt[7] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_NONE);
1959 m_getReferences_stmt[8] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_SOME);
1960 m_getReferences_stmt[9] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_SOME);
1961 m_getReferences_stmt[10] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_SOME);
1962 m_getReferences_stmt[11] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_SOME);
1963 m_getReferences_stmt[12] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_SOME);
1964 m_getReferences_stmt[13] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_SOME);
1965 m_getReferences_stmt[14] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_SOME);
1966 m_getReferences_stmt[15] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_SOME);
1967 }
1968
init_getPrivs_stmt()1969 void DatabaseMetaData::init_getPrivs_stmt ()
1970 {
1971 OUStringBuffer sSQL(300);
1972 sSQL.append(
1973 " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable "
1974 " FROM ("
1975 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name,"
1976 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
1977 " FROM information_schema.table_privileges");
1978 if ( PQserverVersion( m_pSettings->pConnection ) < 90200 )
1979 // information_schema.table_privileges does not fill in default ACLs when no ACL
1980 // assume default ACL is "owner has all privileges" and add it
1981 sSQL.append(
1982 " UNION "
1983 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME,"
1984 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
1985 " FROM pg_catalog.pg_class c,"
1986 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) p (privilege),"
1987 " pg_catalog.pg_roles ro,"
1988 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
1989 " UNION ALL"
1990 " VALUES (0::oid, 'PUBLIC')"
1991 " ) AS rg (oid, rolname),"
1992 " pg_catalog.pg_namespace pn"
1993 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
1994 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid");
1995 sSQL.append(
1996 " ) dp,"
1997 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
1998 " WHERE table_schem LIKE ? AND table_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
1999 " ORDER BY table_schem, table_name, privilege" );
2000
2001 m_getTablePrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() );
2002
2003 sSQL.append(
2004 " 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 ("
2005 " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name, column_name,"
2006 " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable"
2007 " FROM information_schema.column_privileges");
2008 if ( PQserverVersion( m_pSettings->pConnection ) < 90200 )
2009 // information_schema.table_privileges does not fill in default ACLs when no ACL
2010 // assume default ACL is "owner has all privileges" and add it
2011 sSQL.append(
2012 " UNION "
2013 " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, a.attname AS column_name,"
2014 " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable"
2015 " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a,"
2016 " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) p (privilege),"
2017 " pg_catalog.pg_roles ro,"
2018 " ( SELECT oid, rolname FROM pg_catalog.pg_roles"
2019 " UNION ALL"
2020 " VALUES (0::oid, 'PUBLIC')"
2021 " ) AS rg (oid, rolname),"
2022 " pg_catalog.pg_namespace pn"
2023 " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')"
2024 " AND c.relowner=ro.oid AND c.relnamespace = pn.oid AND a.attrelid = c.oid AND a.attnum > 0");
2025 sSQL.append(
2026 " ) dp,"
2027 " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr"
2028 " WHERE table_schem = ? AND table_name = ? AND column_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))"
2029 " ORDER BY column_name, privilege" );
2030
2031 m_getColumnPrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() );
2032 }
2033
getImportedExportedKeys(const Any &,const OUString & primarySchema,const OUString & primaryTable,const Any &,const OUString & foreignSchema,const OUString & foreignTable)2034 css::uno::Reference< XResultSet > DatabaseMetaData::getImportedExportedKeys(
2035 const Any& /* primaryCatalog */,
2036 const OUString& primarySchema,
2037 const OUString& primaryTable,
2038 const Any& /* foreignCatalog */,
2039 const OUString& foreignSchema,
2040 const OUString& foreignTable )
2041 {
2042 unsigned int i = 0;
2043 if ( ! primarySchema.isEmpty() )
2044 i |= 0x01;
2045 if ( ! primaryTable.isEmpty() )
2046 i |= 0x02;
2047 if ( ! foreignSchema.isEmpty() )
2048 i |= 0x04;
2049 if ( ! foreignTable.isEmpty() )
2050 i |= 0x08;
2051
2052 Reference< XPreparedStatement > stmt = m_getReferences_stmt[i];
2053 Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
2054
2055 unsigned int j = 1;
2056 if ( i & 0x01 )
2057 param->setString( j++, primarySchema );
2058 if ( i & 0x02 )
2059 param->setString( j++, primaryTable );
2060 if ( i & 0x04 )
2061 param->setString( j++, foreignSchema );
2062 if ( i & 0x08 )
2063 param->setString( j++, foreignTable );
2064
2065 Reference< XResultSet > rs = stmt->executeQuery();
2066
2067 return rs;
2068 }
2069
2070
getImportedKeys(const css::uno::Any & catalog,const OUString & schema,const OUString & table)2071 css::uno::Reference< XResultSet > DatabaseMetaData::getImportedKeys(
2072 const css::uno::Any& catalog,
2073 const OUString& schema,
2074 const OUString& table )
2075 {
2076 return getImportedExportedKeys(Any(), OUString(), OUString(), catalog, schema, table);
2077 }
2078
getExportedKeys(const css::uno::Any & catalog,const OUString & schema,const OUString & table)2079 css::uno::Reference< XResultSet > DatabaseMetaData::getExportedKeys(
2080 const css::uno::Any& catalog,
2081 const OUString& schema,
2082 const OUString& table )
2083 {
2084 return getImportedExportedKeys(catalog, schema, table, Any(), OUString(), OUString());
2085 }
2086
getCrossReference(const css::uno::Any & primaryCatalog,const OUString & primarySchema,const OUString & primaryTable,const css::uno::Any & foreignCatalog,const OUString & foreignSchema,const OUString & foreignTable)2087 css::uno::Reference< XResultSet > DatabaseMetaData::getCrossReference(
2088 const css::uno::Any& primaryCatalog,
2089 const OUString& primarySchema,
2090 const OUString& primaryTable,
2091 const css::uno::Any& foreignCatalog,
2092 const OUString& foreignSchema,
2093 const OUString& foreignTable )
2094 {
2095 return getImportedExportedKeys( primaryCatalog, primarySchema, primaryTable, foreignCatalog, foreignSchema, foreignTable );
2096 }
2097
2098 namespace
2099 {
2100 struct TypeInfoByDataTypeSorter
2101 {
operator ()pq_sdbc_driver::__anon4e7f8dfb0311::TypeInfoByDataTypeSorter2102 bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b )
2103 {
2104 OUString valueA;
2105 OUString valueB;
2106 a[1 /*DATA_TYPE*/] >>= valueA;
2107 b[1 /*DATA_TYPE*/] >>= valueB;
2108 if( valueB.toInt32() == valueA.toInt32() )
2109 {
2110 OUString nameA;
2111 OUString nameB;
2112 a[0 /*TYPE_NAME*/] >>= nameA;
2113 b[0 /*TYPE_NAME*/] >>= nameB;
2114 OUString nsA, tnA, nsB, tnB;
2115
2116 // parse typename into schema and typename
2117 sal_Int32 nIndex=0;
2118 nsA = nameA.getToken(0, '.', nIndex);
2119 if (nIndex<0)
2120 {
2121 tnA = nsA;
2122 nsA.clear();
2123 }
2124 else
2125 {
2126 tnA = nameA.getToken(0, '.', nIndex);
2127 assert(nIndex < 0);
2128 }
2129
2130 nIndex=0;
2131 nsB = nameB.getToken(0, '.', nIndex);
2132 if (nIndex<0)
2133 {
2134 tnB = nsB;
2135 nsB.clear();
2136 }
2137 else
2138 {
2139 tnB = nameB.getToken(0, '.', nIndex);
2140 assert(nIndex < 0);
2141 }
2142
2143 const int ns_comp = compare_schema(nsA, nsB);
2144 if(ns_comp == 0)
2145 {
2146 if(nsA.isEmpty())
2147 {
2148 assert(nsB.isEmpty());
2149 // within each type category, sort privileged choice first
2150 if( tnA == "int4" || tnA == "varchar" || tnA == "char" || tnA == "text")
2151 return true;
2152 if( tnB == "int4" || tnB == "varchar" || tnB == "char" || tnB == "text")
2153 return false;
2154 }
2155 return nameA.compareTo( nameB ) < 0;
2156 }
2157 else
2158 {
2159 return ns_comp < 0;
2160 }
2161 }
2162
2163 return valueA.toInt32() < valueB.toInt32();
2164 }
2165 };
2166
calcSearchable(sal_Int32 dataType)2167 sal_Int32 calcSearchable( sal_Int32 dataType )
2168 {
2169 sal_Int32 ret = css::sdbc::ColumnSearch::FULL;
2170 if( css::sdbc::DataType::BINARY == dataType ||
2171 css::sdbc::DataType::VARBINARY == dataType ||
2172 css::sdbc::DataType::LONGVARBINARY == dataType )
2173 ret = css::sdbc::ColumnSearch::NONE;
2174
2175 return ret;
2176 }
2177
getMaxScale(sal_Int32 dataType)2178 sal_Int32 getMaxScale( sal_Int32 dataType )
2179 {
2180 // LEM TODO: review, see where used, see JDBC, ...
2181 sal_Int32 ret = 0;
2182 if( dataType == css::sdbc::DataType::NUMERIC )
2183 ret = 1000; // see pg-docs DataType/numeric
2184 // else if( dataType == DataType::DOUBLE )
2185 // ret = 308;
2186 // else if( dataType == DataType::FLOAT )
2187 // ret =
2188 return ret;
2189 }
2190
construct_full_typename(const OUString & ns,const OUString & tn)2191 OUString construct_full_typename(const OUString &ns, const OUString &tn)
2192 {
2193 if(ns.isEmpty() || ns == "pg_catalog")
2194 return tn;
2195 else
2196 return ns + "." + tn;
2197 }
2198
pgTypeInfo2ResultSet(std::vector<std::vector<Any>> & vec,const Reference<XResultSet> & rs)2199 void pgTypeInfo2ResultSet(
2200 std::vector< std::vector<Any> > &vec,
2201 const Reference< XResultSet > &rs )
2202 {
2203 static const sal_Int32 TYPE_NAME = 0; // string Type name
2204 static const sal_Int32 DATA_TYPE = 1; // short SQL data type from java.sql.Types
2205 static const sal_Int32 PRECISION = 2; // long maximum precision
2206 static const sal_Int32 CREATE_PARAMS = 5; // string => parameters used in creating the type (may be NULL )
2207 static const sal_Int32 NULLABLE = 6; // short ==> can you use NULL for this type?
2208 // - NO_NULLS - does not allow NULL values
2209 // - NULLABLE - allows NULL values
2210 // - NULLABLE_UNKNOWN - nullability unknown
2211
2212 static const sal_Int32 CASE_SENSITIVE = 7; // boolean==> is it case sensitive
2213 static const sal_Int32 SEARCHABLE = 8; // short ==>; can you use
2214 // "WHERE" based on this type:
2215 // - NONE - No support
2216 // - CHAR - Only supported with WHERE .. LIKE
2217 // - BASIC - Supported except for WHERE .. LIKE
2218 // - FULL - Supported for all WHERE ..
2219 static const sal_Int32 UNSIGNED_ATTRIBUTE = 9; // boolean ==> is it unsigned?
2220 // FIXED_PREC_SCALE = 10; boolean ==> can it be a money value?
2221 static const sal_Int32 AUTO_INCREMENT = 11; // boolean ==> can it be used for
2222 // an auto-increment value?
2223 static const sal_Int32 MINIMUM_SCALE = 13; // short ==> minimum scale supported
2224 static const sal_Int32 MAXIMUM_SCALE = 14; // short ==> maximum scale supported
2225 static const sal_Int32 NUM_PREC_RADIX = 17; // long ==> usually 2 or 10
2226
2227 /* not filled so far
2228 3. LITERAL_PREFIX string ==> prefix used to quote a literal
2229 (may be <NULL/>)
2230 4. LITERAL_SUFFIX string ==> suffix used to quote a literal
2231 (may be <NULL/>)
2232 5. CREATE_PARAMS string ==> parameters used in creating the type (may be <NULL/>)
2233 12. LOCAL_TYPE_NAME string ==> localized version of type name (may be <NULL/>)
2234 15, SQL_DATA_TYPE long ==> unused
2235 16. SQL_DATETIME_SUB long ==> unused
2236 */
2237 Reference< XRow > xRow( rs, UNO_QUERY_THROW );
2238 while( rs->next() )
2239 {
2240 std::vector< Any > row(18);
2241
2242 sal_Int32 dataType =typeNameToDataType(xRow->getString(5),xRow->getString(2));
2243 sal_Int32 precision = xRow->getString(3).toInt32();
2244
2245 if( dataType == css::sdbc::DataType::CHAR ||
2246 ( dataType == css::sdbc::DataType::VARCHAR &&
2247 xRow->getString(TYPE_NAME+1).equalsIgnoreAsciiCase("varchar") ) )
2248 {
2249 // reflect varchar as varchar with upper limit !
2250 //NOTE: the sql spec requires varchar to have an upper limit, however
2251 // in postgresql the upper limit is optional, no limit means unlimited
2252 // length (=1GB).
2253 precision = 0x40000000; // about 1 GB, see character type docs in postgresql
2254 row[CREATE_PARAMS] <<= OUString("length");
2255 }
2256 else if( dataType == css::sdbc::DataType::NUMERIC )
2257 {
2258 precision = 1000;
2259 row[CREATE_PARAMS] <<= OUString("length, scale");
2260 }
2261
2262 row[TYPE_NAME] <<= construct_full_typename(xRow->getString(6), xRow->getString(1));
2263 row[DATA_TYPE] <<= OUString::number(dataType);
2264 row[PRECISION] <<= OUString::number( precision );
2265 sal_Int32 nullable = xRow->getBoolean(4) ?
2266 css::sdbc::ColumnValue::NO_NULLS :
2267 css::sdbc::ColumnValue::NULLABLE;
2268 row[NULLABLE] <<= OUString::number(nullable);
2269 row[CASE_SENSITIVE] <<= OUString::number(1);
2270 row[SEARCHABLE] <<= OUString::number( calcSearchable( dataType ) );
2271 row[UNSIGNED_ATTRIBUTE] <<= OUString("0");
2272 if( css::sdbc::DataType::INTEGER == dataType ||
2273 css::sdbc::DataType::BIGINT == dataType )
2274 row[AUTO_INCREMENT] <<= OUString("1"); // TODO
2275 else
2276 row[AUTO_INCREMENT] <<= OUString("0"); // TODO
2277 row[MINIMUM_SCALE] <<= OUString("0"); // TODO: what is this ?
2278 row[MAXIMUM_SCALE] <<= OUString::number( getMaxScale( dataType ) );
2279 row[NUM_PREC_RADIX] <<= OUString("10"); // TODO: what is this ?
2280 vec.push_back( row );
2281 }
2282 }
2283 }
2284
2285
getTypeInfo()2286 css::uno::Reference< XResultSet > DatabaseMetaData::getTypeInfo( )
2287 {
2288 // Note: Indexes start at 0 (in the API doc, they start at 1)
2289 MutexGuard guard( m_xMutex->GetMutex() );
2290
2291 if (isLog(m_pSettings, LogLevel::Info))
2292 {
2293 log(m_pSettings, LogLevel::Info, "DatabaseMetaData::getTypeInfo() got called");
2294 }
2295
2296 Reference< XStatement > statement = m_origin->createStatement();
2297 Reference< XResultSet > rs = statement->executeQuery(
2298 "SELECT pg_type.typname AS typname," //1
2299 "pg_type.typtype AS typtype," //2
2300 "pg_type.typlen AS typlen," //3
2301 "pg_type.typnotnull AS typnotnull," //4
2302 "pg_type.typname AS typname, " //5
2303 "pg_namespace.nspname as typns " //6
2304 "FROM pg_type LEFT JOIN pg_namespace ON pg_type.typnamespace=pg_namespace.oid "
2305 "WHERE pg_type.typtype = 'b' "
2306 "OR pg_type.typtype = 'p'"
2307 );
2308
2309 std::vector< std::vector<Any> > vec;
2310 pgTypeInfo2ResultSet( vec, rs );
2311
2312 // check for domain types
2313 rs = statement->executeQuery(
2314 "SELECT t1.typname as typname,"
2315 "t2.typtype AS typtype,"
2316 "t2.typlen AS typlen,"
2317 "t2.typnotnull AS typnotnull,"
2318 "t2.typname as realtypname, "
2319 "pg_namespace.nspname as typns "
2320 "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 "
2321 "WHERE t1.typtype = 'd'" );
2322 pgTypeInfo2ResultSet( vec, rs );
2323
2324 std::sort( vec.begin(), vec.end(), TypeInfoByDataTypeSorter() );
2325
2326 return new SequenceResultSet(
2327 m_xMutex,
2328 *this,
2329 getStatics().typeinfoColumnNames,
2330 vec,
2331 m_pSettings->tc,
2332 &( getStatics().typeInfoMetaData ));
2333 }
2334
2335
getIndexInfo(const css::uno::Any &,const OUString & schema,const OUString & table,sal_Bool unique,sal_Bool)2336 css::uno::Reference< XResultSet > DatabaseMetaData::getIndexInfo(
2337 const css::uno::Any& ,
2338 const OUString& schema,
2339 const OUString& table,
2340 sal_Bool unique,
2341 sal_Bool )
2342 {
2343 //LEM TODO: review
2344 MutexGuard guard( m_xMutex->GetMutex() );
2345
2346 /*
2347 1. TABLE_CAT string -> table catalog (may be NULL )
2348 2. TABLE_SCHEM string -> table schema (may be NULL )
2349 3. TABLE_NAME string -> table name
2350 4. NON_UNIQUE boolean -> Can index values be non-unique?
2351 false when TYPE is tableIndexStatistic
2352 5. INDEX_QUALIFIER string -> index catalog (may be NULL );
2353 NULL when TYPE is tableIndexStatistic
2354 6. INDEX_NAME string -> index name; NULL when TYPE is tableIndexStatistic
2355 7. TYPE short -> index type:
2356 * 0 - this identifies table statistics that are returned
2357 in conjunction with a table's index descriptions
2358 * CLUSTERED - this is a clustered index
2359 * HASHED - this is a hashed index
2360 * OTHER - this is some other style of index
2361 8. ORDINAL_POSITION short -> column sequence number within index;
2362 zero when TYPE is tableIndexStatistic
2363 9. COLUMN_NAME string -> column name; NULL when TYPE is tableIndexStatistic
2364 10. ASC_OR_DESC string -> column sort sequence, "A"= ascending,
2365 "D" = descending, may be NULL if sort sequence
2366 is not supported; NULL when TYPE is tableIndexStatistic
2367 11. CARDINALITY long -> When TYPE is tableIndexStatistic, then this is
2368 the number of rows in the table; otherwise, it
2369 is the number of unique values in the index.
2370 12. PAGES long -> When TYPE is tableIndexStatisic then this is
2371 the number of pages used for the table, otherwise
2372 it is the number of pages used for the current index.
2373 13. FILTER_CONDITION string -> Filter condition, if any. (may be NULL )
2374
2375 */
2376 static const sal_Int32 C_SCHEMA = 1;
2377 static const sal_Int32 C_TABLENAME = 2;
2378 static const sal_Int32 C_INDEXNAME = 3;
2379 static const sal_Int32 C_IS_CLUSTERED = 4;
2380 static const sal_Int32 C_IS_UNIQUE = 5;
2381 // C_IS_PRIMARY = 6
2382 static const sal_Int32 C_COLUMNS = 7;
2383
2384 static const sal_Int32 R_TABLE_SCHEM = 1;
2385 static const sal_Int32 R_TABLE_NAME = 2;
2386 static const sal_Int32 R_NON_UNIQUE = 3;
2387 static const sal_Int32 R_INDEX_NAME = 5;
2388 static const sal_Int32 R_TYPE = 6;
2389 static const sal_Int32 R_ORDINAL_POSITION = 7;
2390 static const sal_Int32 R_COLUMN_NAME = 8;
2391
2392 Reference< XPreparedStatement > stmt = m_origin->prepareStatement(
2393 "SELECT nspname, " // 1
2394 "pg_class.relname, " // 2
2395 "class2.relname, " // 3
2396 "indisclustered, " // 4
2397 "indisunique, " // 5
2398 "indisprimary, " // 6
2399 "indkey " // 7
2400 "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid "
2401 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
2402 "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid "
2403 "WHERE nspname = ? AND pg_class.relname = ?" );
2404
2405 Reference< XParameters > param ( stmt, UNO_QUERY_THROW );
2406 param->setString( 1, schema );
2407 param->setString( 2, table );
2408 Reference< XResultSet > rs = stmt->executeQuery();
2409 Reference< XRow > xRow ( rs, UNO_QUERY_THROW );
2410
2411 std::vector< std::vector<Any> > vec;
2412 while( rs->next() )
2413 {
2414 std::vector< sal_Int32 > columns = parseIntArray( xRow->getString(C_COLUMNS) );
2415 Reference< XPreparedStatement > columnsStmt = m_origin->prepareStatement(
2416 "SELECT attnum, attname "
2417 "FROM pg_attribute "
2418 " INNER JOIN pg_class ON attrelid = pg_class.oid "
2419 " INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid "
2420 " WHERE pg_namespace.nspname=? AND pg_class.relname=?" );
2421 Reference< XParameters > paramColumn ( columnsStmt, UNO_QUERY_THROW );
2422 OUString currentSchema = xRow->getString( C_SCHEMA );
2423 OUString currentTable = xRow->getString( C_TABLENAME );
2424 OUString currentIndexName = xRow->getString( C_INDEXNAME );
2425 bool isNonUnique = ! xRow->getBoolean( C_IS_UNIQUE );
2426 sal_Int32 indexType = xRow->getBoolean( C_IS_CLUSTERED ) ?
2427 css::sdbc::IndexType::CLUSTERED :
2428 css::sdbc::IndexType::HASHED;
2429
2430 paramColumn->setString( C_SCHEMA, currentSchema );
2431 paramColumn->setString( C_TABLENAME, currentTable );
2432
2433 Reference< XResultSet > rsColumn = columnsStmt->executeQuery();
2434 Reference< XRow > rowColumn( rsColumn, UNO_QUERY_THROW );
2435 while( rsColumn->next() )
2436 {
2437 auto findIt = std::find( columns.begin(), columns.end(), rowColumn->getInt( 1 ) );
2438 if( findIt != columns.end() && ( ! isNonUnique || ! unique ) )
2439 {
2440 std::vector< Any > result( 13 );
2441 result[R_TABLE_SCHEM] <<= currentSchema;
2442 result[R_TABLE_NAME] <<= currentTable;
2443 result[R_INDEX_NAME] <<= currentIndexName;
2444 result[R_NON_UNIQUE] <<= isNonUnique;
2445 result[R_TYPE] <<= indexType;
2446 result[R_COLUMN_NAME] <<= rowColumn->getString(2);
2447 sal_Int32 nPos = static_cast<sal_Int32>(findIt - columns.begin() +1); // MSVC++ nonsense
2448 result[R_ORDINAL_POSITION] <<= nPos;
2449 vec.push_back( result );
2450 }
2451 }
2452 }
2453 return new SequenceResultSet(
2454 m_xMutex, *this, getStatics().indexinfoColumnNames,
2455 vec,
2456 m_pSettings->tc );
2457 }
2458
supportsResultSetType(sal_Int32 setType)2459 sal_Bool DatabaseMetaData::supportsResultSetType( sal_Int32 setType )
2460 {
2461 if ( setType == css::sdbc::ResultSetType::SCROLL_SENSITIVE )
2462 return false;
2463 else
2464 return true;
2465 }
2466
supportsResultSetConcurrency(sal_Int32 setType,sal_Int32)2467 sal_Bool DatabaseMetaData::supportsResultSetConcurrency(
2468 sal_Int32 setType, sal_Int32 )
2469 {
2470 if ( ! supportsResultSetType( setType ) )
2471 return false;
2472 else
2473 return true;
2474 }
2475
ownUpdatesAreVisible(sal_Int32)2476 sal_Bool DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /* setType */ )
2477 {
2478 return true;
2479 }
2480
ownDeletesAreVisible(sal_Int32)2481 sal_Bool DatabaseMetaData::ownDeletesAreVisible( sal_Int32 /* setType */ )
2482 {
2483 return true;
2484 }
2485
ownInsertsAreVisible(sal_Int32)2486 sal_Bool DatabaseMetaData::ownInsertsAreVisible( sal_Int32 /* setType */ )
2487 {
2488 return true;
2489 }
2490
othersUpdatesAreVisible(sal_Int32)2491 sal_Bool DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /* setType */ )
2492 {
2493 return false;
2494 }
2495
othersDeletesAreVisible(sal_Int32)2496 sal_Bool DatabaseMetaData::othersDeletesAreVisible( sal_Int32 /* setType */ )
2497 {
2498 return false;
2499 }
2500
othersInsertsAreVisible(sal_Int32)2501 sal_Bool DatabaseMetaData::othersInsertsAreVisible( sal_Int32 /* setType */ )
2502 {
2503 return false;
2504 }
2505
updatesAreDetected(sal_Int32)2506 sal_Bool DatabaseMetaData::updatesAreDetected( sal_Int32 /* setType */ )
2507 {
2508 return false;
2509 }
2510
deletesAreDetected(sal_Int32)2511 sal_Bool DatabaseMetaData::deletesAreDetected( sal_Int32 /* setType */ )
2512 {
2513 return false;
2514 }
insertsAreDetected(sal_Int32)2515 sal_Bool DatabaseMetaData::insertsAreDetected( sal_Int32 /* setType */ )
2516 {
2517 return false;
2518 }
2519
supportsBatchUpdates()2520 sal_Bool DatabaseMetaData::supportsBatchUpdates( )
2521 {
2522 return true;
2523 }
2524
getUDTs(const css::uno::Any &,const OUString &,const OUString &,const css::uno::Sequence<sal_Int32> &)2525 css::uno::Reference< XResultSet > DatabaseMetaData::getUDTs( const css::uno::Any&, const OUString&, const OUString&, const css::uno::Sequence< sal_Int32 >& )
2526 {
2527 //LEM TODO: implement! See JDBC driver
2528 MutexGuard guard( m_xMutex->GetMutex() );
2529 return new SequenceResultSet(
2530 m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc );
2531 }
2532
getConnection()2533 css::uno::Reference< css::sdbc::XConnection > DatabaseMetaData::getConnection()
2534 {
2535 return m_origin;
2536 }
2537 }
2538
2539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2540