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