Files
libreoffice/connectivity/source/drivers/postgresql/pq_tools.cxx
2011-11-17 21:15:14 +01:00

1234 lines
38 KiB
C++

#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
#include <com/sun/star/sdbc/XParameters.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/KeyRule.hpp>
#include <com/sun/star/sdbcx/KeyType.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include "pq_xcontainer.hxx"
#include "pq_tools.hxx"
#include "pq_statics.hxx"
#include <libpq-fe.h>
#include <string.h>
using rtl::OUString;
using rtl::OUStringBuffer;
using com::sun::star::beans::XPropertySet;
using com::sun::star::lang::XComponent;
using com::sun::star::sdbc::SQLException;
using com::sun::star::sdbc::XStatement;
using com::sun::star::sdbc::XConnection;
using com::sun::star::sdbc::XPreparedStatement;
using com::sun::star::sdbc::XParameters;
using com::sun::star::sdbc::XResultSet;
using com::sun::star::sdbc::XRow;
using com::sun::star::sdbcx::XColumnsSupplier;
using com::sun::star::uno::UNO_QUERY;
using com::sun::star::uno::Reference;
using com::sun::star::uno::Sequence;
using com::sun::star::uno::XInterface;
using com::sun::star::uno::Any;
using com::sun::star::uno::makeAny;
using com::sun::star::container::XEnumeration;
using com::sun::star::container::XEnumerationAccess;
namespace pq_sdbc_driver
{
#define ASCII_STR(x) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
rtl::OUString date2String( const com::sun::star::util::Date & x )
{
char buffer[64];
sprintf( buffer, "%d-%02d-%02d", x.Year, x.Month, x.Day );
return OUString::createFromAscii( buffer );
}
com::sun::star::util::Date string2Date( const rtl::OUString &date )
{
// Format: Year-Month-Day
com::sun::star::util::Date ret;
ret.Year = (sal_Int32) rtl_ustr_toInt32( date.pData->buffer, 10 );
int index = date.indexOf( '-' );
if( index >= 0 )
{
ret.Month = (sal_Int32)rtl_ustr_toInt32( &(date.pData->buffer[ index+1]), 10 );
int start = index;
index = date.indexOf( '-', start+1 );
if( index >= 0 )
{
ret.Day = (sal_Int32)rtl_ustr_toInt32( &date.pData->buffer[index+1], 10 );
}
}
return ret;
}
rtl::OUString time2String( const com::sun::star::util::Time & x )
{
char buffer[64];
sprintf( buffer, "%02d:%02d:%02d.%02d", x.Hours, x.Minutes, x.Seconds, x.HundredthSeconds );
return OUString::createFromAscii( buffer );
}
com::sun::star::util::Time string2Time( const rtl::OUString & time )
{
com::sun::star::util::Time ret;
sal_Unicode temp[4];
temp[0] = time[0];
temp[1] = time[1];
temp[2] = 0;
ret.Hours = (sal_Int32)rtl_ustr_toInt32( temp , 10 );
temp[0] = time[3];
temp[1] = time[4];
ret.Minutes = (sal_Int32)rtl_ustr_toInt32( temp , 10 );
temp[0] = time[6];
temp[1] = time[7];
ret.Seconds = (sal_Int32)rtl_ustr_toInt32( temp , 10 );
if( time.getLength() >9 )
{
ret.HundredthSeconds = (sal_Int32)rtl_ustr_toInt32( &time[9] , 10 );
}
return ret;
}
rtl::OUString dateTime2String( const com::sun::star::util::DateTime & x )
{
char buffer[128];
sprintf( buffer, "%d-%02d-%02d %02d:%02d:%02d.%02d",
x.Year, x.Month, x.Day,
x.Hours, x.Minutes, x.Seconds, x.HundredthSeconds );
return OUString::createFromAscii( buffer );
}
com::sun::star::util::DateTime string2DateTime( const rtl::OUString & dateTime )
{
int space = dateTime.indexOf( ' ' );
com::sun::star::util::DateTime ret;
if( space >= 0 )
{
com::sun::star::util::Date date ( string2Date( OUString( dateTime.getStr(), space ) ) );
com::sun::star::util::Time time( string2Time( OUString( dateTime.getStr() + space +1 ) ) );
ret.Day = date.Day;
ret.Month = date.Month;
ret.Year = date.Year;
ret.Hours = time.Hours;
ret.Minutes = time.Minutes;
ret.Seconds = time.Seconds;
ret.HundredthSeconds = time.HundredthSeconds;
}
return ret;
}
rtl::OUString concatQualified( const rtl::OUString & a, const rtl::OUString &b)
{
rtl::OUStringBuffer buf( a.getLength() + 2 + b.getLength() );
buf.append( a );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "." ) );
buf.append( b );
return buf.makeStringAndClear();
}
void bufferEscapeConstant( rtl::OUStringBuffer & buf, const rtl::OUString & value, sal_Int32 encoding )
{
rtl::OString y = rtl::OUStringToOString( value, encoding );
rtl::OStringBuffer strbuf( y.getLength() * 2 + 2 );
int len = PQescapeString( ((char*)strbuf.getStr()), y.getStr() , y.getLength() );
strbuf.setLength( len );
buf.append( rtl::OStringToOUString( strbuf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
}
void bufferQuoteConstant( rtl::OUStringBuffer & buf, const rtl::OUString & value, sal_Int32 encoding )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " '" ) );
bufferEscapeConstant( buf, value, encoding );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "' " ) );
}
void bufferQuoteQualifiedIdentifier(
rtl::OUStringBuffer & buf, const rtl::OUString &schema, const rtl::OUString &name)
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" \"" ) );
buf.append(schema);
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\".\"" ) );
buf.append( name );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\" " ) );
}
void bufferQuoteQualifiedIdentifier(
rtl::OUStringBuffer & buf,
const rtl::OUString &schema,
const rtl::OUString &name,
const rtl::OUString &col)
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" \"" ) );
buf.append(schema);
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\".\"" ) );
buf.append( name );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\".\"" ) );
buf.append( col );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\" " ) );
}
void bufferQuoteIdentifier( rtl::OUStringBuffer & buf, const rtl::OUString &toQuote )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " \"") );
buf.append( toQuote );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\" " ) );
}
rtl::OUString extractStringProperty(
const Reference< XPropertySet > & descriptor, const rtl::OUString &name )
{
rtl::OUString value;
descriptor->getPropertyValue( name ) >>= value;
return value;
}
sal_Bool extractBoolProperty(
const Reference< XPropertySet > & descriptor, const rtl::OUString &name )
{
sal_Bool value = sal_False;
descriptor->getPropertyValue( name ) >>= value;
return value;
}
sal_Int32 extractIntProperty(
const Reference< XPropertySet > & descriptor, const rtl::OUString &name )
{
sal_Int32 ret = 0;
descriptor->getPropertyValue( name ) >>= ret;
return ret;
}
void disposeObject( const com::sun::star::uno::Reference< com::sun::star::uno::XInterface > & r )
{
Reference< XComponent > comp( r, UNO_QUERY );
if( comp.is() )
comp->dispose();
}
void disposeNoThrow( const com::sun::star::uno::Reference< com::sun::star::uno::XInterface > & r )
{
try
{
disposeObject( r );
}
catch( SQLException & e )
{
// ignore this
}
}
void rollbackNoThrow( const com::sun::star::uno::Reference< com::sun::star::sdbc::XConnection > & r )
{
try
{
Reference< XStatement > stmt = r->createStatement();
stmt->executeUpdate( getStatics().ROLLBACK );
}
catch( SQLException & )
{
// ignore this
}
}
Reference< XConnection > extractConnectionFromStatement( const Reference< XInterface > & stmt )
{
Reference< XConnection > ret;
Reference< com::sun::star::sdbc::XStatement > owner( stmt, UNO_QUERY );
if( owner.is() )
ret = owner->getConnection();
else
{
Reference< com::sun::star::sdbc::XPreparedStatement > myowner( stmt, UNO_QUERY );
if( myowner.is() )
ret = myowner->getConnection();
if( ! ret.is() )
throw SQLException(
ASCII_STR( "PQSDBC: Couldn't retrieve connection from statement" ),
Reference< XInterface > () , rtl::OUString(), 0 , com::sun::star::uno::Any() );
}
return ret;
}
DisposeGuard::DisposeGuard( const Reference< XInterface > & r )
: d( r )
{}
DisposeGuard::~DisposeGuard()
{
disposeNoThrow( d );
}
TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt )
: m_stmt( stmt ),
m_commited( sal_False )
{
m_stmt->executeUpdate( getStatics().BEGIN );
}
void TransactionGuard::commit()
{
m_stmt->executeUpdate( getStatics().COMMIT );
m_commited = sal_True;
}
void TransactionGuard::executeUpdate( const rtl::OUString & sql )
{
m_stmt->executeUpdate( sql );
}
TransactionGuard::~TransactionGuard()
{
try
{
if( ! m_commited )
m_stmt->executeUpdate( getStatics().ROLLBACK );
}
catch( com::sun::star::uno::Exception & e )
{
// ignore, we are within a dtor
}
disposeNoThrow( m_stmt );
}
bool isWhitespace( sal_Unicode c )
{
return ' ' == c || 9 == c || 10 == c || 13 == c;
}
::rtl::OUString extractTableFromInsert( const rtl::OUString & sql )
{
rtl::OUString ret;
int i = 0;
for( ; i < sql.getLength() && isWhitespace(sql[i]) ; i++ );
if( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(
&sql[i], sql.getLength() - i, "insert" , 6 ) )
{
i += 6;
for( ; i < sql.getLength() && isWhitespace(sql[i]) ; i++ );
if( 0 == rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(
&sql[i], sql.getLength() - i, "into" , 4 ) )
{
i +=4;
for( ; i < sql.getLength() && isWhitespace(sql[i]) ; i++ );
int start = i;
bool quote = (sql[i] == '"');
for( i++ ; i < sql.getLength() ; i ++ )
{
if( quote && sql[i] == '"' )
{
for( i++ ; i < sql.getLength() && isWhitespace(sql[i]) ; i++ );
if( '.' == sql[i] )
{
for( i++ ; i < sql.getLength() && isWhitespace(sql[i]) ; i++ );
if( '"' == sql[i] )
{
// the second part of the table name does not use quotes
// parse on
quote = 0;
}
}
else
{
// end quoted name, ok
break;
}
}
else
{
if( isWhitespace( sql[i] ) )
{
// found the end of an unquoted name
break;
}
}
}
ret = rtl::OUString( &sql[start], i - start ).trim();
// printf( "pq_statement: parsed table name %s from insert\n" ,
// OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() );
}
}
return ret;
}
static bool isOperator( char c )
{
bool ret;
switch(c)
{
case '+':
case '-':
case '*':
case '/':
case '<':
case '>':
case '=':
case '~':
case '!':
case '@':
case '#':
case '%':
case '^':
case '&':
case '|':
case '`':
case '?':
case '$':
ret = true;
default:
ret = false;
}
return ret;
}
void splitSQL( const rtl::OString & sql, OStringVector &vec )
{
int length = sql.getLength();
int i = 0;
bool singleQuote = false;
bool doubleQuote = false;
int start = 0;
for( ; i < length ; i ++ )
{
char c = sql[i];
if( doubleQuote )
{
if( '"' == c )
{
vec.push_back( rtl::OString( &sql[start], i-start+1 ) );
start = i + 1;
doubleQuote = false;
}
}
else if( singleQuote )
{
if( '\'' == c && '\'' == sql[i+1] )
{
// two subsequent single quotes within a quoted string
// mean a single quote within the string
i ++;
}
else if( '\'' == c )
{
vec.push_back( rtl::OString( &sql[start], i - start +1 ) );
start = i + 1; // leave single quotes !
singleQuote = false;
}
}
else
{
if( '"' == c )
{
vec.push_back( rtl::OString( &sql[start], i - start ) );
doubleQuote = true;
start = i;
}
else if( '\'' == c )
{
vec.push_back( rtl::OString( &sql[start], i - start ) );
singleQuote = true;
start = i;
}
}
}
if( start < i )
vec.push_back( rtl::OString( &sql[start] , i - start ) );
// for( i = 0 ; i < vec.size() ; i ++ )
// printf( "%s!" , vec[i].getStr() );
// printf( "\n" );
}
void tokenizeSQL( const rtl::OString & sql, OStringVector &vec )
{
int length = sql.getLength();
int i = 0;
bool singleQuote = false;
bool doubleQuote = false;
int start = 0;
for( ; i < length ; i ++ )
{
char c = sql[i];
if( doubleQuote )
{
if( '"' == c )
{
vec.push_back( rtl::OString( &sql[start], i-start ) );
start = i + 1;
doubleQuote = false;
}
}
else if( singleQuote )
{
if( '\'' == c )
{
vec.push_back( rtl::OString( &sql[start], i - start +1 ) );
start = i + 1; // leave single quotes !
singleQuote = false;
}
}
else
{
if( '"' == c )
{
doubleQuote = true;
start = i +1; // skip double quotes !
}
else if( '\'' == c )
{
singleQuote = true;
start = i; // leave single quotes
}
else if( isWhitespace( c ) )
{
if( i == start )
start ++; // skip additional whitespace
else
{
vec.push_back( rtl::OString( &sql[start], i - start ) );
start = i +1;
}
}
else if( ',' == c || isOperator( c ) || '(' == c || ')' == c )
{
if( i - start )
vec.push_back( rtl::OString( &sql[start], i - start ) );
vec.push_back( rtl::OString( &sql[i], 1 ) );
start = i + 1;
}
else if( '.' == c )
{
if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) ||
( i == start && i > 1 && isWhitespace( sql[i-1] ) ) )
{
// ignore, is a literal
}
else
{
if( i - start )
vec.push_back( rtl::OString( &sql[start], i - start ) );
vec.push_back( rtl::OString( RTL_CONSTASCII_STRINGPARAM( "." ) ) );
start = i + 1;
}
}
}
}
if( start < i )
vec.push_back( rtl::OString( &sql[start] , i - start ) );
// for( i = 0 ; i < vec.size() ; i ++ )
// printf( "%s!" , vec[i].getStr() );
// printf( "\n" );
}
void splitConcatenatedIdentifier( const rtl::OUString & source, rtl::OUString *first, rtl::OUString *second)
{
OStringVector vec;
tokenizeSQL( rtl::OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec );
if( vec.size() == 3 )
{
*first = rtl::OStringToOUString( vec[0] , RTL_TEXTENCODING_UTF8 );
*second = rtl::OStringToOUString( vec[2], RTL_TEXTENCODING_UTF8 );
}
}
typedef std::vector< sal_Int32 , Allocator< sal_Int32 > > IntVector;
rtl::OUString array2String( const com::sun::star::uno::Sequence< Any > &seq )
{
OUStringBuffer buf(128);
int len = seq.getLength();
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "{" ) );
for( int i = 0 ; i < len ; i ++ )
{
OUString element;
seq[i] >>= element;
if( i > 0 )
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(",") );
int strLength = element.getLength();
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\"") );
for( int j = 0 ; j < strLength ; j ++ )
{
sal_Unicode c = element[j];
if( c == '\\' || c == '"' || c == '{' || c == '}' )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\\" ) );
}
buf.append( c );
}
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "\"" ) );
}
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "}" ) );
return buf.makeStringAndClear();
}
typedef
std::vector
<
com::sun::star::uno::Any,
Allocator< com::sun::star::uno::Any >
> AnyVector;
com::sun::star::uno::Sequence< Any > parseArray( const rtl::OUString & str ) throw( SQLException )
{
com::sun::star::uno::Sequence< Any > ret;
int len = str.getLength();
bool doubleQuote = false;
int brackets = 0;
int i = 0;
OUStringBuffer current;
AnyVector elements;
bool doubleQuotedValue = false;
while( i < len )
{
sal_Unicode c = str[i];
sal_Unicode cnext = str[i+1];
if( doubleQuote )
{
if( '\\' == c )
{
i ++;
current.append( cnext );
}
else if( '"' == c )
{
doubleQuote = false;
doubleQuotedValue = true; // signal, that there was an empty element
}
else
{
current.append( c );
}
}
else if ( '{' == c )
{
brackets ++;
}
else if( '}' == c )
{
brackets --;
if( brackets < 0 )
{
OUStringBuffer buf;
buf.appendAscii( "error during array parsing, didn't expect a } at position " );
buf.append( (sal_Int32) i );
buf.appendAscii( " ('" );
buf.append( str );
buf.appendAscii( "')" );
throw SQLException(
buf.makeStringAndClear(),
Reference< XInterface > (), rtl::OUString(), 1, Any() );
}
if( brackets == 0 )
{
if( current.getLength() > 0 || doubleQuotedValue )
elements.push_back( makeAny( current.makeStringAndClear() ) );
}
else
{
current.append( c );
}
}
else if( '"' == c )
{
// if( current.getLength() != 0 )
// {
// OUStringBuffer buf;
// buf.appendAscii( "error during array parsing, didn't expect a \" at position " );
// buf.append( i );
// buf.append( " ('" );
// buf.append( str );
// buf.append( "')" );
// throw SDBCException(
// buf.makeStringAndClear(),
// Reference< XInterface > (), 1, Any() );
// }
// else
// {
doubleQuote = true;
// }
}
else if( ',' == c && brackets == 1)
{
doubleQuotedValue = false;
elements.push_back( makeAny( current.makeStringAndClear() ) );
}
else if( isWhitespace( c ) )
{
// ignore whitespace without quotes
}
else
{
current.append( c );
}
i++;
}
ret = Sequence< Any > ( &elements[0] , elements.size() );
return ret;
}
com::sun::star::uno::Sequence< sal_Int32 > parseIntArray( const ::rtl::OUString & str )
{
sal_Int32 start = 0;
IntVector vec;
// printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
for( sal_Int32 i = str.indexOf( ' ' ) ; i != -1 ; i = str.indexOf( ' ', start) )
{
vec.push_back( (sal_Int32)rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
start = i + 1;
}
vec.push_back( (sal_Int32)rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) );
// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 ));
return Sequence< sal_Int32 > ( &vec[0], vec.size() );
}
void fillAttnum2attnameMap(
Int2StringMap &map,
const Reference< com::sun::star::sdbc::XConnection > &conn,
const rtl::OUString &schema,
const rtl::OUString &table )
{
Reference< XPreparedStatement > prep = conn->prepareStatement(
ASCII_STR( "SELECT attname,attnum "
"FROM pg_attribute "
"INNER JOIN pg_class ON attrelid = pg_class.oid "
"INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
"WHERE relname=? AND nspname=?" ) );
Reference< XParameters > paras( prep, UNO_QUERY );
paras->setString( 1 , table );
paras->setString( 2 , schema );
Reference< XResultSet > rs = prep->executeQuery();
Reference< XRow > xRow( rs , UNO_QUERY );
while( rs->next() )
{
map[ xRow->getInt(2) ] = xRow->getString(1);
}
}
::rtl::OString extractSingleTableFromSelect( const OStringVector &vec )
{
rtl::OString ret;
int token = 0;
if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) )
{
for( token = 1; token < vec.size() ; token ++ )
{
if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) )
{
// found from
break;
}
}
token ++;
if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) )
{
token ++;
}
if( token < vec.size() && rtl_str_compare_WithLength(
vec[token].getStr(), vec[token].getLength(),
RTL_CONSTASCII_STRINGPARAM("(") ) )
{
// it is a table or a function name
rtl::OStringBuffer buf(128);
if( '"' == vec[token][0] )
buf.append( &(vec[token][1]) , vec[token].getLength() -2 );
else
buf.append( vec[token] );
token ++;
if( token < vec.size() )
{
if( rtl_str_compare_WithLength(
vec[token].getStr(), vec[token].getLength(),
RTL_CONSTASCII_STRINGPARAM( "." ) ) == 0 )
{
buf.append( vec[token] );
token ++;
if( token < vec.size() )
{
if( '"' == vec[token][0] )
buf.append( &(vec[token][1]) , vec[token].getLength() -2 );
else
buf.append( vec[token] );
token ++;
}
}
}
ret = buf.makeStringAndClear();
// now got my table candidate
if( token < vec.size() && rtl_str_compare_WithLength(
vec[token].getStr(), vec[token].getLength(),
RTL_CONSTASCII_STRINGPARAM( "(" ) ) == 0 )
{
// whoops, it is a function
ret = rtl::OString();
}
else
{
if( token < vec.size() )
{
if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) )
{
token += 2; // skip alias
}
}
if( token < vec.size() )
{
if( rtl_str_compare_WithLength(
vec[token].getStr(), vec[token].getLength(),
RTL_CONSTASCII_STRINGPARAM( "," ) ) == 0 )
{
// whoops, multiple tables are used
ret = rtl::OString();
}
else
{
static const char * forbiddenKeywords[] =
{ "join", "natural", "outer", "inner", "left", "right", "full" , 0 };
for( int i = 0 ; forbiddenKeywords[i] ; i ++ )
{
if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
vec[token].pData->buffer, vec[token].pData->length,
forbiddenKeywords[i], strlen(forbiddenKeywords[i]),
strlen(forbiddenKeywords[i]) ) )
{
// whoops, it is a join
ret = rtl::OString();
}
}
}
}
}
}
}
return ret;
}
com::sun::star::uno::Sequence< sal_Int32 > string2intarray( const ::rtl::OUString & str )
{
com::sun::star::uno::Sequence< sal_Int32 > ret;
if( str.getLength() > 1 && '{' == str[0] )
{
std::vector< sal_Int32, Allocator< sal_Int32 > > vec;
sal_Int32 start = 0;
do
{
start ++;
vec.push_back( (sal_Int32)rtl_ustr_toInt32( &str[start], 10 ) );
start = str.indexOf( ',' , start );
} while( start != -1 );
ret = com::sun::star::uno::Sequence< sal_Int32 > ( &vec[0] , vec.size() );
}
return ret;
}
Sequence< rtl::OUString > convertMappedIntArray2StringArray(
const Int2StringMap &map, const Sequence< sal_Int32 > &intArray )
{
Sequence< ::rtl::OUString > ret( intArray.getLength() );
for( int i = 0; i < intArray.getLength() ; i ++ )
{
Int2StringMap::const_iterator ii = map.find( intArray[i] );
if( ii != map.end() )
ret[i] = ii->second;
}
return ret;
}
::rtl::OUString sqltype2string( const Reference< XPropertySet > & desc )
{
OUStringBuffer typeName;
typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) );
sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION );
if( precision )
{
switch( extractIntProperty( desc, getStatics().TYPE ) )
{
case com::sun::star::sdbc::DataType::VARBINARY:
case com::sun::star::sdbc::DataType::VARCHAR:
case com::sun::star::sdbc::DataType::CHAR:
{
typeName.appendAscii( RTL_CONSTASCII_STRINGPARAM( "(" ) );
typeName.append( precision );
typeName.appendAscii( RTL_CONSTASCII_STRINGPARAM( ")" ) );
break;
}
case com::sun::star::sdbc::DataType::DECIMAL:
case com::sun::star::sdbc::DataType::NUMERIC:
{
typeName.appendAscii( RTL_CONSTASCII_STRINGPARAM( "(" ) );
typeName.append( precision );
typeName.appendAscii( RTL_CONSTASCII_STRINGPARAM( "," ) );
typeName.append( extractIntProperty( desc, getStatics().SCALE ) );
typeName.appendAscii( RTL_CONSTASCII_STRINGPARAM( ")" ) );
break;
}
default:
((void)0);
}
}
return typeName.makeStringAndClear();
}
static void keyType2String( OUStringBuffer & buf, sal_Int32 keyType )
{
if( com::sun::star::sdbc::KeyRule::CASCADE == keyType )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "CASCADE " ) );
}
else if( com::sun::star::sdbc::KeyRule::RESTRICT == keyType )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "RESTRICT " ) );
}
else if( com::sun::star::sdbc::KeyRule::SET_DEFAULT == keyType )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "SET DEFAULT " ) );
}
else if( com::sun::star::sdbc::KeyRule::SET_NULL == keyType )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "SET NULL " ) );
}
else //if( com::sun::star::sdbc::KeyRule::NO_ACTION == keyType )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "NO ACTION " ) );
}
}
void bufferKey2TableConstraint(
OUStringBuffer &buf, const Reference< XPropertySet > &key )
{
Statics &st = getStatics();
sal_Int32 type = extractIntProperty( key, st.TYPE );
OUString referencedTable = extractStringProperty( key, st.REFERENCED_TABLE );
sal_Int32 updateRule = extractIntProperty( key, st.UPDATE_RULE );
sal_Int32 deleteRule = extractIntProperty( key, st.DELETE_RULE );
bool foreign = false;
if( type == com::sun::star::sdbcx::KeyType::UNIQUE )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "UNIQUE( " ) );
}
else if( type == com::sun::star::sdbcx::KeyType::PRIMARY )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "PRIMARY KEY( " ) );
}
else if( type == com::sun::star::sdbcx::KeyType::FOREIGN )
{
foreign = true;
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "FOREIGN KEY( " ) );
}
Reference< XColumnsSupplier > columns( key, UNO_QUERY );
if( columns.is() )
{
Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY );
if( colEnumAccess.is() )
{
Reference< XEnumeration > colEnum = colEnumAccess->createEnumeration();
bool first = true;
while(colEnum.is() && colEnum->hasMoreElements() )
{
if( first )
{
first = false;
}
else
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
}
Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY );
bufferQuoteIdentifier(buf, extractStringProperty( keyColumn, st.NAME ) );
}
}
}
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ") " ));
if( foreign )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "REFERENCES " ) );
OUString schema;
OUString tableName;
splitConcatenatedIdentifier( referencedTable, &schema, &tableName );
bufferQuoteQualifiedIdentifier(buf , schema, tableName);
if(columns.is() )
{
Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY);
if( colEnumAccess.is() )
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " (" ) );
Reference< XEnumeration > colEnum(colEnumAccess->createEnumeration());
bool first = true;
while(colEnum.is() && colEnum->hasMoreElements() )
{
if( first )
{
first = false;
}
else
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
}
Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY );
bufferQuoteIdentifier(
buf, extractStringProperty( keyColumn, st.RELATED_COLUMN ) );
}
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ") " ) );
}
}
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "ON DELETE " ) );
keyType2String( buf, deleteRule );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " ON UPDATE " ) );
keyType2String( buf, updateRule );
}
}
static bool equalsIgnoreCase( const rtl::OString & str, const char *str2, int length2 )
{
return 0 == rtl_str_compareIgnoreAsciiCase_WithLength(
str.pData->buffer, str.pData->length, str2, length2 );
}
void extractNameValuePairsFromInsert( String2StringMap & map, const rtl::OString & lastQuery )
{
OStringVector vec;
tokenizeSQL( lastQuery, vec );
int nSize = vec.size();
// printf( "1 %d\n", nSize );
if( nSize > 6 &&
equalsIgnoreCase( vec[0] , RTL_CONSTASCII_STRINGPARAM( "insert" ) ) &&
equalsIgnoreCase( vec[1] , RTL_CONSTASCII_STRINGPARAM( "into" ) ) )
{
int n = 2;
// printf( "1a\n" );
// extract table name
rtl::OString tableName;
if( equalsIgnoreCase( vec[n+1], RTL_CONSTASCII_STRINGPARAM( "." ) ) )
{
tableName = vec[n];
tableName += vec[n+1];
tableName += vec[n+2];
n +=2;
}
else
{
tableName = vec[n];
}
OStringVector names;
n ++;
if( equalsIgnoreCase( vec[n], RTL_CONSTASCII_STRINGPARAM( "(" ) ) )
{
// printf( "2\n" );
// extract names
n++;
while( nSize > n && ! equalsIgnoreCase(vec[n] , RTL_CONSTASCII_STRINGPARAM( ")" ) ) )
{
names.push_back( vec[n] );
if( nSize > n+1 && equalsIgnoreCase( vec[n+1] , RTL_CONSTASCII_STRINGPARAM( "," ) ) )
{
n ++;
}
n++;
}
n++;
// now read the values
if( nSize > n +1 && equalsIgnoreCase( vec[n], RTL_CONSTASCII_STRINGPARAM("VALUES") ) &&
equalsIgnoreCase(vec[n+1], RTL_CONSTASCII_STRINGPARAM( "(" ) ) )
{
n +=2;
// printf( "3\n" );
for ( int i = 0 ; i < names.size() && nSize > n ; i ++ )
{
map[names[i]] = vec[n];
if( nSize > n+1 && equalsIgnoreCase( vec[n+1] , RTL_CONSTASCII_STRINGPARAM(",") ) )
{
n ++;
}
n++;
}
}
}
}
}
rtl::OUString querySingleValue(
const com::sun::star::uno::Reference< com::sun::star::sdbc::XConnection > &connection,
const rtl::OUString &query )
{
OUString ret;
Reference< XStatement > stmt = connection->createStatement();
DisposeGuard guard( stmt );
Reference< XResultSet > rs = stmt->executeQuery( query );
Reference< XRow > xRow( rs, UNO_QUERY );
if( rs->next() )
ret = xRow->getString( 1 );
return ret;
}
// copied from connectivity/source/dbtools, can't use the function directly
bool implSetObject( const Reference< XParameters >& _rxParameters,
const sal_Int32 _nColumnIndex, const Any& _rValue)
{
sal_Bool bSuccessfullyReRouted = sal_True;
switch (_rValue.getValueTypeClass())
{
case typelib_TypeClass_HYPER:
{
sal_Int64 nValue = 0;
_rxParameters->setLong( _nColumnIndex, nValue );
}
break;
case typelib_TypeClass_VOID:
_rxParameters->setNull(_nColumnIndex,com::sun::star::sdbc::DataType::VARCHAR);
break;
case typelib_TypeClass_STRING:
_rxParameters->setString(_nColumnIndex, *(rtl::OUString*)_rValue.getValue());
break;
case typelib_TypeClass_BOOLEAN:
_rxParameters->setBoolean(_nColumnIndex, *(sal_Bool *)_rValue.getValue());
break;
case typelib_TypeClass_BYTE:
_rxParameters->setByte(_nColumnIndex, *(sal_Int8 *)_rValue.getValue());
break;
case typelib_TypeClass_UNSIGNED_SHORT:
case typelib_TypeClass_SHORT:
_rxParameters->setShort(_nColumnIndex, *(sal_Int16*)_rValue.getValue());
break;
case typelib_TypeClass_CHAR:
_rxParameters->setString(_nColumnIndex, ::rtl::OUString((sal_Unicode *)_rValue.getValue(),1));
break;
case typelib_TypeClass_UNSIGNED_LONG:
case typelib_TypeClass_LONG:
_rxParameters->setInt(_nColumnIndex, *(sal_Int32*)_rValue.getValue());
break;
case typelib_TypeClass_FLOAT:
_rxParameters->setFloat(_nColumnIndex, *(float*)_rValue.getValue());
break;
case typelib_TypeClass_DOUBLE:
_rxParameters->setDouble(_nColumnIndex, *(double*)_rValue.getValue());
break;
case typelib_TypeClass_SEQUENCE:
if (_rValue.getValueType() == ::getCppuType((const Sequence< sal_Int8 > *)0))
{
_rxParameters->setBytes(_nColumnIndex, *(Sequence<sal_Int8>*)_rValue.getValue());
}
else
bSuccessfullyReRouted = sal_False;
break;
case typelib_TypeClass_STRUCT:
if (_rValue.getValueType() == ::getCppuType((const com::sun::star::util::DateTime*)0))
_rxParameters->setTimestamp(_nColumnIndex, *(com::sun::star::util::DateTime*)_rValue.getValue());
else if (_rValue.getValueType() == ::getCppuType((const com::sun::star::util::Date*)0))
_rxParameters->setDate(_nColumnIndex, *(com::sun::star::util::Date*)_rValue.getValue());
else if (_rValue.getValueType() == ::getCppuType((const com::sun::star::util::Time*)0))
_rxParameters->setTime(_nColumnIndex, *(com::sun::star::util::Time*)_rValue.getValue());
else
bSuccessfullyReRouted = sal_False;
break;
case typelib_TypeClass_INTERFACE:
{
Reference< com::sun::star::io::XInputStream > xStream;
if (_rValue >>= xStream)
{
_rValue >>= xStream;
_rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available());
break;
}
}
// run through
default:
bSuccessfullyReRouted = sal_False;
}
return bSuccessfullyReRouted;
}
}