nss: upgrade to release 3.73
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_tools.cxx
blobbece8a806f29be308ccff4899ad8fca4f9fc4ba1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * Effective License of whole file:
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18 * MA 02111-1307 USA
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
25 * Copyright: 2000 by Sun Microsystems, Inc.
27 * Contributor(s): Joerg Budischewski
29 * All parts contributed on or after August 2011:
31 * This Source Code Form is subject to the terms of the Mozilla Public
32 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
35 ************************************************************************/
37 #include <sal/config.h>
39 #include <o3tl/any.hxx>
40 #include <rtl/strbuf.hxx>
41 #include <rtl/ustrbuf.hxx>
42 #include <sal/log.hxx>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/container/XEnumerationAccess.hpp>
46 #include <com/sun/star/lang/XComponent.hpp>
47 #include <com/sun/star/sdbc/SQLException.hpp>
48 #include <com/sun/star/sdbc/XRow.hpp>
49 #include <com/sun/star/sdbc/XParameters.hpp>
50 #include <com/sun/star/sdbc/DataType.hpp>
51 #include <com/sun/star/sdbc/KeyRule.hpp>
52 #include <com/sun/star/sdbcx/KeyType.hpp>
53 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
55 #include "pq_tools.hxx"
56 #include "pq_statics.hxx"
58 #include <libpq-fe.h>
59 #include <string.h>
61 using com::sun::star::beans::XPropertySet;
63 using com::sun::star::lang::XComponent;
65 using com::sun::star::sdbc::SQLException;
66 using com::sun::star::sdbc::XStatement;
67 using com::sun::star::sdbc::XConnection;
68 using com::sun::star::sdbc::XPreparedStatement;
69 using com::sun::star::sdbc::XParameters;
70 using com::sun::star::sdbc::XResultSet;
71 using com::sun::star::sdbc::XRow;
73 using com::sun::star::sdbcx::XColumnsSupplier;
75 using com::sun::star::uno::UNO_QUERY;
76 using com::sun::star::uno::UNO_QUERY_THROW;
77 using com::sun::star::uno::Reference;
78 using com::sun::star::uno::Sequence;
79 using com::sun::star::uno::XInterface;
80 using com::sun::star::uno::Any;
81 using com::sun::star::uno::makeAny;
83 using com::sun::star::container::XEnumeration;
84 using com::sun::star::container::XEnumerationAccess;
86 namespace pq_sdbc_driver
89 OUString concatQualified( const OUString & a, const OUString &b)
91 return a + "." + b;
94 static OString iOUStringToOString( const OUString& str, ConnectionSettings const *settings) {
95 OSL_ENSURE(settings, "pgsql-sdbc: OUStringToOString got NULL settings");
96 return OUStringToOString( str, ConnectionSettings::encoding );
99 OString OUStringToOString( const OUString& str, ConnectionSettings const *settings) {
100 return iOUStringToOString( str, settings );
103 void bufferEscapeConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings )
106 OString y = iOUStringToOString( value, settings );
107 OStringBuffer strbuf( y.getLength() * 2 + 2 );
108 int error;
109 int len = PQescapeStringConn(settings->pConnection, const_cast<char*>(strbuf.getStr()), y.getStr() , y.getLength(), &error );
110 if ( error )
112 char *errstr = PQerrorMessage(settings->pConnection);
113 // As of PostgreSQL 9.1, the only possible errors "involve invalid multibyte encoding"
114 // According to https://www2.opengroup.org/ogsys/jsp/publications/PublicationDetails.jsp?publicationid=11216
115 // (X/Open SQL CLI, March 1995, ISBN: 1-85912-081-4, X/Open Document Number: C451)
116 // 22018 is for "Invalid character value" and seems to be the best match.
117 // We have no good XInterface Reference to pass here, so just give NULL
118 throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding),
119 nullptr,
120 "22018",
122 Any());
124 strbuf.setLength( len );
125 // Previously here RTL_TEXTENCODING_ASCII_US; as we set the PostgreSQL client_encoding to UTF8,
126 // we get UTF8 here, too. I'm not sure why it worked well before...
127 buf.append( OStringToOUString( strbuf.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) );
130 static void ibufferQuoteConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings )
132 buf.append( "'" );
133 bufferEscapeConstant( buf, value, settings );
134 buf.append( "'" );
137 void bufferQuoteConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings )
139 return ibufferQuoteConstant( buf, value, settings );
142 void bufferQuoteAnyConstant( OUStringBuffer & buf, const Any &val, ConnectionSettings *settings )
144 if( val.hasValue() )
146 OUString str;
147 val >>= str;
148 bufferQuoteConstant( buf, str, settings );
150 else
151 buf.append( "NULL" );
154 static void ibufferQuoteIdentifier( OUStringBuffer & buf, const OUString &toQuote, ConnectionSettings *settings )
156 OSL_ENSURE(settings, "pgsql-sdbc: bufferQuoteIdentifier got NULL settings");
158 OString y = iOUStringToOString( toQuote, settings );
159 char *cstr = PQescapeIdentifier(settings->pConnection, y.getStr(), y.getLength());
160 if ( cstr == nullptr )
162 char *errstr = PQerrorMessage(settings->pConnection);
163 // Implementation-defined SQLACCESS error
164 throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding),
165 nullptr,
166 "22018",
168 Any());
170 buf.append( OStringToOUString( cstr, RTL_TEXTENCODING_UTF8 ) );
171 PQfreemem( cstr );
174 void bufferQuoteIdentifier( OUStringBuffer & buf, const OUString &toQuote, ConnectionSettings *settings )
176 return ibufferQuoteIdentifier(buf, toQuote, settings);
180 void bufferQuoteQualifiedIdentifier(
181 OUStringBuffer & buf, const OUString &schema, const OUString &table, ConnectionSettings *settings )
183 ibufferQuoteIdentifier(buf, schema, settings);
184 buf.append( "." );
185 ibufferQuoteIdentifier(buf, table, settings);
188 void bufferQuoteQualifiedIdentifier(
189 OUStringBuffer & buf,
190 const OUString &schema,
191 const OUString &table,
192 const OUString &col,
193 ConnectionSettings *settings)
195 ibufferQuoteIdentifier(buf, schema, settings);
196 buf.append( "." );
197 ibufferQuoteIdentifier(buf, table, settings);
198 buf.append( "." );
199 ibufferQuoteIdentifier(buf, col, settings);
203 OUString extractStringProperty(
204 const Reference< XPropertySet > & descriptor, const OUString &name )
206 OUString value;
207 descriptor->getPropertyValue( name ) >>= value;
208 return value;
211 bool extractBoolProperty(
212 const Reference< XPropertySet > & descriptor, const OUString &name )
214 bool value = false;
215 descriptor->getPropertyValue( name ) >>= value;
216 return value;
219 sal_Int32 extractIntProperty(
220 const Reference< XPropertySet > & descriptor, const OUString &name )
222 sal_Int32 ret = 0;
223 descriptor->getPropertyValue( name ) >>= ret;
224 return ret;
227 void disposeObject( const css::uno::Reference< css::uno::XInterface > & r )
229 Reference< XComponent > comp( r, UNO_QUERY );
230 if( comp.is() )
231 comp->dispose();
234 void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r )
238 disposeObject( r );
240 catch( SQLException & )
242 // ignore this
247 Reference< XConnection > extractConnectionFromStatement( const Reference< XInterface > & stmt )
249 Reference< XConnection > ret;
251 Reference< css::sdbc::XStatement > owner( stmt, UNO_QUERY );
252 if( owner.is() )
253 ret = owner->getConnection();
254 else
256 Reference< css::sdbc::XPreparedStatement > myowner( stmt, UNO_QUERY );
257 if( myowner.is() )
258 ret = myowner->getConnection();
259 if( ! ret.is() )
260 throw SQLException(
261 "PQSDBC: Couldn't retrieve connection from statement",
262 Reference< XInterface > () , OUString(), 0 , css::uno::Any() );
265 return ret;
269 DisposeGuard::DisposeGuard( const Reference< XInterface > & r )
270 : d( r )
273 DisposeGuard::~DisposeGuard()
275 disposeNoThrow( d );
278 TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt )
279 : m_stmt( stmt ),
280 m_commited( false )
282 m_stmt->executeUpdate( getStatics().BEGIN );
285 void TransactionGuard::commit()
287 m_stmt->executeUpdate( getStatics().COMMIT );
288 m_commited = true;
291 void TransactionGuard::executeUpdate( const OUString & sql )
293 m_stmt->executeUpdate( sql );
296 TransactionGuard::~TransactionGuard()
300 if( ! m_commited )
301 m_stmt->executeUpdate( getStatics().ROLLBACK );
303 catch( css::uno::Exception & )
305 // ignore, we are within a dtor
308 disposeNoThrow( m_stmt );
312 bool isWhitespace( sal_Unicode c )
314 return ' ' == c || 9 == c || 10 == c || 13 == c;
317 OUString extractTableFromInsert( const OUString & sql )
319 OUString ret;
320 int i = 0;
321 while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
323 if( sql.matchIgnoreAsciiCase("insert", i) )
325 i += 6;
326 while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
327 if( sql.matchIgnoreAsciiCase("into", i) )
329 i +=4;
330 while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
331 int start = i;
332 bool quote = (sql[i] == '"');
333 for( i++ ; i < sql.getLength() ; i ++ )
335 if( quote && sql[i] == '"' )
337 while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
338 if( '.' == sql[i] )
340 while (i < sql.getLength() && isWhitespace(sql[i])) { i++; }
341 if( '"' == sql[i] )
343 // the second part of the table name does not use quotes
344 // parse on
345 quote = false;
348 else
350 // end quoted name, ok
351 break;
354 else
356 if( isWhitespace( sql[i] ) )
358 // found the end of an unquoted name
359 break;
363 ret = sql.copy(start, i - start ).trim();
364 // printf( "pq_statement: parsed table name %s from insert\n" ,
365 // OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() );
368 return ret;
372 static bool isOperator( char c )
374 bool ret;
375 switch(c)
377 case '+':
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 ret = true;
396 break;
397 default:
398 ret = false;
400 return ret;
403 void splitSQL( const OString & sql, std::vector< OString > &vec )
405 int length = sql.getLength();
407 int i = 0;
408 bool singleQuote = false;
409 bool doubleQuote = false;
410 int start = 0;
411 for( ; i < length ; i ++ )
413 char c = sql[i];
414 if( doubleQuote )
416 if( '"' == c )
418 vec.push_back( OString( &sql.getStr()[start], i-start+1 ) );
419 start = i + 1;
420 doubleQuote = false;
423 else if( singleQuote )
425 if( '\'' == c && (i+1) < length && '\'' == sql[i+1] )
427 // two subsequent single quotes within a quoted string
428 // mean a single quote within the string
429 i ++;
431 else if( '\'' == c )
433 vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
434 start = i + 1; // leave single quotes !
435 singleQuote = false;
438 else
440 if( '"' == c )
442 vec.push_back( OString( &sql.getStr()[start], i - start ) );
443 doubleQuote = true;
444 start = i;
446 else if( '\'' == c )
448 vec.push_back( OString( &sql.getStr()[start], i - start ) );
449 singleQuote = true;
450 start = i;
454 if( start < i )
455 vec.push_back( OString( &sql.getStr()[start] , i - start ) );
457 // for( i = 0 ; i < vec.size() ; i ++ )
458 // printf( "%s!" , vec[i].getStr() );
459 // printf( "\n" );
463 void tokenizeSQL( const OString & sql, std::vector< OString > &vec )
465 int length = sql.getLength();
467 int i = 0;
468 bool singleQuote = false;
469 bool doubleQuote = false;
470 int start = 0;
471 for( ; i < length ; i ++ )
473 char c = sql[i];
474 if( doubleQuote )
476 if( '"' == c )
478 vec.push_back( OString( &sql.getStr()[start], i-start ) );
479 start = i + 1;
480 doubleQuote = false;
483 else if( singleQuote )
485 if( '\'' == c )
487 vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
488 start = i + 1; // leave single quotes !
489 singleQuote = false;
492 else
494 if( '"' == c )
496 doubleQuote = true;
497 start = i +1; // skip double quotes !
499 else if( '\'' == c )
501 singleQuote = true;
502 start = i; // leave single quotes
504 else if( isWhitespace( c ) )
506 if( i == start )
507 start ++; // skip additional whitespace
508 else
510 vec.push_back( OString( &sql.getStr()[start], i - start ) );
511 start = i +1;
514 else if( ',' == c || isOperator( c ) || '(' == c || ')' == c )
516 if( i - start )
517 vec.push_back( OString( &sql.getStr()[start], i - start ) );
518 vec.push_back( OString( &sql.getStr()[i], 1 ) );
519 start = i + 1;
521 else if( '.' == c )
523 if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) ||
524 ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) )
526 // ignore, is a literal
528 else
530 if( i - start )
531 vec.push_back( OString( &sql.getStr()[start], i - start ) );
532 vec.push_back( OString( "." ) );
533 start = i + 1;
538 if( start < i )
539 vec.push_back( OString( &sql.getStr()[start] , i - start ) );
541 // for( i = 0 ; i < vec.size() ; i ++ )
542 // printf( "%s!" , vec[i].getStr() );
543 // printf( "\n" );
547 void splitConcatenatedIdentifier( const OUString & source, OUString *first, OUString *second)
549 std::vector< OString > vec;
550 tokenizeSQL( OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec );
551 switch (vec.size())
553 case 1:
554 first->clear();
555 *second = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
556 break;
557 case 3:
558 *first = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 );
559 *second = OStringToOUString( vec[2], RTL_TEXTENCODING_UTF8 );
560 break;
561 default:
562 SAL_WARN("connectivity.postgresql",
563 "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: "
564 << vec.size());
568 OUString array2String( const css::uno::Sequence< Any > &seq )
570 OUStringBuffer buf(128);
571 int len = seq.getLength();
572 buf.append( "{" );
573 for( int i = 0 ; i < len ; i ++ )
575 OUString element;
576 seq[i] >>= element;
578 if( i > 0 )
579 buf.append( "," );
580 int strLength = element.getLength();
581 buf.append( "\"" );
582 for( int j = 0 ; j < strLength ; j ++ )
584 sal_Unicode c = element[j];
585 if( c == '\\' || c == '"' || c == '{' || c == '}' )
587 buf.append( "\\" );
589 buf.append( c );
591 buf.append( "\"" );
593 buf.append( "}" );
594 return buf.makeStringAndClear();
598 std::vector< Any > parseArray( const OUString & str )
600 int len = str.getLength();
601 bool doubleQuote = false;
602 int brackets = 0;
603 int i = 0;
605 OUStringBuffer current;
606 std::vector<Any> elements;
607 bool doubleQuotedValue = false;
608 while( i < len )
610 sal_Unicode c = str[i];
611 sal_Unicode cnext = str[i+1];
612 if( doubleQuote )
614 if( '\\' == c )
616 i ++;
617 current.append( cnext );
619 else if( '"' == c )
621 doubleQuote = false;
622 doubleQuotedValue = true; // signal, that there was an empty element
624 else
626 current.append( c );
629 else if ( '{' == c )
631 brackets ++;
633 else if( '}' == c )
635 brackets --;
636 if( brackets < 0 )
638 throw SQLException(
639 "error during array parsing, didn't expect a } at position "
640 + OUString::number(i) + " ('" + str + "')",
641 Reference< XInterface > (), OUString(), 1, Any() );
643 if( brackets == 0 )
645 if( !current.isEmpty() || doubleQuotedValue )
646 elements.push_back( makeAny( current.makeStringAndClear() ) );
648 else
650 current.append( c );
653 else if( '"' == c )
655 // if( current.getLength() != 0 )
656 // {
657 // OUStringBuffer buf;
658 // buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
659 // buf.append( i );
660 // buf.append( " ('" );
661 // buf.append( str );
662 // buf.append( "')" );
663 // throw SDBCException(
664 // buf.makeStringAndClear(),
665 // Reference< XInterface > (), 1, Any() );
666 // }
667 // else
668 // {
669 doubleQuote = true;
670 // }
672 else if( ',' == c && brackets == 1)
674 doubleQuotedValue = false;
675 elements.push_back( makeAny( current.makeStringAndClear() ) );
677 else if( isWhitespace( c ) )
679 // ignore whitespace without quotes
681 else
683 current.append( c );
685 i++;
687 return elements;
690 std::vector< sal_Int32 > parseIntArray( const OUString & str )
692 sal_Int32 start = 0;
693 std::vector<sal_Int32> vec;
694 // printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
695 for( sal_Int32 i = str.indexOf( ' ' ) ; i != -1 ; i = str.indexOf( ' ', start) )
697 vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
698 // printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
699 start = i + 1;
701 vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
702 // printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
703 return vec;
706 void fillAttnum2attnameMap(
707 Int2StringMap &map,
708 const Reference< css::sdbc::XConnection > &conn,
709 const OUString &schema,
710 const OUString &table )
712 Reference< XPreparedStatement > prep = conn->prepareStatement(
713 "SELECT attname,attnum "
714 "FROM pg_attribute "
715 "INNER JOIN pg_class ON attrelid = pg_class.oid "
716 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
717 "WHERE relname=? AND nspname=?" );
719 Reference< XParameters > paras( prep, UNO_QUERY_THROW );
720 paras->setString( 1 , table );
721 paras->setString( 2 , schema );
722 Reference< XResultSet > rs = prep->executeQuery();
724 Reference< XRow > xRow( rs , UNO_QUERY_THROW );
725 while( rs->next() )
727 map[ xRow->getInt(2) ] = xRow->getString(1);
731 OString extractSingleTableFromSelect( const std::vector< OString > &vec )
733 OString ret;
735 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
736 vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) )
738 size_t token = 0;
740 for( token = 1; token < vec.size() ; token ++ )
742 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
743 vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) )
745 // found from
746 break;
749 token ++;
751 if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
752 vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) )
754 token ++;
757 if( token < vec.size() && vec[token] != "(" )
759 // it is a table or a function name
760 OStringBuffer buf(128);
761 if( '"' == vec[token][0] )
762 buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
763 else
764 buf.append( vec[token] );
765 token ++;
767 if( token < vec.size() )
769 if( vec[token] == "." )
771 buf.append( vec[token] );
772 token ++;
773 if( token < vec.size() )
775 if( '"' == vec[token][0] )
776 buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
777 else
778 buf.append( vec[token] );
779 token ++;
784 ret = buf.makeStringAndClear();
785 // now got my table candidate
787 if( token < vec.size() && vec[token] == "(" )
789 // whoops, it is a function
790 ret.clear();
792 else
794 if( token < vec.size() )
796 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
797 vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) )
799 token += 2; // skip alias
803 if( token < vec.size() )
805 if( vec[token] == "," )
807 // whoops, multiple tables are used
808 ret.clear();
810 else
812 static const char * forbiddenKeywords[] =
813 { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr };
814 for( int i = 0 ; forbiddenKeywords[i] ; i ++ )
816 size_t nKeywordLen = strlen(forbiddenKeywords[i]);
817 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
818 vec[token].pData->buffer, vec[token].pData->length,
819 forbiddenKeywords[i], nKeywordLen,
820 nKeywordLen ) )
822 // whoops, it is a join
823 ret.clear();
831 return ret;
835 OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings)
837 return (PQserverVersion( settings->pConnection ) < 80000)?
838 OUString("pg_attrdef.adsrc"):
839 OUString("pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid, true)");
842 css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str )
844 css::uno::Sequence< sal_Int32 > ret;
845 const sal_Int32 strlen = str.getLength();
846 if( str.getLength() > 1 )
848 sal_Int32 start = 0;
849 sal_uInt32 c;
850 for (;;)
852 c = str.iterateCodePoints(&start);
853 if (!iswspace(c))
854 break;
855 if ( start == strlen)
856 return ret;
858 if ( c != L'{' )
859 return ret;
860 for (;;)
862 c = str.iterateCodePoints(&start);
863 if ( !iswspace(c) )
864 break;
865 if ( start == strlen)
866 return ret;
868 if ( c == L'}' )
869 return ret;
871 std::vector< sal_Int32 > vec;
874 OUStringBuffer digits;
877 if(!iswspace(c))
878 break;
879 if ( start == strlen)
880 return ret;
881 c=str.iterateCodePoints(&start);
882 } while ( c );
885 if (!iswdigit(c))
886 break;
887 if ( start == strlen)
888 return ret;
889 digits.append(OUString(&c, 1));
890 c = str.iterateCodePoints(&start);
891 } while ( c );
892 vec.push_back( digits.makeStringAndClear().toInt32() );
895 if(!iswspace(c))
896 break;
897 if ( start == strlen)
898 return ret;
899 c = str.iterateCodePoints(&start);
900 } while ( c );
901 if ( c == L'}' )
902 break;
903 if ( str.iterateCodePoints(&start) != L',' )
904 return ret;
905 if ( start == strlen)
906 return ret;
907 } while( true );
908 // vec is guaranteed non-empty
909 assert(vec.size() > 0);
910 ret = css::uno::Sequence< sal_Int32 > ( vec.data() , vec.size() );
912 return ret;
916 Sequence< OUString > convertMappedIntArray2StringArray(
917 const Int2StringMap &map, const Sequence< sal_Int32 > &intArray )
919 Sequence< OUString > ret( intArray.getLength() );
920 for( int i = 0; i < intArray.getLength() ; i ++ )
922 Int2StringMap::const_iterator ii = map.find( intArray[i] );
923 if( ii != map.end() )
924 ret[i] = ii->second;
926 return ret;
930 OUString sqltype2string( const Reference< XPropertySet > & desc )
932 OUStringBuffer typeName;
933 typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) );
934 sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION );
936 if( precision )
938 switch( extractIntProperty( desc, getStatics().TYPE ) )
940 case css::sdbc::DataType::VARBINARY:
941 case css::sdbc::DataType::VARCHAR:
942 case css::sdbc::DataType::CHAR:
944 typeName.append( "(" );
945 typeName.append( precision );
946 typeName.append( ")" );
947 break;
949 case css::sdbc::DataType::DECIMAL:
950 case css::sdbc::DataType::NUMERIC:
952 typeName.append( "(" );
953 typeName.append( precision );
954 typeName.append( "," );
955 typeName.append( extractIntProperty( desc, getStatics().SCALE ) );
956 typeName.append( ")" );
957 break;
959 default:
960 ((void)0);
963 return typeName.makeStringAndClear();
967 static void keyType2String( OUStringBuffer & buf, sal_Int32 keyType )
969 if( css::sdbc::KeyRule::CASCADE == keyType )
971 buf.append( "CASCADE " );
973 else if( css::sdbc::KeyRule::RESTRICT == keyType )
975 buf.append( "RESTRICT " );
977 else if( css::sdbc::KeyRule::SET_DEFAULT == keyType )
979 buf.append( "SET DEFAULT " );
981 else if( css::sdbc::KeyRule::SET_NULL == keyType )
983 buf.append( "SET NULL " );
985 else //if( css::sdbc::KeyRule::NO_ACTION == keyType )
987 buf.append( "NO ACTION " );
991 void bufferKey2TableConstraint(
992 OUStringBuffer &buf, const Reference< XPropertySet > &key, ConnectionSettings *settings )
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 )
1002 buf.append( "UNIQUE( " );
1004 else if( type == css::sdbcx::KeyType::PRIMARY )
1006 buf.append( "PRIMARY KEY( " );
1008 else if( type == css::sdbcx::KeyType::FOREIGN )
1010 foreign = true;
1011 buf.append( "FOREIGN KEY( " );
1014 Reference< XColumnsSupplier > columns( key, UNO_QUERY );
1015 if( columns.is() )
1017 Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY );
1018 if( colEnumAccess.is() )
1020 Reference< XEnumeration > colEnum = colEnumAccess->createEnumeration();
1021 bool first = true;
1022 while(colEnum.is() && colEnum->hasMoreElements() )
1024 if( first )
1026 first = false;
1028 else
1030 buf.append( ", " );
1032 Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
1033 bufferQuoteIdentifier(buf, extractStringProperty( keyColumn, st.NAME ), settings );
1037 buf.append( ") " );
1039 if( !foreign )
1040 return;
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() )
1049 Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY);
1050 if( colEnumAccess.is() )
1052 buf.append( " (" );
1053 Reference< XEnumeration > colEnum(colEnumAccess->createEnumeration());
1054 bool first = true;
1055 while(colEnum.is() && colEnum->hasMoreElements() )
1057 if( first )
1059 first = false;
1061 else
1063 buf.append( ", " );
1065 Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW );
1066 bufferQuoteIdentifier(
1067 buf, extractStringProperty( keyColumn, st.RELATED_COLUMN ), settings );
1069 buf.append( ") " );
1073 buf.append( "ON DELETE " );
1074 keyType2String( buf, deleteRule );
1075 buf.append( " ON UPDATE " );
1076 keyType2String( buf, updateRule );
1080 void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery )
1082 std::vector< OString > vec;
1083 tokenizeSQL( lastQuery, vec );
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;
1092 int n = 2;
1094 // printf( "1a\n" );
1095 // skip table name
1096 if( vec[n+1].equalsIgnoreAsciiCase( "." ) )
1098 n +=2;
1101 n ++;
1102 if( !vec[n].equalsIgnoreAsciiCase( "(" ) )
1103 return;
1105 std::vector< OString> names;
1106 // printf( "2\n" );
1107 // extract names
1108 n++;
1109 while( nSize > n && ! vec[n].equalsIgnoreAsciiCase( ")" ) )
1111 names.push_back( vec[n] );
1112 if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase( "," ) )
1114 n ++;
1116 n++;
1118 n++;
1120 // now read the values
1121 if( !(nSize > n +1 && vec[n].equalsIgnoreAsciiCase("VALUES") &&
1122 vec[n+1].equalsIgnoreAsciiCase( "(" )) )
1123 return;
1125 n +=2;
1126 // printf( "3\n" );
1127 for (auto& name : names)
1129 if (n >= nSize)
1130 break;
1132 map[name] = vec[n];
1133 if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase(",") )
1135 n ++;
1137 n++;
1141 OUString querySingleValue(
1142 const css::uno::Reference< css::sdbc::XConnection > &connection,
1143 const OUString &query )
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;
1156 // copied from connectivity/source/dbtools, can't use the function directly
1157 bool implSetObject( const Reference< XParameters >& _rxParameters,
1158 const sal_Int32 _nColumnIndex, const Any& _rValue)
1160 bool bSuccessfullyReRouted = true;
1161 switch (_rValue.getValueTypeClass())
1163 case css::uno::TypeClass_HYPER:
1165 _rxParameters->setLong( _nColumnIndex, sal_Int64(0) );
1167 break;
1169 case css::uno::TypeClass_VOID:
1170 _rxParameters->setNull(_nColumnIndex,css::sdbc::DataType::VARCHAR);
1171 break;
1173 case css::uno::TypeClass_STRING:
1174 _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue));
1175 break;
1177 case css::uno::TypeClass_BOOLEAN:
1178 _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue));
1179 break;
1181 case css::uno::TypeClass_BYTE:
1182 _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue));
1183 break;
1185 case css::uno::TypeClass_UNSIGNED_SHORT:
1186 case css::uno::TypeClass_SHORT:
1187 _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue));
1188 break;
1190 case css::uno::TypeClass_CHAR:
1191 _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue)));
1192 break;
1194 case css::uno::TypeClass_UNSIGNED_LONG:
1195 case css::uno::TypeClass_LONG:
1196 _rxParameters->setInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue));
1197 break;
1199 case css::uno::TypeClass_FLOAT:
1200 _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue));
1201 break;
1203 case css::uno::TypeClass_DOUBLE:
1204 _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue));
1205 break;
1207 case css::uno::TypeClass_SEQUENCE:
1208 if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue))
1210 _rxParameters->setBytes(_nColumnIndex, *s);
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;
1226 case css::uno::TypeClass_INTERFACE:
1228 Reference< css::io::XInputStream > xStream;
1229 if (_rValue >>= xStream)
1231 _rValue >>= xStream;
1232 _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
1233 break;
1235 [[fallthrough]];
1237 default:
1238 bSuccessfullyReRouted = false;
1242 return bSuccessfullyReRouted;
1247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */