tdf#150789 - FILEOPEN PPTX: fix text in SmartArt vertically off
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_tools.cxx
blobb6e5d28f938efe77d09dc06392190f4fada43410
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 <o3tl/string_view.hxx>
41 #include <rtl/strbuf.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <sal/log.hxx>
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>
56 #include "pq_tools.hxx"
57 #include "pq_statics.hxx"
59 #include <libpq-fe.h>
60 #include <string.h>
61 #include <string_view>
63 using com::sun::star::beans::XPropertySet;
65 using com::sun::star::lang::XComponent;
67 using com::sun::star::sdbc::SQLException;
68 using com::sun::star::sdbc::XStatement;
69 using com::sun::star::sdbc::XConnection;
70 using com::sun::star::sdbc::XPreparedStatement;
71 using com::sun::star::sdbc::XParameters;
72 using com::sun::star::sdbc::XResultSet;
73 using com::sun::star::sdbc::XRow;
75 using com::sun::star::sdbcx::XColumnsSupplier;
77 using com::sun::star::uno::UNO_QUERY;
78 using com::sun::star::uno::UNO_QUERY_THROW;
79 using com::sun::star::uno::Reference;
80 using com::sun::star::uno::Sequence;
81 using com::sun::star::uno::XInterface;
82 using com::sun::star::uno::Any;
84 using com::sun::star::container::XEnumeration;
85 using com::sun::star::container::XEnumerationAccess;
87 namespace pq_sdbc_driver
90 OUString concatQualified( std::u16string_view a, std::u16string_view b)
92 return OUString::Concat(a) + "." + b;
95 static OString iOUStringToOString( std::u16string_view str, ConnectionSettings const *settings) {
96 OSL_ENSURE(settings, "pgsql-sdbc: OUStringToOString got NULL settings");
97 return rtl::OUStringToOString( str, ConnectionSettings::encoding );
100 OString OUStringToOString( std::u16string_view str, ConnectionSettings const *settings) {
101 return iOUStringToOString( str, settings );
104 void bufferEscapeConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
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 )
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 u"22018"_ustr,
123 Any());
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 ) );
131 static void ibufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
133 buf.append( "'" );
134 bufferEscapeConstant( buf, value, settings );
135 buf.append( "'" );
138 void bufferQuoteConstant( OUStringBuffer & buf, std::u16string_view value, ConnectionSettings *settings )
140 return ibufferQuoteConstant( buf, value, settings );
143 void bufferQuoteAnyConstant( OUStringBuffer & buf, const Any &val, ConnectionSettings *settings )
145 if( val.hasValue() )
147 OUString str;
148 val >>= str;
149 bufferQuoteConstant( buf, str, settings );
151 else
152 buf.append( "NULL" );
155 static void ibufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings )
157 assert(settings && "pgsql-sdbc: bufferQuoteIdentifier got NULL settings");
159 OString y = iOUStringToOString( toQuote, settings );
160 char *cstr = PQescapeIdentifier(settings->pConnection, y.getStr(), y.getLength());
161 if ( cstr == nullptr )
163 char *errstr = PQerrorMessage(settings->pConnection);
164 // Implementation-defined SQLACCESS error
165 throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding),
166 nullptr,
167 u"22018"_ustr,
169 Any());
171 buf.append( OStringToOUString( cstr, RTL_TEXTENCODING_UTF8 ) );
172 PQfreemem( cstr );
175 void bufferQuoteIdentifier( OUStringBuffer & buf, std::u16string_view toQuote, ConnectionSettings *settings )
177 return ibufferQuoteIdentifier(buf, toQuote, settings);
181 void bufferQuoteQualifiedIdentifier(
182 OUStringBuffer & buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings )
184 ibufferQuoteIdentifier(buf, schema, settings);
185 buf.append( "." );
186 ibufferQuoteIdentifier(buf, table, settings);
189 void bufferQuoteQualifiedIdentifier(
190 OUStringBuffer & buf,
191 std::u16string_view schema,
192 std::u16string_view table,
193 std::u16string_view col,
194 ConnectionSettings *settings)
196 ibufferQuoteIdentifier(buf, schema, settings);
197 buf.append( "." );
198 ibufferQuoteIdentifier(buf, table, settings);
199 buf.append( "." );
200 ibufferQuoteIdentifier(buf, col, settings);
204 OUString extractStringProperty(
205 const Reference< XPropertySet > & descriptor, const OUString &name )
207 OUString value;
208 descriptor->getPropertyValue( name ) >>= value;
209 return value;
212 bool extractBoolProperty(
213 const Reference< XPropertySet > & descriptor, const OUString &name )
215 bool value = false;
216 descriptor->getPropertyValue( name ) >>= value;
217 return value;
220 sal_Int32 extractIntProperty(
221 const Reference< XPropertySet > & descriptor, const OUString &name )
223 sal_Int32 ret = 0;
224 descriptor->getPropertyValue( name ) >>= ret;
225 return ret;
228 void disposeObject( const css::uno::Reference< css::uno::XInterface > & r )
230 Reference< XComponent > comp( r, UNO_QUERY );
231 if( comp.is() )
232 comp->dispose();
235 void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r )
239 disposeObject( r );
241 catch( SQLException & )
243 // ignore this
248 Reference< XConnection > extractConnectionFromStatement( const Reference< XInterface > & stmt )
250 Reference< XConnection > ret;
252 Reference< css::sdbc::XStatement > owner( stmt, UNO_QUERY );
253 if( owner.is() )
254 ret = owner->getConnection();
255 else
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 u"PQSDBC: Couldn't retrieve connection from statement"_ustr,
263 Reference< XInterface > () , OUString(), 0 , css::uno::Any() );
266 return ret;
270 DisposeGuard::DisposeGuard( const Reference< XInterface > & r )
271 : d( r )
274 DisposeGuard::~DisposeGuard()
276 disposeNoThrow( d );
279 TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt )
280 : m_stmt( stmt ),
281 m_commited( false )
283 m_stmt->executeUpdate( getStatics().BEGIN );
286 void TransactionGuard::commit()
288 m_stmt->executeUpdate( getStatics().COMMIT );
289 m_commited = true;
292 void TransactionGuard::executeUpdate( const OUString & sql )
294 m_stmt->executeUpdate( sql );
297 TransactionGuard::~TransactionGuard()
301 if( ! m_commited )
302 m_stmt->executeUpdate( getStatics().ROLLBACK );
304 catch( css::uno::Exception & )
306 // ignore, we are within a dtor
309 disposeNoThrow( m_stmt );
313 bool isWhitespace( sal_Unicode c )
315 return ' ' == c || 9 == c || 10 == c || 13 == c;
318 OUString extractTableFromInsert( std::u16string_view sql )
320 OUString ret;
321 size_t i = 0;
322 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
324 if( o3tl::matchIgnoreAsciiCase(sql, u"insert", i) )
326 i += 6;
327 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
328 if( o3tl::matchIgnoreAsciiCase(sql, u"into", i) )
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 ++ )
336 if( quote && sql[i] == '"' )
338 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
339 if( '.' == sql[i] )
341 while (i < sql.size() && isWhitespace(sql[i])) { i++; }
342 if( '"' == sql[i] )
344 // the second part of the table name does not use quotes
345 // parse on
346 quote = false;
349 else
351 // end quoted name, ok
352 break;
355 else
357 if( isWhitespace( sql[i] ) )
359 // found the end of an unquoted name
360 break;
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() );
369 return ret;
373 static bool isOperator( char c )
375 bool ret;
376 switch(c)
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;
401 return ret;
404 void splitSQL( const OString & sql, std::vector< OString > &vec )
406 int length = sql.getLength();
408 int i = 0;
409 bool singleQuote = false;
410 bool doubleQuote = false;
411 int start = 0;
412 for( ; i < length ; i ++ )
414 char c = sql[i];
415 if( doubleQuote )
417 if( '"' == c )
419 vec.emplace_back( &sql.getStr()[start], i-start+1 );
420 start = i + 1;
421 doubleQuote = false;
424 else if( singleQuote )
426 if( '\'' == c && (i+1) < length && '\'' == sql[i+1] )
428 // two subsequent single quotes within a quoted string
429 // mean a single quote within the string
430 i ++;
432 else if( '\'' == c )
434 vec.emplace_back( &sql.getStr()[start], i - start +1 );
435 start = i + 1; // leave single quotes !
436 singleQuote = false;
439 else
441 if( '"' == c )
443 vec.emplace_back( &sql.getStr()[start], i - start );
444 doubleQuote = true;
445 start = i;
447 else if( '\'' == c )
449 vec.emplace_back( &sql.getStr()[start], i - start );
450 singleQuote = true;
451 start = i;
455 if( start < i )
456 vec.emplace_back( &sql.getStr()[start] , i - start );
458 // for( i = 0 ; i < vec.size() ; i ++ )
459 // printf( "%s!" , vec[i].getStr() );
460 // printf( "\n" );
464 void tokenizeSQL( const OString & sql, std::vector< OString > &vec )
466 int length = sql.getLength();
468 int i = 0;
469 bool singleQuote = false;
470 bool doubleQuote = false;
471 int start = 0;
472 for( ; i < length ; i ++ )
474 char c = sql[i];
475 if( doubleQuote )
477 if( '"' == c )
479 vec.emplace_back( &sql.getStr()[start], i-start );
480 start = i + 1;
481 doubleQuote = false;
484 else if( singleQuote )
486 if( '\'' == c )
488 vec.emplace_back( &sql.getStr()[start], i - start +1 );
489 start = i + 1; // leave single quotes !
490 singleQuote = false;
493 else
495 if( '"' == c )
497 doubleQuote = true;
498 start = i +1; // skip double quotes !
500 else if( '\'' == c )
502 singleQuote = true;
503 start = i; // leave single quotes
505 else if( isWhitespace( c ) )
507 if( i == start )
508 start ++; // skip additional whitespace
509 else
511 vec.emplace_back( &sql.getStr()[start], i - start );
512 start = i +1;
515 else if( ',' == c || isOperator( c ) || '(' == c || ')' == c )
517 if( i - start )
518 vec.emplace_back( &sql.getStr()[start], i - start );
519 vec.emplace_back( &sql.getStr()[i], 1 );
520 start = i + 1;
522 else if( '.' == c )
524 if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) ||
525 ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) )
527 // ignore, is a literal
529 else
531 if( i - start )
532 vec.emplace_back( &sql.getStr()[start], i - start );
533 vec.emplace_back( "." );
534 start = i + 1;
539 if( start < i )
540 vec.emplace_back( &sql.getStr()[start] , i - start );
542 // for( i = 0 ; i < vec.size() ; i ++ )
543 // printf( "%s!" , vec[i].getStr() );
544 // printf( "\n" );
548 void splitConcatenatedIdentifier( std::u16string_view source, OUString *first, OUString *second)
550 std::vector< OString > vec;
551 tokenizeSQL( rtl::OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec );
552 switch (vec.size())
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());
569 OUString array2String( const css::uno::Sequence< Any > &seq )
571 OUStringBuffer buf(128);
572 int len = seq.getLength();
573 buf.append( "{" );
574 for( int i = 0 ; i < len ; i ++ )
576 OUString element;
577 seq[i] >>= element;
579 if( i > 0 )
580 buf.append( "," );
581 int strLength = element.getLength();
582 buf.append( "\"" );
583 for( int j = 0 ; j < strLength ; j ++ )
585 sal_Unicode c = element[j];
586 if( c == '\\' || c == '"' || c == '{' || c == '}' )
588 buf.append( "\\" );
590 buf.append( c );
592 buf.append( "\"" );
594 buf.append( "}" );
595 return buf.makeStringAndClear();
599 std::vector< Any > parseArray( std::u16string_view str )
601 size_t len = str.size();
602 bool doubleQuote = false;
603 int brackets = 0;
604 size_t i = 0;
606 OUStringBuffer current;
607 std::vector<Any> elements;
608 bool doubleQuotedValue = false;
609 while( i < len )
611 sal_Unicode c = str[i];
612 sal_Unicode cnext = str[i+1];
613 if( doubleQuote )
615 if( '\\' == c )
617 i ++;
618 current.append( cnext );
620 else if( '"' == c )
622 doubleQuote = false;
623 doubleQuotedValue = true; // signal, that there was an empty element
625 else
627 current.append( c );
630 else if ( '{' == c )
632 brackets ++;
634 else if( '}' == c )
636 brackets --;
637 if( brackets < 0 )
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() );
644 if( brackets == 0 )
646 if( !current.isEmpty() || doubleQuotedValue )
647 elements.emplace_back( current.makeStringAndClear() );
649 else
651 current.append( c );
654 else if( '"' == c )
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 // }
673 else if( ',' == c && brackets == 1)
675 doubleQuotedValue = false;
676 elements.emplace_back( current.makeStringAndClear() );
678 else if( isWhitespace( c ) )
680 // ignore whitespace without quotes
682 else
684 current.append( c );
686 i++;
688 return elements;
691 std::vector< sal_Int32 > parseIntArray( const OUString & str )
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) )
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;
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;
707 void fillAttnum2attnameMap(
708 Int2StringMap &map,
709 const Reference< css::sdbc::XConnection > &conn,
710 const OUString &schema,
711 const OUString &table )
713 Reference< XPreparedStatement > prep = conn->prepareStatement(
714 u"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=?"_ustr );
720 Reference< XParameters > paras( prep, UNO_QUERY_THROW );
721 paras->setString( 1 , table );
722 paras->setString( 2 , schema );
723 Reference< XResultSet > rs = prep->executeQuery();
725 Reference< XRow > xRow( rs , UNO_QUERY_THROW );
726 while( rs->next() )
728 map[ xRow->getInt(2) ] = xRow->getString(1);
732 OString extractSingleTableFromSelect( const std::vector< OString > &vec )
734 OString ret;
736 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
737 vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) )
739 size_t token = 0;
741 for( token = 1; token < vec.size() ; token ++ )
743 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
744 vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) )
746 // found from
747 break;
750 token ++;
752 if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
753 vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) )
755 token ++;
758 if( token < vec.size() && vec[token] != "(" )
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 ++;
768 if( token < vec.size() )
770 if( vec[token] == "." )
772 buf.append( vec[token] );
773 token ++;
774 if( token < vec.size() )
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 ++;
785 ret = buf.makeStringAndClear();
786 // now got my table candidate
788 if( token < vec.size() && vec[token] == "(" )
790 // whoops, it is a function
791 ret.clear();
793 else
795 if( token < vec.size() )
797 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
798 vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) )
800 token += 2; // skip alias
804 if( token < vec.size() )
806 if( vec[token] == "," )
808 // whoops, multiple tables are used
809 ret.clear();
811 else
813 static const char * forbiddenKeywords[] =
814 { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr };
815 for( int i = 0 ; forbiddenKeywords[i] ; i ++ )
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 ) )
823 // whoops, it is a join
824 ret.clear();
832 return ret;
836 OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings)
838 return (PQserverVersion( settings->pConnection ) < 80000)?
839 u"pg_attrdef.adsrc"_ustr:
840 u"pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid, true)"_ustr;
843 css::uno::Sequence< sal_Int32 > string2intarray( std::u16string_view str )
845 css::uno::Sequence< sal_Int32 > ret;
846 const sal_Int32 strlen = str.size();
847 if( strlen > 1 )
849 sal_Int32 start = 0;
850 sal_uInt32 c;
851 for (;;)
853 c = o3tl::iterateCodePoints(str, &start);
854 if (!iswspace(c))
855 break;
856 if ( start == strlen)
857 return ret;
859 if ( c != L'{' )
860 return ret;
861 for (;;)
863 c = o3tl::iterateCodePoints(str, &start);
864 if ( !iswspace(c) )
865 break;
866 if ( start == strlen)
867 return ret;
869 if ( c == L'}' )
870 return ret;
872 std::vector< sal_Int32 > vec;
875 OUStringBuffer digits;
878 if(!iswspace(c))
879 break;
880 if ( start == strlen)
881 return ret;
882 c = o3tl::iterateCodePoints(str, &start);
883 } while ( c );
886 if (!iswdigit(c))
887 break;
888 if ( start == strlen)
889 return ret;
890 digits.append(OUString(&c, 1));
891 c = o3tl::iterateCodePoints(str, &start);
892 } while ( c );
893 vec.push_back( o3tl::toInt32(digits) );
896 if(!iswspace(c))
897 break;
898 if ( start == strlen)
899 return ret;
900 c = o3tl::iterateCodePoints(str, &start);
901 } while ( c );
902 if ( c == L'}' )
903 break;
904 if ( o3tl::iterateCodePoints(str, &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() );
913 return ret;
917 Sequence< OUString > convertMappedIntArray2StringArray(
918 const Int2StringMap &map, const Sequence< sal_Int32 > &intArray )
920 Sequence< OUString > ret( intArray.getLength() );
921 auto retRange = asNonConstRange(ret);
922 for( int i = 0; i < intArray.getLength() ; i ++ )
924 Int2StringMap::const_iterator ii = map.find( intArray[i] );
925 if( ii != map.end() )
926 retRange[i] = ii->second;
928 return ret;
932 OUString sqltype2string( const Reference< XPropertySet > & desc )
934 OUStringBuffer typeName;
935 typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) );
936 sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION );
938 if( precision )
940 switch( extractIntProperty( desc, getStatics().TYPE ) )
942 case css::sdbc::DataType::VARBINARY:
943 case css::sdbc::DataType::VARCHAR:
944 case css::sdbc::DataType::CHAR:
946 typeName.append( "(" + OUString::number(precision) + ")" );
947 break;
949 case css::sdbc::DataType::DECIMAL:
950 case css::sdbc::DataType::NUMERIC:
952 typeName.append( "("
953 + OUString::number(precision)
954 + ","
955 + OUString::number(extractIntProperty( desc, getStatics().SCALE ))
956 + ")" );
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: */