LibreOffice Module connectivity (master) 1
pq_tools.cxx
Go to the documentation of this file.
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 ************************************************************************/
36
37#include <sal/config.h>
38
39#include <o3tl/any.hxx>
40#include <o3tl/string_view.hxx>
41#include <rtl/strbuf.hxx>
42#include <rtl/ustrbuf.hxx>
43#include <sal/log.hxx>
44
45#include <com/sun/star/beans/XPropertySet.hpp>
46#include <com/sun/star/container/XEnumerationAccess.hpp>
47#include <com/sun/star/lang/XComponent.hpp>
48#include <com/sun/star/sdbc/SQLException.hpp>
49#include <com/sun/star/sdbc/XRow.hpp>
50#include <com/sun/star/sdbc/XParameters.hpp>
51#include <com/sun/star/sdbc/DataType.hpp>
52#include <com/sun/star/sdbc/KeyRule.hpp>
53#include <com/sun/star/sdbcx/KeyType.hpp>
54#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
55
56#include "pq_tools.hxx"
57#include "pq_statics.hxx"
58
59#include <libpq-fe.h>
60#include <string.h>
61#include <string_view>
62
64
65using com::sun::star::lang::XComponent;
66
67using com::sun::star::sdbc::SQLException;
68using com::sun::star::sdbc::XStatement;
69using com::sun::star::sdbc::XConnection;
70using com::sun::star::sdbc::XPreparedStatement;
71using com::sun::star::sdbc::XParameters;
72using com::sun::star::sdbc::XResultSet;
73using com::sun::star::sdbc::XRow;
74
75using com::sun::star::sdbcx::XColumnsSupplier;
76
77using com::sun::star::uno::UNO_QUERY;
78using com::sun::star::uno::UNO_QUERY_THROW;
81using com::sun::star::uno::XInterface;
82using com::sun::star::uno::Any;
83
84using com::sun::star::container::XEnumeration;
85using com::sun::star::container::XEnumerationAccess;
86
87namespace pq_sdbc_driver
88{
89
90OUString concatQualified( std::u16string_view a, std::u16string_view b)
91{
92 return OUString::Concat(a) + "." + b;
93}
94
95static OString iOUStringToOString( std::u16string_view str, ConnectionSettings const *settings) {
96 OSL_ENSURE(settings, "pgsql-sdbc: OUStringToOString got NULL settings");
98}
99
100OString OUStringToOString( std::u16string_view str, ConnectionSettings const *settings) {
101 return iOUStringToOString( str, settings );
102}
103
104void bufferEscapeConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
105{
106
107 OString y = iOUStringToOString( value, settings );
108 OStringBuffer strbuf( y.getLength() * 2 + 2 );
109 int error;
110 int len = PQescapeStringConn(settings->pConnection, const_cast<char*>(strbuf.getStr()), y.getStr() , y.getLength(), &error );
111 if ( error )
112 {
113 char *errstr = PQerrorMessage(settings->pConnection);
114 // As of PostgreSQL 9.1, the only possible errors "involve invalid multibyte encoding"
115 // According to https://www2.opengroup.org/ogsys/jsp/publications/PublicationDetails.jsp?publicationid=11216
116 // (X/Open SQL CLI, March 1995, ISBN: 1-85912-081-4, X/Open Document Number: C451)
117 // 22018 is for "Invalid character value" and seems to be the best match.
118 // We have no good XInterface Reference to pass here, so just give NULL
119 throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding),
120 nullptr,
121 "22018",
122 -1,
123 Any());
124 }
125 strbuf.setLength( len );
126 // Previously here RTL_TEXTENCODING_ASCII_US; as we set the PostgreSQL client_encoding to UTF8,
127 // we get UTF8 here, too. I'm not sure why it worked well before...
128 buf.append( OStringToOUString( strbuf, RTL_TEXTENCODING_UTF8 ) );
129}
130
131static void ibufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
132{
133 buf.append( "'" );
134 bufferEscapeConstant( buf, value, settings );
135 buf.append( "'" );
136}
137
138void bufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
139{
140 return ibufferQuoteConstant( buf, value, settings );
141}
142
143void bufferQuoteAnyConstant( OUStringBuffer & buf, const Any &val, ConnectionSettings *settings )
144{
145 if( val.hasValue() )
146 {
147 OUString str;
148 val >>= str;
149 bufferQuoteConstant( buf, str, settings );
150 }
151 else
152 buf.append( "NULL" );
153}
154
155static void ibufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings )
156{
157 OSL_ENSURE(settings, "pgsql-sdbc: bufferQuoteIdentifier got NULL settings");
158
159 OString y = iOUStringToOString( toQuote, settings );
160 char *cstr = PQescapeIdentifier(settings->pConnection, y.getStr(), y.getLength());
161 if ( cstr == nullptr )
162 {
163 char *errstr = PQerrorMessage(settings->pConnection);
164 // Implementation-defined SQLACCESS error
165 throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding),
166 nullptr,
167 "22018",
168 -1,
169 Any());
170 }
171 buf.append( OStringToOUString( cstr, RTL_TEXTENCODING_UTF8 ) );
172 PQfreemem( cstr );
173}
174
175void bufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings )
176{
177 return ibufferQuoteIdentifier(buf, toQuote, settings);
178}
179
180
182 OUStringBuffer & buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings )
183{
184 ibufferQuoteIdentifier(buf, schema, settings);
185 buf.append( "." );
186 ibufferQuoteIdentifier(buf, table, settings);
187}
188
190 OUStringBuffer & buf,
191 std::u16string_view schema,
192 std::u16string_view table,
193 std::u16string_view col,
194 ConnectionSettings *settings)
195{
196 ibufferQuoteIdentifier(buf, schema, settings);
197 buf.append( "." );
198 ibufferQuoteIdentifier(buf, table, settings);
199 buf.append( "." );
200 ibufferQuoteIdentifier(buf, col, settings);
201}
202
203
205 const Reference< XPropertySet > & descriptor, const OUString &name )
206{
207 OUString value;
208 descriptor->getPropertyValue( name ) >>= value;
209 return value;
210}
211
213 const Reference< XPropertySet > & descriptor, const OUString &name )
214{
215 bool value = false;
216 descriptor->getPropertyValue( name ) >>= value;
217 return value;
218}
219
221 const Reference< XPropertySet > & descriptor, const OUString &name )
222{
223 sal_Int32 ret = 0;
224 descriptor->getPropertyValue( name ) >>= ret;
225 return ret;
226}
227
228void disposeObject( const css::uno::Reference< css::uno::XInterface > & r )
229{
230 Reference< XComponent > comp( r, UNO_QUERY );
231 if( comp.is() )
232 comp->dispose();
233}
234
235void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r )
236{
237 try
238 {
239 disposeObject( r );
240 }
241 catch( SQLException & )
242 {
243 // ignore this
244 }
245
246}
247
249{
251
252 Reference< css::sdbc::XStatement > owner( stmt, UNO_QUERY );
253 if( owner.is() )
254 ret = owner->getConnection();
255 else
256 {
257 Reference< css::sdbc::XPreparedStatement > myowner( stmt, UNO_QUERY );
258 if( myowner.is() )
259 ret = myowner->getConnection();
260 if( ! ret.is() )
261 throw SQLException(
262 "PQSDBC: Couldn't retrieve connection from statement",
263 Reference< XInterface > () , OUString(), 0 , css::uno::Any() );
264 }
265
266 return ret;
267
268}
269
271 : d( r )
272{}
273
274DisposeGuard::~DisposeGuard()
275{
276 disposeNoThrow( d );
277}
278
279TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt )
280 : m_stmt( stmt ),
281 m_commited( false )
282{
283 m_stmt->executeUpdate( getStatics().BEGIN );
284}
285
287{
288 m_stmt->executeUpdate( getStatics().COMMIT );
289 m_commited = true;
290}
291
292void TransactionGuard::executeUpdate( const OUString & sql )
293{
294 m_stmt->executeUpdate( sql );
295}
296
298{
299 try
300 {
301 if( ! m_commited )
302 m_stmt->executeUpdate( getStatics().ROLLBACK );
303 }
304 catch( css::uno::Exception & )
305 {
306 // ignore, we are within a dtor
307 }
308
310}
311
312
314{
315 return ' ' == c || 9 == c || 10 == c || 13 == c;
316}
317
318OUString extractTableFromInsert( std::u16string_view sql )
319{
320 OUString ret;
321 size_t i = 0;
322 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
323
324 if( o3tl::matchIgnoreAsciiCase(sql, u"insert", i) )
325 {
326 i += 6;
327 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
328 if( o3tl::matchIgnoreAsciiCase(sql, u"into", i) )
329 {
330 i +=4;
331 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
332 int start = i;
333 bool quote = (sql[i] == '"');
334 for( i++ ; i < sql.size() ; i ++ )
335 {
336 if( quote && sql[i] == '"' )
337 {
338 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
339 if( '.' == sql[i] )
340 {
341 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
342 if( '"' == sql[i] )
343 {
344 // the second part of the table name does not use quotes
345 // parse on
346 quote = false;
347 }
348 }
349 else
350 {
351 // end quoted name, ok
352 break;
353 }
354 }
355 else
356 {
357 if( isWhitespace( sql[i] ) )
358 {
359 // found the end of an unquoted name
360 break;
361 }
362 }
363 }
364 ret = o3tl::trim(sql.substr(start, i - start ));
365// printf( "pq_statement: parsed table name %s from insert\n" ,
366// OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() );
367 }
368 }
369 return ret;
370}
371
372
373static bool isOperator( char c )
374{
375 bool ret;
376 switch(c)
377 {
378 case '+':
379 case '-':
380 case '*':
381 case '/':
382 case '<':
383 case '>':
384 case '=':
385 case '~':
386 case '!':
387 case '@':
388 case '#':
389 case '%':
390 case '^':
391 case '&':
392 case '|':
393 case '`':
394 case '?':
395 case '$':
396 ret = true;
397 break;
398 default:
399 ret = false;
400 }
401 return ret;
402}
403
404void splitSQL( const OString & sql, std::vector< OString > &vec )
405{
406 int length = sql.getLength();
407
408 int i = 0;
409 bool singleQuote = false;
410 bool doubleQuote = false;
411 int start = 0;
412 for( ; i < length ; i ++ )
413 {
414 char c = sql[i];
415 if( doubleQuote )
416 {
417 if( '"' == c )
418 {
419 vec.push_back( OString( &sql.getStr()[start], i-start+1 ) );
420 start = i + 1;
421 doubleQuote = false;
422 }
423 }
424 else if( singleQuote )
425 {
426 if( '\'' == c && (i+1) < length && '\'' == sql[i+1] )
427 {
428 // two subsequent single quotes within a quoted string
429 // mean a single quote within the string
430 i ++;
431 }
432 else if( '\'' == c )
433 {
434 vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
435 start = i + 1; // leave single quotes !
436 singleQuote = false;
437 }
438 }
439 else
440 {
441 if( '"' == c )
442 {
443 vec.push_back( OString( &sql.getStr()[start], i - start ) );
444 doubleQuote = true;
445 start = i;
446 }
447 else if( '\'' == c )
448 {
449 vec.push_back( OString( &sql.getStr()[start], i - start ) );
450 singleQuote = true;
451 start = i;
452 }
453 }
454 }
455 if( start < i )
456 vec.push_back( OString( &sql.getStr()[start] , i - start ) );
457
458// for( i = 0 ; i < vec.size() ; i ++ )
459// printf( "%s!" , vec[i].getStr() );
460// printf( "\n" );
461
462}
463
464void tokenizeSQL( const OString & sql, std::vector< OString > &vec )
465{
466 int length = sql.getLength();
467
468 int i = 0;
469 bool singleQuote = false;
470 bool doubleQuote = false;
471 int start = 0;
472 for( ; i < length ; i ++ )
473 {
474 char c = sql[i];
475 if( doubleQuote )
476 {
477 if( '"' == c )
478 {
479 vec.push_back( OString( &sql.getStr()[start], i-start ) );
480 start = i + 1;
481 doubleQuote = false;
482 }
483 }
484 else if( singleQuote )
485 {
486 if( '\'' == c )
487 {
488 vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
489 start = i + 1; // leave single quotes !
490 singleQuote = false;
491 }
492 }
493 else
494 {
495 if( '"' == c )
496 {
497 doubleQuote = true;
498 start = i +1; // skip double quotes !
499 }
500 else if( '\'' == c )
501 {
502 singleQuote = true;
503 start = i; // leave single quotes
504 }
505 else if( isWhitespace( c ) )
506 {
507 if( i == start )
508 start ++; // skip additional whitespace
509 else
510 {
511 vec.push_back( OString( &sql.getStr()[start], i - start ) );
512 start = i +1;
513 }
514 }
515 else if( ',' == c || isOperator( c ) || '(' == c || ')' == c )
516 {
517 if( i - start )
518 vec.push_back( OString( &sql.getStr()[start], i - start ) );
519 vec.push_back( OString( &sql.getStr()[i], 1 ) );
520 start = i + 1;
521 }
522 else if( '.' == c )
523 {
524 if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) ||
525 ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) )
526 {
527 // ignore, is a literal
528 }
529 else
530 {
531 if( i - start )
532 vec.push_back( OString( &sql.getStr()[start], i - start ) );
533 vec.push_back( OString( "." ) );
534 start = i + 1;
535 }
536 }
537 }
538 }
539 if( start < i )
540 vec.push_back( OString( &sql.getStr()[start] , i - start ) );
541
542// for( i = 0 ; i < vec.size() ; i ++ )
543// printf( "%s!" , vec[i].getStr() );
544// printf( "\n" );
545}
546
547
548void splitConcatenatedIdentifier( std::u16string_view source, OUString *first, OUString *second)
549{
550 std::vector< OString > vec;
551 tokenizeSQL( rtl::OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec );
552 switch (vec.size())
553 {
554 case 1:
555 first->clear();
556 *second = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
557 break;
558 case 3:
559 *first = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
560 *second = OStringToOUString( vec[2], RTL_TEXTENCODING_UTF8 );
561 break;
562 default:
563 SAL_WARN("connectivity.postgresql",
564 "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: "
565 << vec.size());
566 }
567}
568
569OUString array2String( const css::uno::Sequence< Any > &seq )
570{
571 OUStringBuffer buf(128);
572 int len = seq.getLength();
573 buf.append( "{" );
574 for( int i = 0 ; i < len ; i ++ )
575 {
576 OUString element;
577 seq[i] >>= element;
578
579 if( i > 0 )
580 buf.append( "," );
581 int strLength = element.getLength();
582 buf.append( "\"" );
583 for( int j = 0 ; j < strLength ; j ++ )
584 {
585 sal_Unicode c = element[j];
586 if( c == '\\' || c == '"' || c == '{' || c == '}' )
587 {
588 buf.append( "\\" );
589 }
590 buf.append( c );
591 }
592 buf.append( "\"" );
593 }
594 buf.append( "}" );
595 return buf.makeStringAndClear();
596}
597
598
599std::vector< Any > parseArray( std::u16string_view str )
600{
601 size_t len = str.size();
602 bool doubleQuote = false;
603 int brackets = 0;
604 size_t i = 0;
605
606 OUStringBuffer current;
607 std::vector<Any> elements;
608 bool doubleQuotedValue = false;
609 while( i < len )
610 {
611 sal_Unicode c = str[i];
612 sal_Unicode cnext = str[i+1];
613 if( doubleQuote )
614 {
615 if( '\\' == c )
616 {
617 i ++;
618 current.append( cnext );
619 }
620 else if( '"' == c )
621 {
622 doubleQuote = false;
623 doubleQuotedValue = true; // signal, that there was an empty element
624 }
625 else
626 {
627 current.append( c );
628 }
629 }
630 else if ( '{' == c )
631 {
632 brackets ++;
633 }
634 else if( '}' == c )
635 {
636 brackets --;
637 if( brackets < 0 )
638 {
639 throw SQLException(
640 "error during array parsing, didn't expect a } at position "
641 + OUString::number(i) + " ('" + str + "')",
642 Reference< XInterface > (), OUString(), 1, Any() );
643 }
644 if( brackets == 0 )
645 {
646 if( !current.isEmpty() || doubleQuotedValue )
647 elements.push_back( Any( current.makeStringAndClear() ) );
648 }
649 else
650 {
651 current.append( c );
652 }
653 }
654 else if( '"' == c )
655 {
656// if( current.getLength() != 0 )
657// {
658// OUStringBuffer buf;
659// buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
660// buf.append( i );
661// buf.append( " ('" );
662// buf.append( str );
663// buf.append( "')" );
664// throw SDBCException(
665// buf.makeStringAndClear(),
666// Reference< XInterface > (), 1, Any() );
667// }
668// else
669// {
670 doubleQuote = true;
671// }
672 }
673 else if( ',' == c && brackets == 1)
674 {
675 doubleQuotedValue = false;
676 elements.push_back( Any( current.makeStringAndClear() ) );
677 }
678 else if( isWhitespace( c ) )
679 {
680 // ignore whitespace without quotes
681 }
682 else
683 {
684 current.append( c );
685 }
686 i++;
687 }
688 return elements;
689}
690
691std::vector< sal_Int32 > parseIntArray( const OUString & str )
692{
693 sal_Int32 start = 0;
694 std::vector<sal_Int32> vec;
695// printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
696 for( sal_Int32 i = str.indexOf( ' ' ) ; i != -1 ; i = str.indexOf( ' ', start) )
697 {
698 vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
699// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
700 start = i + 1;
701 }
702 vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
703// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
704 return vec;
705}
706
708 Int2StringMap &map,
710 const OUString &schema,
711 const OUString &table )
712{
713 Reference< XPreparedStatement > prep = conn->prepareStatement(
714 "SELECT attname,attnum "
715 "FROM pg_attribute "
716 "INNER JOIN pg_class ON attrelid = pg_class.oid "
717 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
718 "WHERE relname=? AND nspname=?" );
719
720 Reference< XParameters > paras( prep, UNO_QUERY_THROW );
721 paras->setString( 1 , table );
722 paras->setString( 2 , schema );
723 Reference< XResultSet > rs = prep->executeQuery();
724
725 Reference< XRow > xRow( rs , UNO_QUERY_THROW );
726 while( rs->next() )
727 {
728 map[ xRow->getInt(2) ] = xRow->getString(1);
729 }
730}
731
732OString extractSingleTableFromSelect( const std::vector< OString > &vec )
733{
734 OString ret;
735
736 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
737 vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) )
738 {
739 size_t token = 0;
740
741 for( token = 1; token < vec.size() ; token ++ )
742 {
743 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
744 vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) )
745 {
746 // found from
747 break;
748 }
749 }
750 token ++;
751
752 if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
753 vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) )
754 {
755 token ++;
756 }
757
758 if( token < vec.size() && vec[token] != "(" )
759 {
760 // it is a table or a function name
761 OStringBuffer buf(128);
762 if( '"' == vec[token][0] )
763 buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
764 else
765 buf.append( vec[token] );
766 token ++;
767
768 if( token < vec.size() )
769 {
770 if( vec[token] == "." )
771 {
772 buf.append( vec[token] );
773 token ++;
774 if( token < vec.size() )
775 {
776 if( '"' == vec[token][0] )
777 buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
778 else
779 buf.append( vec[token] );
780 token ++;
781 }
782 }
783 }
784
785 ret = buf.makeStringAndClear();
786 // now got my table candidate
787
788 if( token < vec.size() && vec[token] == "(" )
789 {
790 // whoops, it is a function
791 ret.clear();
792 }
793 else
794 {
795 if( token < vec.size() )
796 {
797 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
798 vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) )
799 {
800 token += 2; // skip alias
801 }
802 }
803
804 if( token < vec.size() )
805 {
806 if( vec[token] == "," )
807 {
808 // whoops, multiple tables are used
809 ret.clear();
810 }
811 else
812 {
813 static const char * forbiddenKeywords[] =
814 { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr };
815 for( int i = 0 ; forbiddenKeywords[i] ; i ++ )
816 {
817 size_t nKeywordLen = strlen(forbiddenKeywords[i]);
818 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
819 vec[token].pData->buffer, vec[token].pData->length,
820 forbiddenKeywords[i], nKeywordLen,
821 nKeywordLen ) )
822 {
823 // whoops, it is a join
824 ret.clear();
825 }
826 }
827 }
828 }
829 }
830 }
831 }
832 return ret;
833
834}
835
837{
838 return (PQserverVersion( settings->pConnection ) < 80000)?
839 OUString("pg_attrdef.adsrc"):
840 OUString("pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid, true)");
841}
842
843css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str )
844{
845 css::uno::Sequence< sal_Int32 > ret;
846 const sal_Int32 strlen = str.getLength();
847 if( str.getLength() > 1 )
848 {
849 sal_Int32 start = 0;
850 sal_uInt32 c;
851 for (;;)
852 {
853 c = str.iterateCodePoints(&start);
854 if (!iswspace(c))
855 break;
856 if ( start == strlen)
857 return ret;
858 }
859 if ( c != L'{' )
860 return ret;
861 for (;;)
862 {
863 c = str.iterateCodePoints(&start);
864 if ( !iswspace(c) )
865 break;
866 if ( start == strlen)
867 return ret;
868 }
869 if ( c == L'}' )
870 return ret;
871
872 std::vector< sal_Int32 > vec;
873 do
874 {
875 OUStringBuffer digits;
876 do
877 {
878 if(!iswspace(c))
879 break;
880 if ( start == strlen)
881 return ret;
882 c=str.iterateCodePoints(&start);
883 } while ( c );
884 do
885 {
886 if (!iswdigit(c))
887 break;
888 if ( start == strlen)
889 return ret;
890 digits.append(OUString(&c, 1));
891 c = str.iterateCodePoints(&start);
892 } while ( c );
893 vec.push_back( o3tl::toInt32(digits) );
894 do
895 {
896 if(!iswspace(c))
897 break;
898 if ( start == strlen)
899 return ret;
900 c = str.iterateCodePoints(&start);
901 } while ( c );
902 if ( c == L'}' )
903 break;
904 if ( str.iterateCodePoints(&start) != L',' )
905 return ret;
906 if ( start == strlen)
907 return ret;
908 } while( true );
909 // vec is guaranteed non-empty
910 assert(vec.size() > 0);
911 ret = css::uno::Sequence< sal_Int32 > ( vec.data() , vec.size() );
912 }
913 return ret;
914}
915
916
918 const Int2StringMap &map, const Sequence< sal_Int32 > &intArray )
919{
920 Sequence< OUString > ret( intArray.getLength() );
921 auto retRange = asNonConstRange(ret);
922 for( int i = 0; i < intArray.getLength() ; i ++ )
923 {
924 Int2StringMap::const_iterator ii = map.find( intArray[i] );
925 if( ii != map.end() )
926 retRange[i] = ii->second;
927 }
928 return ret;
929}
930
931
933{
934 OUStringBuffer typeName;
935 typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) );
936 sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION );
937
938 if( precision )
939 {
940 switch( extractIntProperty( desc, getStatics().TYPE ) )
941 {
942 case css::sdbc::DataType::VARBINARY:
943 case css::sdbc::DataType::VARCHAR:
944 case css::sdbc::DataType::CHAR:
945 {
946 typeName.append( "(" + OUString::number(precision) + ")" );
947 break;
948 }
949 case css::sdbc::DataType::DECIMAL:
950 case css::sdbc::DataType::NUMERIC:
951 {
952 typeName.append( "("
953 + OUString::number(precision)
954 + ","
955 + OUString::number(extractIntProperty( desc, getStatics().SCALE ))
956 + ")" );
957 break;
958 }
959 default:
960 ((void)0);
961 }
962 }
963 return typeName.makeStringAndClear();
964}
965
966
967static void keyType2String( OUStringBuffer & buf, sal_Int32 keyType )
968{
969 if( css::sdbc::KeyRule::CASCADE == keyType )
970 {
971 buf.append( "CASCADE " );
972 }
973 else if( css::sdbc::KeyRule::RESTRICT == keyType )
974 {
975 buf.append( "RESTRICT " );
976 }
977 else if( css::sdbc::KeyRule::SET_DEFAULT == keyType )
978 {
979 buf.append( "SET DEFAULT " );
980 }
981 else if( css::sdbc::KeyRule::SET_NULL == keyType )
982 {
983 buf.append( "SET NULL " );
984 }
985 else //if( css::sdbc::KeyRule::NO_ACTION == keyType )
986 {
987 buf.append( "NO ACTION " );
988 }
989}
990
992 OUStringBuffer &buf, const Reference< XPropertySet > &key, ConnectionSettings *settings )
993{
994 Statics &st = getStatics();
995 sal_Int32 type = extractIntProperty( key, st.TYPE );
996 OUString referencedTable = extractStringProperty( key, st.REFERENCED_TABLE );
997 sal_Int32 updateRule = extractIntProperty( key, st.UPDATE_RULE );
998 sal_Int32 deleteRule = extractIntProperty( key, st.DELETE_RULE );
999 bool foreign = false;
1000 if( type == css::sdbcx::KeyType::UNIQUE )
1001 {
1002 buf.append( "UNIQUE( " );
1003 }
1004 else if( type == css::sdbcx::KeyType::PRIMARY )
1005 {
1006 buf.append( "PRIMARY KEY( " );
1007 }
1008 else if( type == css::sdbcx::KeyType::FOREIGN )
1009 {
1010 foreign = true;
1011 buf.append( "FOREIGN KEY( " );
1012 }
1013
1014 Reference< XColumnsSupplier > columns( key, UNO_QUERY );
1015 if( columns.is() )
1016 {
1017 Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY );
1018 if( colEnumAccess.is() )
1019 {
1020 Reference< XEnumeration > colEnum = colEnumAccess->createEnumeration();
1021 bool first = true;
1022 while(colEnum.is() && colEnum->hasMoreElements() )
1023 {
1024 if( first )
1025 {
1026 first = false;
1027 }
1028 else
1029 {
1030 buf.append( ", " );
1031 }
1032 Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
1033 bufferQuoteIdentifier(buf, extractStringProperty( keyColumn, st.NAME ), settings );
1034 }
1035 }
1036 }
1037 buf.append( ") " );
1038
1039 if( !foreign )
1040 return;
1041
1042 buf.append( "REFERENCES " );
1043 OUString schema;
1044 OUString tableName;
1045 splitConcatenatedIdentifier( referencedTable, &schema, &tableName );
1046 bufferQuoteQualifiedIdentifier(buf , schema, tableName, settings );
1047 if(columns.is() )
1048 {
1049 Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY);
1050 if( colEnumAccess.is() )
1051 {
1052 buf.append( " (" );
1053 Reference< XEnumeration > colEnum(colEnumAccess->createEnumeration());
1054 bool first = true;
1055 while(colEnum.is() && colEnum->hasMoreElements() )
1056 {
1057 if( first )
1058 {
1059 first = false;
1060 }
1061 else
1062 {
1063 buf.append( ", " );
1064 }
1065 Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
1067 buf, extractStringProperty( keyColumn, st.RELATED_COLUMN ), settings );
1068 }
1069 buf.append( ") " );
1070 }
1071 }
1072
1073 buf.append( "ON DELETE " );
1074 keyType2String( buf, deleteRule );
1075 buf.append( " ON UPDATE " );
1076 keyType2String( buf, updateRule );
1077
1078}
1079
1080void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery )
1081{
1082 std::vector< OString > vec;
1083 tokenizeSQL( lastQuery, vec );
1084
1085 int nSize = vec.size();
1086// printf( "1 %d\n", nSize );
1087 if( !(nSize > 6 &&
1088 vec[0].equalsIgnoreAsciiCase( "insert" ) &&
1089 vec[1].equalsIgnoreAsciiCase( "into" )) )
1090 return;
1091
1092 int n = 2;
1093
1094// printf( "1a\n" );
1095 // skip table name
1096 if( vec[n+1].equalsIgnoreAsciiCase( "." ) )
1097 {
1098 n +=2;
1099 }
1100
1101 n ++;
1102 if( !vec[n].equalsIgnoreAsciiCase( "(" ) )
1103 return;
1104
1105 std::vector< OString> names;
1106// printf( "2\n" );
1107 // extract names
1108 n++;
1109 while( nSize > n && ! vec[n].equalsIgnoreAsciiCase( ")" ) )
1110 {
1111 names.push_back( vec[n] );
1112 if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase( "," ) )
1113 {
1114 n ++;
1115 }
1116 n++;
1117 }
1118 n++;
1119
1120 // now read the values
1121 if( !(nSize > n +1 && vec[n].equalsIgnoreAsciiCase("VALUES") &&
1122 vec[n+1].equalsIgnoreAsciiCase( "(" )) )
1123 return;
1124
1125 n +=2;
1126// printf( "3\n" );
1127 for (auto& name : names)
1128 {
1129 if (n >= nSize)
1130 break;
1131
1132 map[name] = vec[n];
1133 if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase(",") )
1134 {
1135 n ++;
1136 }
1137 n++;
1138 }
1139}
1140
1142 const css::uno::Reference< css::sdbc::XConnection > &connection,
1143 const OUString &query )
1144{
1145 OUString ret;
1146 Reference< XStatement > stmt = connection->createStatement();
1147 DisposeGuard guard( stmt );
1148 Reference< XResultSet > rs = stmt->executeQuery( query );
1149 Reference< XRow > xRow( rs, UNO_QUERY );
1150 if( rs->next() )
1151 ret = xRow->getString( 1 );
1152 return ret;
1153}
1154
1155
1156// copied from connectivity/source/dbtools, can't use the function directly
1157bool implSetObject( const Reference< XParameters >& _rxParameters,
1158 const sal_Int32 _nColumnIndex, const Any& _rValue)
1159{
1160 bool bSuccessfullyReRouted = true;
1161 switch (_rValue.getValueTypeClass())
1162 {
1163 case css::uno::TypeClass_HYPER:
1164 {
1165 _rxParameters->setLong( _nColumnIndex, sal_Int64(0) );
1166 }
1167 break;
1168
1169 case css::uno::TypeClass_VOID:
1170 _rxParameters->setNull(_nColumnIndex,css::sdbc::DataType::VARCHAR);
1171 break;
1172
1173 case css::uno::TypeClass_STRING:
1174 _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
1175 break;
1176
1177 case css::uno::TypeClass_BOOLEAN:
1178 _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
1179 break;
1180
1181 case css::uno::TypeClass_BYTE:
1182 _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
1183 break;
1184
1185 case css::uno::TypeClass_UNSIGNED_SHORT:
1186 case css::uno::TypeClass_SHORT:
1187 _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
1188 break;
1189
1190 case css::uno::TypeClass_CHAR:
1191 _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
1192 break;
1193
1194 case css::uno::TypeClass_UNSIGNED_LONG:
1195 case css::uno::TypeClass_LONG:
1196 _rxParameters->setInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
1197 break;
1198
1199 case css::uno::TypeClass_FLOAT:
1200 _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
1201 break;
1202
1203 case css::uno::TypeClass_DOUBLE:
1204 _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
1205 break;
1206
1207 case css::uno::TypeClass_SEQUENCE:
1208 if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
1209 {
1210 _rxParameters->setBytes(_nColumnIndex, *s);
1211 }
1212 else
1213 bSuccessfullyReRouted = false;
1214 break;
1215 case css::uno::TypeClass_STRUCT:
1216 if (auto s1 = o3tl::tryAccess<css::util::DateTime>(_rValue))
1217 _rxParameters->setTimestamp(_nColumnIndex, *s1);
1218 else if (auto s2 = o3tl::tryAccess<css::util::Date>(_rValue))
1219 _rxParameters->setDate(_nColumnIndex, *s2);
1220 else if (auto s3 = o3tl::tryAccess<css::util::Time>(_rValue))
1221 _rxParameters->setTime(_nColumnIndex, *s3);
1222 else
1223 bSuccessfullyReRouted = false;
1224 break;
1225
1226 case css::uno::TypeClass_INTERFACE:
1227 {
1229 if (_rValue >>= xStream)
1230 {
1231 _rValue >>= xStream;
1232 _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
1233 break;
1234 }
1235 [[fallthrough]];
1236 }
1237 default:
1238 bSuccessfullyReRouted = false;
1239
1240 }
1241
1242 return bSuccessfullyReRouted;
1243}
1244
1245}
1246
1247/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
double d
DisposeGuard(const css::uno::Reference< css::uno::XInterface > &r)
css::uno::Reference< css::sdbc::XStatement > m_stmt
Definition: pq_tools.hxx:163
void executeUpdate(const OUString &sql)
Definition: pq_tools.cxx:292
Any value
float u
float y
sal_Int64 n
uno_Any a
#define SAL_WARN(area, stream)
std::unique_ptr< sal_Int32[]> pData
RttiCompleteObjectLocator col
@ table
double getLength(const B2DPolygon &rCandidate)
class SAL_NO_VTABLE XPropertySet
int i
constexpr OUStringLiteral first
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
bool matchIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2, sal_Int32 fromIndex=0)
std::enable_if<!(detail::IsDerivedReference< T >::value||detail::IsUnoSequenceType< T >::value||std::is_base_of< css::uno::XInterface, T >::value), typenamedetail::Optional< T >::type >::type tryAccess(css::uno::Any const &any)
OString extractSingleTableFromSelect(const std::vector< OString > &vec)
Definition: pq_tools.cxx:732
bool implSetObject(const Reference< XParameters > &_rxParameters, const sal_Int32 _nColumnIndex, const Any &_rValue)
Definition: pq_tools.cxx:1157
void bufferQuoteConstant(OUStringBuffer &buf, std::u16string_view value, ConnectionSettings *settings)
Definition: pq_tools.cxx:138
static void ibufferQuoteIdentifier(OUStringBuffer &buf, std::u16string_view toQuote, ConnectionSettings *settings)
Definition: pq_tools.cxx:155
Statics & getStatics()
Definition: pq_statics.cxx:112
static OString iOUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pq_tools.cxx:95
bool isWhitespace(sal_Unicode c)
Definition: pq_tools.cxx:313
void bufferQuoteQualifiedIdentifier(OUStringBuffer &buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings)
Definition: pq_tools.cxx:181
OUString extractTableFromInsert(std::u16string_view sql)
Definition: pq_tools.cxx:318
OUString concatQualified(std::u16string_view a, std::u16string_view b)
Definition: pq_tools.cxx:90
OUString array2String(const css::uno::Sequence< Any > &seq)
Definition: pq_tools.cxx:569
sal_Int32 extractIntProperty(const Reference< XPropertySet > &descriptor, const OUString &name)
Definition: pq_tools.cxx:220
css::uno::Sequence< sal_Int32 > string2intarray(const OUString &str)
Definition: pq_tools.cxx:843
std::vector< sal_Int32 > parseIntArray(const OUString &str)
Definition: pq_tools.cxx:691
OUString sqltype2string(const Reference< XPropertySet > &desc)
Definition: pq_tools.cxx:932
void tokenizeSQL(const OString &sql, std::vector< OString > &vec)
Definition: pq_tools.cxx:464
void bufferQuoteAnyConstant(OUStringBuffer &buf, const Any &val, ConnectionSettings *settings)
Definition: pq_tools.cxx:143
void extractNameValuePairsFromInsert(String2StringMap &map, const OString &lastQuery)
Definition: pq_tools.cxx:1080
OUString querySingleValue(const css::uno::Reference< css::sdbc::XConnection > &connection, const OUString &query)
Definition: pq_tools.cxx:1141
OUString extractStringProperty(const Reference< XPropertySet > &descriptor, const OUString &name)
Definition: pq_tools.cxx:204
static bool isOperator(char c)
std::unordered_map< OString, OString > String2StringMap
Definition: pq_tools.hxx:139
static void ibufferQuoteConstant(OUStringBuffer &buf, std::u16string_view value, ConnectionSettings *settings)
Definition: pq_tools.cxx:131
void splitConcatenatedIdentifier(std::u16string_view source, OUString *first, OUString *second)
Definition: pq_tools.cxx:548
void disposeNoThrow(const css::uno::Reference< css::uno::XInterface > &r)
Definition: pq_tools.cxx:235
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pq_tools.cxx:100
OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings)
Definition: pq_tools.cxx:836
Sequence< OUString > convertMappedIntArray2StringArray(const Int2StringMap &map, const Sequence< sal_Int32 > &intArray)
Definition: pq_tools.cxx:917
Reference< XConnection > extractConnectionFromStatement(const Reference< XInterface > &stmt)
Definition: pq_tools.cxx:248
void bufferQuoteIdentifier(OUStringBuffer &buf, std::u16string_view toQuote, ConnectionSettings *settings)
Definition: pq_tools.cxx:175
void bufferEscapeConstant(OUStringBuffer &buf, std::u16string_view value, ConnectionSettings *settings)
Definition: pq_tools.cxx:104
void splitSQL(const OString &sql, std::vector< OString > &vec)
Definition: pq_tools.cxx:404
std::unordered_map< sal_Int32, OUString > Int2StringMap
static void keyType2String(OUStringBuffer &buf, sal_Int32 keyType)
Definition: pq_tools.cxx:967
void bufferKey2TableConstraint(OUStringBuffer &buf, const Reference< XPropertySet > &key, ConnectionSettings *settings)
Definition: pq_tools.cxx:991
bool extractBoolProperty(const Reference< XPropertySet > &descriptor, const OUString &name)
Definition: pq_tools.cxx:212
void disposeObject(const css::uno::Reference< css::uno::XInterface > &r)
Definition: pq_tools.cxx:228
std::vector< Any > parseArray(std::u16string_view str)
Definition: pq_tools.cxx:599
void fillAttnum2attnameMap(Int2StringMap &map, const Reference< css::sdbc::XConnection > &conn, const OUString &schema, const OUString &table)
Definition: pq_tools.cxx:707
store_handle_type *SAL_CALL query(OStoreObject *pHandle, store_handle_type *)
comp
OUString typeName
sal_Int32 precision
Definition: pq_statics.cxx:61
OUString name
Definition: pq_statics.cxx:74
sal_Int32 type
Definition: pq_statics.cxx:60
const char * tableName
Definition: pq_statics.cxx:57
std::map< OUString, rtl::Reference< Entity > > map
static const rtl_TextEncoding encoding
TYPE
sal_uInt16 sal_Unicode