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 <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"
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
)
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 );
109 int len
= PQescapeStringConn(settings
->pConnection
, const_cast<char*>(strbuf
.getStr()), y
.getStr() , y
.getLength(), &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
),
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
)
133 bufferEscapeConstant( buf
, value
, settings
);
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
)
148 bufferQuoteConstant( buf
, str
, settings
);
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
),
170 buf
.append( OStringToOUString( cstr
, RTL_TEXTENCODING_UTF8
) );
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
);
185 ibufferQuoteIdentifier(buf
, table
, settings
);
188 void bufferQuoteQualifiedIdentifier(
189 OUStringBuffer
& buf
,
190 const OUString
&schema
,
191 const OUString
&table
,
193 ConnectionSettings
*settings
)
195 ibufferQuoteIdentifier(buf
, schema
, settings
);
197 ibufferQuoteIdentifier(buf
, table
, settings
);
199 ibufferQuoteIdentifier(buf
, col
, settings
);
203 OUString
extractStringProperty(
204 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
207 descriptor
->getPropertyValue( name
) >>= value
;
211 bool extractBoolProperty(
212 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
215 descriptor
->getPropertyValue( name
) >>= value
;
219 sal_Int32
extractIntProperty(
220 const Reference
< XPropertySet
> & descriptor
, const OUString
&name
)
223 descriptor
->getPropertyValue( name
) >>= ret
;
227 void disposeObject( const css::uno::Reference
< css::uno::XInterface
> & r
)
229 Reference
< XComponent
> comp( r
, UNO_QUERY
);
234 void disposeNoThrow( const css::uno::Reference
< css::uno::XInterface
> & r
)
240 catch( SQLException
& )
247 Reference
< XConnection
> extractConnectionFromStatement( const Reference
< XInterface
> & stmt
)
249 Reference
< XConnection
> ret
;
251 Reference
< css::sdbc::XStatement
> owner( stmt
, UNO_QUERY
);
253 ret
= owner
->getConnection();
256 Reference
< css::sdbc::XPreparedStatement
> myowner( stmt
, UNO_QUERY
);
258 ret
= myowner
->getConnection();
261 "PQSDBC: Couldn't retrieve connection from statement",
262 Reference
< XInterface
> () , OUString(), 0 , css::uno::Any() );
269 DisposeGuard::DisposeGuard( const Reference
< XInterface
> & r
)
273 DisposeGuard::~DisposeGuard()
278 TransactionGuard::TransactionGuard( const Reference
< XStatement
> &stmt
)
282 m_stmt
->executeUpdate( getStatics().BEGIN
);
285 void TransactionGuard::commit()
287 m_stmt
->executeUpdate( getStatics().COMMIT
);
291 void TransactionGuard::executeUpdate( const OUString
& sql
)
293 m_stmt
->executeUpdate( sql
);
296 TransactionGuard::~TransactionGuard()
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
)
321 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
323 if( sql
.matchIgnoreAsciiCase("insert", i
) )
326 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
327 if( sql
.matchIgnoreAsciiCase("into", i
) )
330 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { 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
++; }
340 while (i
< sql
.getLength() && isWhitespace(sql
[i
])) { i
++; }
343 // the second part of the table name does not use quotes
350 // end quoted name, ok
356 if( isWhitespace( sql
[i
] ) )
358 // found the end of an unquoted name
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() );
372 static bool isOperator( char c
)
403 void splitSQL( const OString
& sql
, std::vector
< OString
> &vec
)
405 int length
= sql
.getLength();
408 bool singleQuote
= false;
409 bool doubleQuote
= false;
411 for( ; i
< length
; i
++ )
418 vec
.push_back( OString( &sql
.getStr()[start
], i
-start
+1 ) );
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
433 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
+1 ) );
434 start
= i
+ 1; // leave single quotes !
442 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
448 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
455 vec
.push_back( OString( &sql
.getStr()[start
] , i
- start
) );
457 // for( i = 0 ; i < vec.size() ; i ++ )
458 // printf( "%s!" , vec[i].getStr() );
463 void tokenizeSQL( const OString
& sql
, std::vector
< OString
> &vec
)
465 int length
= sql
.getLength();
468 bool singleQuote
= false;
469 bool doubleQuote
= false;
471 for( ; i
< length
; i
++ )
478 vec
.push_back( OString( &sql
.getStr()[start
], i
-start
) );
483 else if( singleQuote
)
487 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
+1 ) );
488 start
= i
+ 1; // leave single quotes !
497 start
= i
+1; // skip double quotes !
502 start
= i
; // leave single quotes
504 else if( isWhitespace( c
) )
507 start
++; // skip additional whitespace
510 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
514 else if( ',' == c
|| isOperator( c
) || '(' == c
|| ')' == c
)
517 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
518 vec
.push_back( OString( &sql
.getStr()[i
], 1 ) );
523 if( ( i
> start
&& sql
[start
] >= '0' && sql
[start
] <= '9' ) ||
524 ( i
== start
&& i
> 1 && isWhitespace( sql
[i
-1] ) ) )
526 // ignore, is a literal
531 vec
.push_back( OString( &sql
.getStr()[start
], i
- start
) );
532 vec
.push_back( OString( "." ) );
539 vec
.push_back( OString( &sql
.getStr()[start
] , i
- start
) );
541 // for( i = 0 ; i < vec.size() ; i ++ )
542 // printf( "%s!" , vec[i].getStr() );
547 void splitConcatenatedIdentifier( const OUString
& source
, OUString
*first
, OUString
*second
)
549 std::vector
< OString
> vec
;
550 tokenizeSQL( OUStringToOString( source
, RTL_TEXTENCODING_UTF8
), vec
);
555 *second
= OStringToOUString( vec
[0], RTL_TEXTENCODING_UTF8
);
558 *first
= OStringToOUString( vec
[0], RTL_TEXTENCODING_UTF8
);
559 *second
= OStringToOUString( vec
[2], RTL_TEXTENCODING_UTF8
);
562 SAL_WARN("connectivity.postgresql",
563 "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: "
568 OUString
array2String( const css::uno::Sequence
< Any
> &seq
)
570 OUStringBuffer
buf(128);
571 int len
= seq
.getLength();
573 for( int i
= 0 ; i
< len
; i
++ )
580 int strLength
= element
.getLength();
582 for( int j
= 0 ; j
< strLength
; j
++ )
584 sal_Unicode c
= element
[j
];
585 if( c
== '\\' || c
== '"' || c
== '{' || c
== '}' )
594 return buf
.makeStringAndClear();
598 std::vector
< Any
> parseArray( const OUString
& str
)
600 int len
= str
.getLength();
601 bool doubleQuote
= false;
605 OUStringBuffer current
;
606 std::vector
<Any
> elements
;
607 bool doubleQuotedValue
= false;
610 sal_Unicode c
= str
[i
];
611 sal_Unicode cnext
= str
[i
+1];
617 current
.append( cnext
);
622 doubleQuotedValue
= true; // signal, that there was an empty element
639 "error during array parsing, didn't expect a } at position "
640 + OUString::number(i
) + " ('" + str
+ "')",
641 Reference
< XInterface
> (), OUString(), 1, Any() );
645 if( !current
.isEmpty() || doubleQuotedValue
)
646 elements
.push_back( makeAny( current
.makeStringAndClear() ) );
655 // if( current.getLength() != 0 )
657 // OUStringBuffer buf;
658 // buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
660 // buf.append( " ('" );
661 // buf.append( str );
662 // buf.append( "')" );
663 // throw SDBCException(
664 // buf.makeStringAndClear(),
665 // Reference< XInterface > (), 1, Any() );
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
690 std::vector
< sal_Int32
> parseIntArray( const OUString
& str
)
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 ));
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 ));
706 void fillAttnum2attnameMap(
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 "
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
);
727 map
[ xRow
->getInt(2) ] = xRow
->getString(1);
731 OString
extractSingleTableFromSelect( const std::vector
< OString
> &vec
)
735 if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
736 vec
[0].pData
->buffer
, vec
[0].pData
->length
, "select" , 6 , 6 ) )
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 ) )
751 if( token
< vec
.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
752 vec
[token
].pData
->buffer
, vec
[token
].pData
->length
, "only " , 4 , 4 ) )
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 );
764 buf
.append( vec
[token
] );
767 if( token
< vec
.size() )
769 if( vec
[token
] == "." )
771 buf
.append( vec
[token
] );
773 if( token
< vec
.size() )
775 if( '"' == vec
[token
][0] )
776 buf
.append( &(vec
[token
].getStr()[1]) , vec
[token
].getLength() -2 );
778 buf
.append( vec
[token
] );
784 ret
= buf
.makeStringAndClear();
785 // now got my table candidate
787 if( token
< vec
.size() && vec
[token
] == "(" )
789 // whoops, it is a function
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
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
,
822 // whoops, it is a join
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 )
852 c
= str
.iterateCodePoints(&start
);
855 if ( start
== strlen
)
862 c
= str
.iterateCodePoints(&start
);
865 if ( start
== strlen
)
871 std::vector
< sal_Int32
> vec
;
874 OUStringBuffer digits
;
879 if ( start
== strlen
)
881 c
=str
.iterateCodePoints(&start
);
887 if ( start
== strlen
)
889 digits
.append(OUString(&c
, 1));
890 c
= str
.iterateCodePoints(&start
);
892 vec
.push_back( digits
.makeStringAndClear().toInt32() );
897 if ( start
== strlen
)
899 c
= str
.iterateCodePoints(&start
);
903 if ( str
.iterateCodePoints(&start
) != L
',' )
905 if ( start
== strlen
)
908 // vec is guaranteed non-empty
909 assert(vec
.size() > 0);
910 ret
= css::uno::Sequence
< sal_Int32
> ( vec
.data() , vec
.size() );
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() )
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
);
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( ")" );
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( ")" );
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: */