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,
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"
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 );
110 int len
= PQescapeStringConn(settings
->pConnection
, const_cast<char*>(strbuf
.getStr()), y
.getStr() , y
.getLength(), &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
),
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
)
134 bufferEscapeConstant( buf
, value
, settings
);
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
)
149 bufferQuoteConstant( buf
, str
, settings
);
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
),
171 buf
.append( OStringToOUString( cstr
, RTL_TEXTENCODING_UTF8
) );
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
);
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
);
198 ibufferQuoteIdentifier(buf
, table
, settings
);
200 ibufferQuoteIdentifier(buf
, col
, settings
);
204 OUString
extractStringProperty(
205 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
208 descriptor
->getPropertyValue( name
) >>= value
;
212 bool extractBoolProperty(
213 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
216 descriptor
->getPropertyValue( name
) >>= value
;
220 sal_Int32
extractIntProperty(
221 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
224 descriptor
->getPropertyValue( name
) >>= ret
;
228 void disposeObject( const css::uno::Reference
< css::uno::XInterface
> & r
)
230 Reference
< XComponent
> comp( r
, UNO_QUERY
);
235 void disposeNoThrow( const css::uno::Reference
< css::uno::XInterface
> & r
)
241 catch( SQLException
& )
248 Reference
< XConnection
> extractConnectionFromStatement( const Reference
< XInterface
> & stmt
)
250 Reference
< XConnection
> ret
;
252 Reference
< css::sdbc::XStatement
> owner( stmt
, UNO_QUERY
);
254 ret
= owner
->getConnection();
257 Reference
< css::sdbc::XPreparedStatement
> myowner( stmt
, UNO_QUERY
);
259 ret
= myowner
->getConnection();
262 u
"PQSDBC: Couldn't retrieve connection from statement"_ustr
,
263 Reference
< XInterface
> () , OUString(), 0 , css::uno::Any() );
270 DisposeGuard::DisposeGuard( const Reference
< XInterface
> & r
)
274 DisposeGuard::~DisposeGuard()
279 TransactionGuard::TransactionGuard( const Reference
< XStatement
> &stmt
)
283 m_stmt
->executeUpdate( getStatics().BEGIN
);
286 void TransactionGuard::commit()
288 m_stmt
->executeUpdate( getStatics().COMMIT
);
292 void TransactionGuard::executeUpdate( const OUString
& sql
)
294 m_stmt
->executeUpdate( sql
);
297 TransactionGuard::~TransactionGuard()
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
)
322 while (i
< sql
.size() && isWhitespace(sql
[i
])) { i
++; }
324 if( o3tl::matchIgnoreAsciiCase(sql
, u
"insert", i
) )
327 while (i
< sql
.size() && isWhitespace(sql
[i
])) { i
++; }
328 if( o3tl::matchIgnoreAsciiCase(sql
, u
"into", i
) )
331 while (i
< sql
.size() && isWhitespace(sql
[i
])) { 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
++; }
341 while (i
< sql
.size() && isWhitespace(sql
[i
])) { i
++; }
344 // the second part of the table name does not use quotes
351 // end quoted name, ok
357 if( isWhitespace( sql
[i
] ) )
359 // found the end of an unquoted name
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() );
373 static bool isOperator( char c
)
404 void splitSQL( const OString
& sql
, std::vector
< OString
> &vec
)
406 int length
= sql
.getLength();
409 bool singleQuote
= false;
410 bool doubleQuote
= false;
412 for( ; i
< length
; i
++ )
419 vec
.emplace_back( &sql
.getStr()[start
], i
-start
+1 );
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
434 vec
.emplace_back( &sql
.getStr()[start
], i
- start
+1 );
435 start
= i
+ 1; // leave single quotes !
443 vec
.emplace_back( &sql
.getStr()[start
], i
- start
);
449 vec
.emplace_back( &sql
.getStr()[start
], i
- start
);
456 vec
.emplace_back( &sql
.getStr()[start
] , i
- start
);
458 // for( i = 0 ; i < vec.size() ; i ++ )
459 // printf( "%s!" , vec[i].getStr() );
464 void tokenizeSQL( const OString
& sql
, std::vector
< OString
> &vec
)
466 int length
= sql
.getLength();
469 bool singleQuote
= false;
470 bool doubleQuote
= false;
472 for( ; i
< length
; i
++ )
479 vec
.emplace_back( &sql
.getStr()[start
], i
-start
);
484 else if( singleQuote
)
488 vec
.emplace_back( &sql
.getStr()[start
], i
- start
+1 );
489 start
= i
+ 1; // leave single quotes !
498 start
= i
+1; // skip double quotes !
503 start
= i
; // leave single quotes
505 else if( isWhitespace( c
) )
508 start
++; // skip additional whitespace
511 vec
.emplace_back( &sql
.getStr()[start
], i
- start
);
515 else if( ',' == c
|| isOperator( c
) || '(' == c
|| ')' == c
)
518 vec
.emplace_back( &sql
.getStr()[start
], i
- start
);
519 vec
.emplace_back( &sql
.getStr()[i
], 1 );
524 if( ( i
> start
&& sql
[start
] >= '0' && sql
[start
] <= '9' ) ||
525 ( i
== start
&& i
> 1 && isWhitespace( sql
[i
-1] ) ) )
527 // ignore, is a literal
532 vec
.emplace_back( &sql
.getStr()[start
], i
- start
);
533 vec
.emplace_back( "." );
540 vec
.emplace_back( &sql
.getStr()[start
] , i
- start
);
542 // for( i = 0 ; i < vec.size() ; i ++ )
543 // printf( "%s!" , vec[i].getStr() );
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
);
556 *second
= OStringToOUString( vec
[0], RTL_TEXTENCODING_UTF8
);
559 *first
= OStringToOUString( vec
[0], RTL_TEXTENCODING_UTF8
);
560 *second
= OStringToOUString( vec
[2], RTL_TEXTENCODING_UTF8
);
563 SAL_WARN("connectivity.postgresql",
564 "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: "
569 OUString
array2String( const css::uno::Sequence
< Any
> &seq
)
571 OUStringBuffer
buf(128);
572 int len
= seq
.getLength();
574 for( int i
= 0 ; i
< len
; i
++ )
581 int strLength
= element
.getLength();
583 for( int j
= 0 ; j
< strLength
; j
++ )
585 sal_Unicode c
= element
[j
];
586 if( c
== '\\' || c
== '"' || c
== '{' || c
== '}' )
595 return buf
.makeStringAndClear();
599 std::vector
< Any
> parseArray( std::u16string_view str
)
601 size_t len
= str
.size();
602 bool doubleQuote
= false;
606 OUStringBuffer current
;
607 std::vector
<Any
> elements
;
608 bool doubleQuotedValue
= false;
611 sal_Unicode c
= str
[i
];
612 sal_Unicode cnext
= str
[i
+1];
618 current
.append( cnext
);
623 doubleQuotedValue
= true; // signal, that there was an empty element
640 "error during array parsing, didn't expect a } at position "
641 + OUString::number(i
) + " ('" + str
+ "')",
642 Reference
< XInterface
> (), OUString(), 1, Any() );
646 if( !current
.isEmpty() || doubleQuotedValue
)
647 elements
.emplace_back( current
.makeStringAndClear() );
656 // if( current.getLength() != 0 )
658 // OUStringBuffer buf;
659 // buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
661 // buf.append( " ('" );
662 // buf.append( str );
663 // buf.append( "')" );
664 // throw SDBCException(
665 // buf.makeStringAndClear(),
666 // Reference< XInterface > (), 1, Any() );
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
691 std::vector
< sal_Int32
> parseIntArray( const OUString
& str
)
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 ));
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 ));
707 void fillAttnum2attnameMap(
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 "
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
);
728 map
[ xRow
->getInt(2) ] = xRow
->getString(1);
732 OString
extractSingleTableFromSelect( const std::vector
< OString
> &vec
)
736 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
737 vec
[0].pData
->buffer
, vec
[0].pData
->length
, "select" , 6 , 6 ) )
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 ) )
752 if( token
< vec
.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
753 vec
[token
].pData
->buffer
, vec
[token
].pData
->length
, "only " , 4 , 4 ) )
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 );
765 buf
.append( vec
[token
] );
768 if( token
< vec
.size() )
770 if( vec
[token
] == "." )
772 buf
.append( vec
[token
] );
774 if( token
< vec
.size() )
776 if( '"' == vec
[token
][0] )
777 buf
.append( &(vec
[token
].getStr()[1]) , vec
[token
].getLength() -2 );
779 buf
.append( vec
[token
] );
785 ret
= buf
.makeStringAndClear();
786 // now got my table candidate
788 if( token
< vec
.size() && vec
[token
] == "(" )
790 // whoops, it is a function
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
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
,
823 // whoops, it is a join
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();
853 c
= o3tl::iterateCodePoints(str
, &start
);
856 if ( start
== strlen
)
863 c
= o3tl::iterateCodePoints(str
, &start
);
866 if ( start
== strlen
)
872 std::vector
< sal_Int32
> vec
;
875 OUStringBuffer digits
;
880 if ( start
== strlen
)
882 c
= o3tl::iterateCodePoints(str
, &start
);
888 if ( start
== strlen
)
890 digits
.append(OUString(&c
, 1));
891 c
= o3tl::iterateCodePoints(str
, &start
);
893 vec
.push_back( o3tl::toInt32(digits
) );
898 if ( start
== strlen
)
900 c
= o3tl::iterateCodePoints(str
, &start
);
904 if ( o3tl::iterateCodePoints(str
, &start
) != L
',' )
906 if ( start
== strlen
)
909 // vec is guaranteed non-empty
910 assert(vec
.size() > 0);
911 ret
= css::uno::Sequence
< sal_Int32
> ( vec
.data() , vec
.size() );
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
;
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
);
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
) + ")" );
949 case css::sdbc::DataType::DECIMAL
:
950 case css::sdbc::DataType::NUMERIC
:
953 + OUString::number(precision
)
955 + OUString::number(extractIntProperty( desc
, getStatics().SCALE
))
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
)
1011 buf
.append( "FOREIGN KEY( " );
1014 Reference
< XColumnsSupplier
> columns( key
, UNO_QUERY
);
1017 Reference
< XEnumerationAccess
> colEnumAccess( columns
->getColumns(), UNO_QUERY
);
1018 if( colEnumAccess
.is() )
1020 Reference
< XEnumeration
> colEnum
= colEnumAccess
->createEnumeration();
1022 while(colEnum
.is() && colEnum
->hasMoreElements() )
1032 Reference
< XPropertySet
> keyColumn( colEnum
->nextElement(), UNO_QUERY_THROW
);
1033 bufferQuoteIdentifier(buf
, extractStringProperty( keyColumn
, st
.NAME
), settings
);
1042 buf
.append( "REFERENCES " );
1045 splitConcatenatedIdentifier( referencedTable
, &schema
, &tableName
);
1046 bufferQuoteQualifiedIdentifier(buf
, schema
, tableName
, settings
);
1049 Reference
< XEnumerationAccess
> colEnumAccess( columns
->getColumns(), UNO_QUERY
);
1050 if( colEnumAccess
.is() )
1053 Reference
< XEnumeration
> colEnum(colEnumAccess
->createEnumeration());
1055 while(colEnum
.is() && colEnum
->hasMoreElements() )
1065 Reference
< XPropertySet
> keyColumn( colEnum
->nextElement(), UNO_QUERY_THROW
);
1066 bufferQuoteIdentifier(
1067 buf
, extractStringProperty( keyColumn
, st
.RELATED_COLUMN
), settings
);
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 );
1088 vec
[0].equalsIgnoreAsciiCase( "insert" ) &&
1089 vec
[1].equalsIgnoreAsciiCase( "into" )) )
1094 // printf( "1a\n" );
1096 if( vec
[n
+1].equalsIgnoreAsciiCase( "." ) )
1102 if( !vec
[n
].equalsIgnoreAsciiCase( "(" ) )
1105 std::vector
< OString
> names
;
1109 while( nSize
> n
&& ! vec
[n
].equalsIgnoreAsciiCase( ")" ) )
1111 names
.push_back( vec
[n
] );
1112 if( nSize
> n
+1 && vec
[n
+1].equalsIgnoreAsciiCase( "," ) )
1120 // now read the values
1121 if( !(nSize
> n
+1 && vec
[n
].equalsIgnoreAsciiCase("VALUES") &&
1122 vec
[n
+1].equalsIgnoreAsciiCase( "(" )) )
1127 for (auto& name
: names
)
1133 if( nSize
> n
+1 && vec
[n
+1].equalsIgnoreAsciiCase(",") )
1141 OUString
querySingleValue(
1142 const css::uno::Reference
< css::sdbc::XConnection
> &connection
,
1143 const OUString
&query
)
1146 Reference
< XStatement
> stmt
= connection
->createStatement();
1147 DisposeGuard
guard( stmt
);
1148 Reference
< XResultSet
> rs
= stmt
->executeQuery( query
);
1149 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
1151 ret
= xRow
->getString( 1 );
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) );
1169 case css::uno::TypeClass_VOID
:
1170 _rxParameters
->setNull(_nColumnIndex
,css::sdbc::DataType::VARCHAR
);
1173 case css::uno::TypeClass_STRING
:
1174 _rxParameters
->setString(_nColumnIndex
, *o3tl::forceAccess
<OUString
>(_rValue
));
1177 case css::uno::TypeClass_BOOLEAN
:
1178 _rxParameters
->setBoolean(_nColumnIndex
, *o3tl::forceAccess
<bool>(_rValue
));
1181 case css::uno::TypeClass_BYTE
:
1182 _rxParameters
->setByte(_nColumnIndex
, *o3tl::forceAccess
<sal_Int8
>(_rValue
));
1185 case css::uno::TypeClass_UNSIGNED_SHORT
:
1186 case css::uno::TypeClass_SHORT
:
1187 _rxParameters
->setShort(_nColumnIndex
, *o3tl::forceAccess
<sal_Int16
>(_rValue
));
1190 case css::uno::TypeClass_CHAR
:
1191 _rxParameters
->setString(_nColumnIndex
, OUString(*o3tl::forceAccess
<sal_Unicode
>(_rValue
)));
1194 case css::uno::TypeClass_UNSIGNED_LONG
:
1195 case css::uno::TypeClass_LONG
:
1196 _rxParameters
->setInt(_nColumnIndex
, *o3tl::forceAccess
<sal_Int32
>(_rValue
));
1199 case css::uno::TypeClass_FLOAT
:
1200 _rxParameters
->setFloat(_nColumnIndex
, *o3tl::forceAccess
<float>(_rValue
));
1203 case css::uno::TypeClass_DOUBLE
:
1204 _rxParameters
->setDouble(_nColumnIndex
, *o3tl::forceAccess
<double>(_rValue
));
1207 case css::uno::TypeClass_SEQUENCE
:
1208 if (auto s
= o3tl::tryAccess
<Sequence
< sal_Int8
>>(_rValue
))
1210 _rxParameters
->setBytes(_nColumnIndex
, *s
);
1213 bSuccessfullyReRouted
= false;
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
);
1223 bSuccessfullyReRouted
= false;
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());
1238 bSuccessfullyReRouted
= false;
1242 return bSuccessfullyReRouted
;
1247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */