Files
loongoffice/connectivity/source/parse/sqlnode.cxx
Tamas Bunth f5a2fedaeb tdf#105075 Firebird: Support Limit of query_GUI
Firebird uses "SELECT FIRST <num> ..." format to limit the number of
result row numbers instead of "SELECT ... LIMIT <num>"

My first approach was to improve OSQLParser and make it understand the
Firebird dialect. But it is hard because the parser has hard-coded
getChild(int) calls all over the code and all the indexes should be
updated.

Instead of this, we recognise the LIMIT keyword with the parser, remove
it and push the FIRST <num> part manually right after SELECT.

All of this should happen in case of Firebird and only when using the
query-GUI.

Change-Id: I53f3f977f77cf98b91b25a7eaa6ebb2ee8ac0951
Reviewed-on: https://gerrit.libreoffice.org/52591
Reviewed-by: Lionel Elie Mamane <lionel@mamane.lu>
Tested-by: Jenkins <ci@libreoffice.org>
2018-04-14 14:15:26 +02:00

2795 lines
115 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/macros.h>
#include <connectivity/sqlnode.hxx>
#include <connectivity/sqlerror.hxx>
#include <connectivity/sqlbison_exports.hxx>
#include <connectivity/internalnode.hxx>
#define YYBISON 1
#include <sqlbison.hxx>
#include <connectivity/sqlparse.hxx>
#include <connectivity/sqlscan.hxx>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/util/XNumberFormatter.hpp>
#include <com/sun/star/util/XNumberFormatTypes.hpp>
#include <com/sun/star/i18n/LocaleData.hpp>
#include <com/sun/star/i18n/NumberFormatIndex.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdb/XQueriesSupplier.hpp>
#include <com/sun/star/sdb/ErrorCondition.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <com/sun/star/util/XNumberFormats.hpp>
#include <com/sun/star/util/NumberFormat.hpp>
#include <com/sun/star/i18n/KParseType.hpp>
#include <com/sun/star/i18n/KParseTokens.hpp>
#include <com/sun/star/i18n/CharacterClassification.hpp>
#include <connectivity/dbconversion.hxx>
#include <com/sun/star/util/DateTime.hpp>
#include <com/sun/star/util/Time.hpp>
#include <com/sun/star/util/Date.hpp>
#include <TConnection.hxx>
#include <comphelper/numbers.hxx>
#include <connectivity/dbtools.hxx>
#include <connectivity/dbmetadata.hxx>
#include <tools/diagnose_ex.h>
#include <string.h>
#include <algorithm>
#include <functional>
#include <memory>
#include <rtl/ustrbuf.hxx>
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::i18n;
using namespace ::com::sun::star;
using namespace ::osl;
using namespace ::dbtools;
using namespace ::comphelper;
namespace
{
bool lcl_saveConvertToNumber(const Reference< XNumberFormatter > & _xFormatter,sal_Int32 _nKey,const OUString& _sValue,double& _nrValue)
{
bool bRet = false;
try
{
_nrValue = _xFormatter->convertStringToNumber(_nKey, _sValue);
bRet = true;
}
catch(Exception&)
{
}
return bRet;
}
void replaceAndReset(connectivity::OSQLParseNode*& _pResetNode,connectivity::OSQLParseNode* _pNewNode)
{
_pResetNode->getParent()->replace(_pResetNode, _pNewNode);
delete _pResetNode;
_pResetNode = _pNewNode;
}
/** quotes a string and search for quotes inside the string and replace them with the new quote
@param rValue
The value to be quoted.
@param rQuot
The quote
@param rQuotToReplace
The quote to replace with
@return
The quoted string.
*/
OUString SetQuotation(const OUString& rValue, const OUString& rQuot, const OUString& rQuotToReplace)
{
OUString rNewValue = rQuot;
rNewValue += rValue;
sal_Int32 nIndex = sal_Int32(-1); // Replace quotes with double quotes or the parser gets into problems
if (!rQuot.isEmpty())
{
do
{
nIndex += 2;
nIndex = rNewValue.indexOf(rQuot,nIndex);
if(nIndex != -1)
rNewValue = rNewValue.replaceAt(nIndex,rQuot.getLength(),rQuotToReplace);
} while (nIndex != -1);
}
rNewValue += rQuot;
return rNewValue;
}
bool columnMatchP(const connectivity::OSQLParseNode* pSubTree, const connectivity::SQLParseNodeParameter& rParam)
{
using namespace connectivity;
assert(SQL_ISRULE(pSubTree,column_ref));
if(!rParam.xField.is())
return false;
// retrieve the field's name & table range
OUString aFieldName;
try
{
sal_Int32 nNamePropertyId = PROPERTY_ID_NAME;
if ( rParam.xField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) )
nNamePropertyId = PROPERTY_ID_REALNAME;
rParam.xField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( nNamePropertyId ) ) >>= aFieldName;
}
catch ( Exception& )
{
}
if(pSubTree->count())
{
const OSQLParseNode* pCol = pSubTree->getChild(pSubTree->count()-1);
if (SQL_ISRULE(pCol,column_val))
{
assert(pCol->count() == 1);
pCol = pCol->getChild(0);
}
const OSQLParseNode* pTable(nullptr);
switch (pSubTree->count())
{
case 1:
break;
case 3:
pTable = pSubTree->getChild(0);
break;
case 5:
case 7:
SAL_WARN("connectivity.parse", "SQL: catalog and/or schema in column_ref in predicate");
break;
default:
SAL_WARN("connectivity.parse", "columnMatchP: SQL grammar changed; column_ref has " << pSubTree->count() << " children");
assert(false);
break;
}
// TODO: not all DBMS match column names case-insensitively...
// see XDatabaseMetaData::supportsMixedCaseIdentifiers()
// and XDatabaseMetaData::supportsMixedCaseQuotedIdentifiers()
if ( // table name matches (or no table name)?
( !pTable || pTable->getTokenValue().equalsIgnoreAsciiCase(rParam.sPredicateTableAlias) )
&& // column name matches?
pCol->getTokenValue().equalsIgnoreAsciiCase(aFieldName)
)
return true;
}
return false;
}
}
namespace connectivity
{
SQLParseNodeParameter::SQLParseNodeParameter( const Reference< XConnection >& _rxConnection,
const Reference< XNumberFormatter >& _xFormatter, const Reference< XPropertySet >& _xField,
const OUString &_sPredicateTableAlias,
const Locale& _rLocale, const IParseContext* _pContext,
bool _bIntl, bool _bQuote, sal_Char _cDecSep, bool _bPredicate, bool _bParseToSDBC )
:rLocale(_rLocale)
,aMetaData( _rxConnection )
,pParser( nullptr )
,pSubQueryHistory( new QueryNameSet )
,xFormatter(_xFormatter)
,xField(_xField)
,sPredicateTableAlias(_sPredicateTableAlias)
,m_rContext( _pContext ? *_pContext : OSQLParser::s_aDefaultContext )
,cDecSep(_cDecSep)
,bQuote(_bQuote)
,bInternational(_bIntl)
,bPredicate(_bPredicate)
,bParseToSDBCLevel( _bParseToSDBC )
{
}
SQLParseNodeParameter::~SQLParseNodeParameter()
{
}
OUString OSQLParseNode::convertDateString(const SQLParseNodeParameter& rParam, const OUString& rString)
{
Date aDate = DBTypeConversion::toDate(rString);
Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
double fDate = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier));
sal_Int32 nKey = xTypes->getStandardIndex(rParam.rLocale) + 36; // XXX hack
return rParam.xFormatter->convertNumberToString(nKey, fDate);
}
OUString OSQLParseNode::convertDateTimeString(const SQLParseNodeParameter& rParam, const OUString& rString)
{
DateTime aDate = DBTypeConversion::toDateTime(rString);
Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
double fDateTime = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier));
sal_Int32 nKey = xTypes->getStandardIndex(rParam.rLocale) + 51; // XXX hack
return rParam.xFormatter->convertNumberToString(nKey, fDateTime);
}
OUString OSQLParseNode::convertTimeString(const SQLParseNodeParameter& rParam, const OUString& rString)
{
css::util::Time aTime = DBTypeConversion::toTime(rString);
Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier());
Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY);
double fTime = DBTypeConversion::toDouble(aTime);
sal_Int32 nKey = xTypes->getStandardIndex(rParam.rLocale) + 41; // XXX hack
return rParam.xFormatter->convertNumberToString(nKey, fTime);
}
void OSQLParseNode::parseNodeToStr(OUString& rString,
const Reference< XConnection >& _rxConnection,
const IParseContext* pContext,
bool _bIntl,
bool _bQuote) const
{
parseNodeToStr(
rString, _rxConnection, nullptr, nullptr, OUString(),
pContext ? pContext->getPreferredLocale() : OParseContext::getDefaultLocale(),
pContext, _bIntl, _bQuote, '.', false );
}
void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
const Reference< XConnection >& _rxConnection,
const Reference< XNumberFormatter > & xFormatter,
const css::lang::Locale& rIntl,
sal_Char _cDec,
const IParseContext* pContext ) const
{
OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");
if (xFormatter.is())
parseNodeToStr(rString, _rxConnection, xFormatter, nullptr, OUString(), rIntl, pContext, true, true, _cDec, true);
}
void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
const Reference< XConnection > & _rxConnection,
const Reference< XNumberFormatter > & xFormatter,
const Reference< XPropertySet > & _xField,
const OUString &_sPredicateTableAlias,
const css::lang::Locale& rIntl,
sal_Char _cDec,
const IParseContext* pContext ) const
{
OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");
if (xFormatter.is())
parseNodeToStr( rString, _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext, true, true, _cDec, true );
}
void OSQLParseNode::parseNodeToStr(OUString& rString,
const Reference< XConnection > & _rxConnection,
const Reference< XNumberFormatter > & xFormatter,
const Reference< XPropertySet > & _xField,
const OUString &_sPredicateTableAlias,
const css::lang::Locale& rIntl,
const IParseContext* pContext,
bool _bIntl,
bool _bQuote,
sal_Char _cDecSep,
bool _bPredicate) const
{
OSL_ENSURE( _rxConnection.is(), "OSQLParseNode::parseNodeToStr: invalid connection!" );
if ( _rxConnection.is() )
{
OUStringBuffer sBuffer = rString;
try
{
OSQLParseNode::impl_parseNodeToString_throw( sBuffer,
SQLParseNodeParameter(
_rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext,
_bIntl, _bQuote, _cDecSep, _bPredicate, false
) );
}
catch( const SQLException& )
{
SAL_WARN( "connectivity.parse", "OSQLParseNode::parseNodeToStr: this should not throw!" );
// our callers don't expect this method to throw anything. The only known situation
// where impl_parseNodeToString_throw can throw is when there is a cyclic reference
// in the sub queries, but this cannot be the case here, as we do not parse to
// SDBC level.
}
rString = sBuffer.makeStringAndClear();
}
}
bool OSQLParseNode::parseNodeToExecutableStatement( OUString& _out_rString, const Reference< XConnection >& _rxConnection,
OSQLParser& _rParser, css::sdbc::SQLException* _pErrorHolder ) const
{
OSL_PRECOND( _rxConnection.is(), "OSQLParseNode::parseNodeToExecutableStatement: invalid connection!" );
SQLParseNodeParameter aParseParam( _rxConnection,
nullptr, nullptr, OUString(), OParseContext::getDefaultLocale(), nullptr, false, true, '.', false, true );
if ( aParseParam.aMetaData.supportsSubqueriesInFrom() )
{
Reference< XQueriesSupplier > xSuppQueries( _rxConnection, UNO_QUERY );
OSL_ENSURE( xSuppQueries.is(), "OSQLParseNode::parseNodeToExecutableStatement: cannot substitute everything without a QueriesSupplier!" );
if ( xSuppQueries.is() )
aParseParam.xQueries = xSuppQueries->getQueries();
}
aParseParam.pParser = &_rParser;
// LIMIT keyword differs in Firebird
OSQLParseNode* pTableExp = getChild(3);
Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData() );
OUString sLimitValue;
if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1)
&& (xMeta->getURL().equalsIgnoreAsciiCase("sdbc:embedded:firebird")
|| xMeta->getURL().startsWithIgnoreAsciiCase("sdbc:firebird:")))
{
sLimitValue = pTableExp->getChild(6)->getChild(1)->getTokenValue();
pTableExp->removeAt(6);
}
_out_rString.clear();
OUStringBuffer sBuffer;
bool bSuccess = false;
try
{
impl_parseNodeToString_throw( sBuffer, aParseParam );
bSuccess = true;
}
catch( const SQLException& e )
{
if ( _pErrorHolder )
*_pErrorHolder = e;
}
if(sLimitValue.getLength() > 0)
{
constexpr char SELECT_KEYWORD[] = "SELECT";
sBuffer.insert(sBuffer.indexOf(SELECT_KEYWORD) + strlen(SELECT_KEYWORD),
" FIRST " + sLimitValue);
}
_out_rString = sBuffer.makeStringAndClear();
return bSuccess;
}
namespace
{
bool lcl_isAliasNamePresent( const OSQLParseNode& _rTableNameNode )
{
return !OSQLParseNode::getTableRange(_rTableNameNode.getParent()).isEmpty();
}
}
void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple) const
{
if ( isToken() )
{
parseLeaf(rString,rParam);
return;
}
// Lets see how many nodes this subtree has
sal_uInt32 nCount = count();
bool bHandled = false;
switch ( getKnownRuleID() )
{
// special handling for parameters
case parameter:
{
bSimple=false;
if(!rString.isEmpty())
rString.append(" ");
if (nCount == 1) // ?
m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
else if (rParam.bParseToSDBCLevel && rParam.aMetaData.shouldSubstituteParameterNames())
{
rString.append("?");
}
else if (nCount == 2) // :Name
{
m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
rString.append(m_aChildren[1]->m_aNodeValue);
} // [Name]
else
{
assert (nCount == 3);
m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
rString.append(m_aChildren[1]->m_aNodeValue);
rString.append(m_aChildren[2]->m_aNodeValue);
}
bHandled = true;
}
break;
// table refs
case table_ref:
bSimple=false;
if ( ( nCount == 2 ) || ( nCount == 3 ) || ( nCount == 5 ) )
{
impl_parseTableRangeNodeToString_throw( rString, rParam );
bHandled = true;
}
break;
// table name - might be a query name
case table_name:
bSimple=false;
bHandled = impl_parseTableNameNodeToString_throw( rString, rParam );
break;
case as_clause:
bSimple=false;
assert(nCount == 0 || nCount == 2);
if (nCount == 2)
{
if ( rParam.aMetaData.generateASBeforeCorrelationName() )
rString.append(" AS ");
m_aChildren[1]->impl_parseNodeToString_throw( rString, rParam, false );
}
bHandled = true;
break;
case opt_as:
assert(nCount == 0);
bHandled = true;
break;
case like_predicate:
// Depending on whether international is given, LIKE is treated differently
// international: *, ? are placeholders
// else SQL92 conform: %, _
impl_parseLikeNodeToString_throw( rString, rParam, bSimple );
bHandled = true;
break;
case general_set_fct:
case set_fct_spec:
case position_exp:
case extract_exp:
case length_exp:
case char_value_fct:
bSimple=false;
if (!addDateValue(rString, rParam))
{
// Do not quote function name
SQLParseNodeParameter aNewParam(rParam);
aNewParam.bQuote = ( SQL_ISRULE(this,length_exp) || SQL_ISRULE(this,char_value_fct) );
m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, false );
aNewParam.bQuote = rParam.bQuote;
//aNewParam.bPredicate = sal_False; // disable [ ] around names // look at i73215
OUStringBuffer aStringPara;
for (sal_uInt32 i=1; i<nCount; i++)
{
const OSQLParseNode * pSubTree = m_aChildren[i].get();
if (pSubTree)
{
pSubTree->impl_parseNodeToString_throw( aStringPara, aNewParam, false );
// In the comma lists, put commas in-between all subtrees
if ((m_eNodeType == SQLNodeType::CommaListRule) && (i < (nCount - 1)))
aStringPara.append(",");
}
else
i++;
}
rString.append(aStringPara.makeStringAndClear());
}
bHandled = true;
break;
case odbc_call_spec:
case subquery:
case term:
case factor:
case window_function:
case cast_spec:
case num_value_exp:
bSimple = false;
break;
default:
break;
} // switch ( getKnownRuleID() )
if ( !bHandled )
{
for (auto i = m_aChildren.begin(); i != m_aChildren.end();)
{
const OSQLParseNode* pSubTree = i->get();
if ( !pSubTree )
{
++i;
continue;
}
SQLParseNodeParameter aNewParam(rParam);
// don't replace the field for subqueries
if (rParam.xField.is() && SQL_ISRULE(pSubTree,subquery))
aNewParam.xField = nullptr;
// When we are building a criterion inside a query view,
// simplify criterion display by removing:
// "currentFieldName"
// "currentFieldName" =
// but only in simple expressions.
// This means anything that is made of:
// (see the rules conditionalised by inPredicateCheck() in sqlbison.y).
// - parentheses
// - logical operators (and, or, not)
// - comparison operators (IS, =, >, <, BETWEEN, LIKE, ...)
// but *not* e.g. in function arguments
if (bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(pSubTree,column_ref))
{
if (columnMatchP(pSubTree, rParam))
{
// skip field
++i;
// if the following node is the comparison operator'=',
// we filter it as well
if (SQL_ISRULE(this, comparison_predicate))
{
if(i != m_aChildren.end())
{
pSubTree = i->get();
if (pSubTree && pSubTree->getNodeType() == SQLNodeType::Equal)
++i;
}
}
}
else
{
pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
++i;
// In the comma lists, put commas in-between all subtrees
if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end()))
rString.append(",");
}
}
else
{
pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
++i;
// In the comma lists, put commas in-between all subtrees
if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end()))
{
if (SQL_ISRULE(this,value_exp_commalist) && rParam.bPredicate)
rString.append(";");
else
rString.append(",");
}
}
// The right hand-side of these operators is not simple
switch ( getKnownRuleID() )
{
case general_set_fct:
case set_fct_spec:
case position_exp:
case extract_exp:
case length_exp:
case char_value_fct:
case odbc_call_spec:
case subquery:
case comparison_predicate:
case between_predicate:
case like_predicate:
case test_for_null:
case in_predicate:
case existence_test:
case unique_test:
case all_or_any_predicate:
case join_condition:
case comparison_predicate_part_2:
case parenthesized_boolean_value_expression:
case other_like_predicate_part_2:
case between_predicate_part_2:
bSimple=false;
break;
default:
break;
}
}
}
}
bool OSQLParseNode::impl_parseTableNameNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const
{
// is the table_name part of a table_ref?
OSL_ENSURE( getParent(), "OSQLParseNode::impl_parseTableNameNodeToString_throw: table_name without parent?" );
if ( !getParent() || ( getParent()->getKnownRuleID() != table_ref ) )
return false;
// if it's a query, maybe we need to substitute the SQL statement ...
if ( !rParam.bParseToSDBCLevel )
return false;
if ( !rParam.xQueries.is() )
// connection does not support queries in queries, or was no query supplier
return false;
try
{
OUString sTableOrQueryName( getChild(0)->getTokenValue() );
bool bIsQuery = rParam.xQueries->hasByName( sTableOrQueryName );
if ( !bIsQuery )
return false;
// avoid recursion (e.g. "foo" defined as "SELECT * FROM bar" and "bar" defined as "SELECT * FROM foo".
if ( rParam.pSubQueryHistory->find( sTableOrQueryName ) != rParam.pSubQueryHistory->end() )
{
OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: no parser?" );
if ( rParam.pParser )
{
const SQLError& rErrors( rParam.pParser->getErrorHelper() );
rErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES );
}
else
{
SQLError aErrors;
aErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES );
}
}
rParam.pSubQueryHistory->insert( sTableOrQueryName );
Reference< XPropertySet > xQuery( rParam.xQueries->getByName( sTableOrQueryName ), UNO_QUERY_THROW );
// substitute the query name with the constituting command
OUString sCommand;
OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sCommand );
bool bEscapeProcessing = false;
OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
// the query we found here might itself be based on another query, so parse it recursively
OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: cannot analyze sub queries without a parser!" );
if ( bEscapeProcessing && rParam.pParser )
{
OUString sError;
std::unique_ptr< OSQLParseNode > pSubQueryNode( rParam.pParser->parseTree( sError, sCommand ) );
if ( pSubQueryNode.get() )
{
// parse the sub-select to SDBC level, too
OUStringBuffer sSubSelect;
pSubQueryNode->impl_parseNodeToString_throw( sSubSelect, rParam, false );
if ( !sSubSelect.isEmpty() )
sCommand = sSubSelect.makeStringAndClear();
}
}
rString.append( " ( " );
rString.append(sCommand);
rString.append( " )" );
// append the query name as table alias, since it might be referenced in other
// parts of the statement - but only if there's no other alias name present
if ( !lcl_isAliasNamePresent( *this ) )
{
rString.append( " AS " );
if ( rParam.bQuote )
rString.append(SetQuotation( sTableOrQueryName,
rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() ));
}
// don't forget to remove the query name from the history, else multiple inclusions
// won't work
// #i69227# / 2006-10-10 / frank.schoenheit@sun.com
rParam.pSubQueryHistory->erase( sTableOrQueryName );
return true;
}
catch( const SQLException& )
{
throw;
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("connectivity.parse");
}
return false;
}
void OSQLParseNode::impl_parseTableRangeNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
{
OSL_PRECOND( ( count() == 2 ) || ( count() == 3 ) || ( count() == 5 ) ,"Illegal count");
// rString += " ";
std::for_each(m_aChildren.begin(),m_aChildren.end(),
[&] (std::unique_ptr<OSQLParseNode> const & pNode) { pNode->impl_parseNodeToString_throw(rString, rParam, false); });
}
void OSQLParseNode::impl_parseLikeNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple ) const
{
assert(SQL_ISRULE(this,like_predicate));
OSL_ENSURE(count() == 2,"count != 2: Prepare for GPF");
const OSQLParseNode* pEscNode = nullptr;
const OSQLParseNode* pParaNode = nullptr;
SQLParseNodeParameter aNewParam(rParam);
//aNewParam.bQuote = sal_True; // why setting this to true? @see https://bz.apache.org/ooo/show_bug.cgi?id=75557
if ( !(bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(m_aChildren[0],column_ref) && columnMatchP(m_aChildren[0].get(), rParam)) )
m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, bSimple );
const OSQLParseNode* pPart2 = m_aChildren[1].get();
pPart2->getChild(0)->impl_parseNodeToString_throw( rString, aNewParam, false );
pPart2->getChild(1)->impl_parseNodeToString_throw( rString, aNewParam, false );
pParaNode = pPart2->getChild(2);
pEscNode = pPart2->getChild(3);
if (pParaNode->isToken())
{
OUString aStr = ConvertLikeToken(pParaNode, pEscNode, rParam.bInternational);
rString.append(" ");
rString.append(SetQuotation(aStr,"\'","\'\'"));
}
else
pParaNode->impl_parseNodeToString_throw( rString, aNewParam, false );
pEscNode->impl_parseNodeToString_throw( rString, aNewParam, false );
}
bool OSQLParseNode::getTableComponents(const OSQLParseNode* _pTableNode,
css::uno::Any &_rCatalog,
OUString &_rSchema,
OUString &_rTable,
const Reference< XDatabaseMetaData >& _xMetaData)
{
OSL_ENSURE(_pTableNode,"Wrong use of getTableComponents! _pTableNode is not allowed to be null!");
if(_pTableNode)
{
const bool bSupportsCatalog = _xMetaData.is() && _xMetaData->supportsCatalogsInDataManipulation();
const bool bSupportsSchema = _xMetaData.is() && _xMetaData->supportsSchemasInDataManipulation();
const OSQLParseNode* pTableNode = _pTableNode;
// clear the parameter given
_rCatalog = Any();
_rSchema.clear();
_rTable.clear();
// see rule catalog_name: in sqlbison.y
if (SQL_ISRULE(pTableNode,catalog_name))
{
OSL_ENSURE(pTableNode->getChild(0) && pTableNode->getChild(0)->isToken(),"Invalid parsenode!");
_rCatalog <<= pTableNode->getChild(0)->getTokenValue();
pTableNode = pTableNode->getChild(2);
}
// check if we have schema_name rule
if(SQL_ISRULE(pTableNode,schema_name))
{
if ( bSupportsCatalog && !bSupportsSchema )
_rCatalog <<= pTableNode->getChild(0)->getTokenValue();
else
_rSchema = pTableNode->getChild(0)->getTokenValue();
pTableNode = pTableNode->getChild(2);
}
// check if we have table_name rule
if(SQL_ISRULE(pTableNode,table_name))
{
_rTable = pTableNode->getChild(0)->getTokenValue();
}
else
{
SAL_WARN( "connectivity.parse","Error in parse tree!");
}
}
return !_rTable.isEmpty();
}
void OSQLParser::killThousandSeparator(OSQLParseNode* pLiteral)
{
if ( pLiteral )
{
if ( s_xLocaleData->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' )
{
pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace('.', sal_Unicode());
// and replace decimal
pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', '.');
}
else
pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', sal_Unicode());
}
}
OSQLParseNode* OSQLParser::convertNode(sal_Int32 nType, OSQLParseNode* pLiteral)
{
if ( !pLiteral )
return nullptr;
OSQLParseNode* pReturn = pLiteral;
if ( ( pLiteral->isRule() && !SQL_ISRULE(pLiteral,value_exp) ) || SQL_ISTOKEN(pLiteral,FALSE) || SQL_ISTOKEN(pLiteral,TRUE) )
{
switch(nType)
{
case DataType::CHAR:
case DataType::VARCHAR:
case DataType::LONGVARCHAR:
case DataType::CLOB:
if ( !SQL_ISRULE(pReturn,char_value_exp) && !buildStringNodes(pReturn) )
pReturn = nullptr;
break;
default:
break;
}
}
else
{
switch(pLiteral->getNodeType())
{
case SQLNodeType::String:
switch(nType)
{
case DataType::CHAR:
case DataType::VARCHAR:
case DataType::LONGVARCHAR:
case DataType::CLOB:
break;
case DataType::DATE:
case DataType::TIME:
case DataType::TIMESTAMP:
if (m_xFormatter.is())
pReturn = buildDate( nType, pReturn);
break;
default:
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
break;
}
break;
case SQLNodeType::AccessDate:
switch(nType)
{
case DataType::DATE:
case DataType::TIME:
case DataType::TIMESTAMP:
if ( m_xFormatter.is() )
pReturn = buildDate( nType, pReturn);
else
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare);
break;
default:
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
break;
}
break;
case SQLNodeType::IntNum:
switch(nType)
{
case DataType::BIT:
case DataType::BOOLEAN:
case DataType::DECIMAL:
case DataType::NUMERIC:
case DataType::TINYINT:
case DataType::SMALLINT:
case DataType::INTEGER:
case DataType::BIGINT:
case DataType::FLOAT:
case DataType::REAL:
case DataType::DOUBLE:
// kill thousand separators if any
killThousandSeparator(pReturn);
break;
case DataType::CHAR:
case DataType::VARCHAR:
case DataType::LONGVARCHAR:
case DataType::CLOB:
pReturn = buildNode_STR_NUM(pReturn);
break;
default:
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidIntCompare);
break;
}
break;
case SQLNodeType::ApproxNum:
switch(nType)
{
case DataType::DECIMAL:
case DataType::NUMERIC:
case DataType::FLOAT:
case DataType::REAL:
case DataType::DOUBLE:
// kill thousand separators if any
killThousandSeparator(pReturn);
break;
case DataType::CHAR:
case DataType::VARCHAR:
case DataType::LONGVARCHAR:
case DataType::CLOB:
pReturn = buildNode_STR_NUM(pReturn);
break;
case DataType::INTEGER:
default:
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidRealCompare);
break;
}
break;
default:
;
}
}
return pReturn;
}
sal_Int16 OSQLParser::buildPredicateRule(OSQLParseNode*& pAppend, OSQLParseNode* pLiteral, OSQLParseNode* pCompare, OSQLParseNode* pLiteral2)
{
OSL_ENSURE(inPredicateCheck(),"Only in predicate check allowed!");
sal_Int16 nErg = 0;
if ( m_xField.is() )
{
sal_Int32 nType = 0;
try
{
m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
}
catch( Exception& )
{
return nErg;
}
OSQLParseNode* pNode1 = convertNode(nType,pLiteral);
if ( pNode1 )
{
OSQLParseNode* pNode2 = convertNode(nType,pLiteral2);
if ( m_sErrorMessage.isEmpty() )
nErg = buildNode(pAppend,pCompare,pNode1,pNode2);
}
}
if (!pCompare->getParent()) // I have no parent so I was not used and I must die :-)
delete pCompare;
return nErg;
}
sal_Int16 OSQLParser::buildLikeRule(OSQLParseNode* pAppend, OSQLParseNode*& pLiteral, const OSQLParseNode* pEscape)
{
sal_Int16 nErg = 0;
sal_Int32 nType = 0;
if (!m_xField.is())
return nErg;
try
{
Any aValue;
{
aValue = m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE));
aValue >>= nType;
}
}
catch( Exception& )
{
return nErg;
}
switch (nType)
{
case DataType::CHAR:
case DataType::VARCHAR:
case DataType::LONGVARCHAR:
case DataType::CLOB:
if(pLiteral->isRule())
{
pAppend->append(pLiteral);
nErg = 1;
}
else
{
switch(pLiteral->getNodeType())
{
case SQLNodeType::String:
pLiteral->m_aNodeValue = ConvertLikeToken(pLiteral, pEscape, false);
pAppend->append(pLiteral);
nErg = 1;
break;
case SQLNodeType::ApproxNum:
if (m_xFormatter.is() && m_nFormatKey)
{
sal_Int16 nScale = 0;
try
{
Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" );
aValue >>= nScale;
}
catch( Exception& )
{
}
pAppend->append(new OSQLInternalNode(stringToDouble(pLiteral->getTokenValue(),nScale),SQLNodeType::String));
}
else
pAppend->append(new OSQLInternalNode(pLiteral->getTokenValue(),SQLNodeType::String));
delete pLiteral;
nErg = 1;
break;
default:
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::ValueNoLike);
m_sErrorMessage = m_sErrorMessage.replaceAt(m_sErrorMessage.indexOf("#1"),2,pLiteral->getTokenValue());
break;
}
}
break;
default:
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::FieldNoLike);
break;
}
return nErg;
}
OSQLParseNode* OSQLParser::buildNode_Date(const double& fValue, sal_Int32 nType)
{
OSQLParseNode* pNewNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::set_fct_spec));
pNewNode->append(new OSQLInternalNode("{", SQLNodeType::Punctuation));
OSQLParseNode* pDateNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::odbc_fct_spec));
pNewNode->append(pDateNode);
pNewNode->append(new OSQLInternalNode("}", SQLNodeType::Punctuation));
switch (nType)
{
case DataType::DATE:
{
Date aDate = DBTypeConversion::toDate(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier()));
OUString aString = DBTypeConversion::toDateString(aDate);
pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D));
pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
break;
}
case DataType::TIME:
{
css::util::Time aTime = DBTypeConversion::toTime(fValue);
OUString aString = DBTypeConversion::toTimeString(aTime);
pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_T));
pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
break;
}
case DataType::TIMESTAMP:
{
DateTime aDateTime = DBTypeConversion::toDateTime(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier()));
if (aDateTime.Seconds || aDateTime.Minutes || aDateTime.Hours)
{
OUString aString = DBTypeConversion::toDateTimeString(aDateTime);
pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_TS));
pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String));
}
else
{
Date aDate(aDateTime.Day,aDateTime.Month,aDateTime.Year);
pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D));
pDateNode->append(new OSQLInternalNode(DBTypeConversion::toDateString(aDate), SQLNodeType::String));
}
break;
}
}
return pNewNode;
}
OSQLParseNode* OSQLParser::buildNode_STR_NUM(OSQLParseNode*& _pLiteral)
{
OSQLParseNode* pReturn = nullptr;
if ( _pLiteral )
{
if (m_nFormatKey)
{
sal_Int16 nScale = 0;
try
{
Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" );
aValue >>= nScale;
}
catch( Exception& )
{
}
pReturn = new OSQLInternalNode(stringToDouble(_pLiteral->getTokenValue(),nScale),SQLNodeType::String);
}
else
pReturn = new OSQLInternalNode(_pLiteral->getTokenValue(),SQLNodeType::String);
delete _pLiteral;
_pLiteral = nullptr;
}
return pReturn;
}
OUString OSQLParser::stringToDouble(const OUString& _rValue,sal_Int16 _nScale)
{
OUString aValue;
if(!m_xCharClass.is())
m_xCharClass = CharacterClassification::create( m_xContext );
if( s_xLocaleData.is() )
{
try
{
ParseResult aResult = m_xCharClass->parsePredefinedToken(KParseType::ANY_NUMBER,_rValue,0,m_pData->aLocale,0,OUString(),KParseType::ANY_NUMBER,OUString());
if((aResult.TokenType & KParseType::IDENTNAME) && aResult.EndPos == _rValue.getLength())
{
aValue = OUString::number(aResult.Value);
sal_Int32 nPos = aValue.lastIndexOf('.');
if((nPos+_nScale) < aValue.getLength())
aValue = aValue.replaceAt(nPos+_nScale,aValue.getLength()-nPos-_nScale,OUString());
aValue = aValue.replaceAt(aValue.lastIndexOf('.'),1,s_xLocaleData->getLocaleItem(m_pData->aLocale).decimalSeparator);
return aValue;
}
}
catch(Exception&)
{
}
}
return aValue;
}
::osl::Mutex& OSQLParser::getMutex()
{
static ::osl::Mutex aMutex;
return aMutex;
}
OSQLParseNode* OSQLParser::predicateTree(OUString& rErrorMessage, const OUString& rStatement,
const Reference< css::util::XNumberFormatter > & xFormatter,
const Reference< XPropertySet > & xField,
bool bUseRealName)
{
// Guard the parsing
::osl::MutexGuard aGuard(getMutex());
// must be reset
setParser(this);
// reset the parser
m_xField = xField;
m_xFormatter = xFormatter;
if (m_xField.is())
{
sal_Int32 nType=0;
try
{
// get the field name
OUString aString;
// retrieve the fields name
// #75243# use the RealName of the column if there is any otherwise the name which could be the alias
// of the field
Reference< XPropertySetInfo> xInfo = m_xField->getPropertySetInfo();
if ( bUseRealName && xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME)))
m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME)) >>= aString;
else
m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aString;
m_sFieldName = aString;
// get the field format key
if ( xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)))
m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= m_nFormatKey;
else
m_nFormatKey = 0;
// get the field type
m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
}
catch ( Exception& )
{
OSL_ASSERT(false);
}
if (m_nFormatKey && m_xFormatter.is())
{
Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LOCALE) );
OSL_ENSURE(aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get(), "OSQLParser::PredicateTree : invalid language property !");
if (aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get())
aValue >>= m_pData->aLocale;
}
else
m_pData->aLocale = m_pContext->getPreferredLocale();
if ( m_xFormatter.is() )
{
try
{
Reference< css::util::XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier();
if ( xFormatSup.is() )
{
Reference< css::util::XNumberFormats > xFormats = xFormatSup->getNumberFormats();
if ( xFormats.is() )
{
css::lang::Locale aLocale;
aLocale.Language = "en";
aLocale.Country = "US";
OUString sFormat("YYYY-MM-DD");
m_nDateFormatKey = xFormats->queryKey(sFormat,aLocale,false);
if ( m_nDateFormatKey == sal_Int32(-1) )
m_nDateFormatKey = xFormats->addNew(sFormat, aLocale);
}
}
}
catch ( Exception& )
{
SAL_WARN( "connectivity.parse","DateFormatKey");
}
}
switch (nType)
{
case DataType::DATE:
case DataType::TIME:
case DataType::TIMESTAMP:
s_pScanner->SetRule(OSQLScanner::GetDATERule());
break;
case DataType::CHAR:
case DataType::VARCHAR:
case DataType::LONGVARCHAR:
case DataType::CLOB:
s_pScanner->SetRule(OSQLScanner::GetSTRINGRule());
break;
default:
if ( s_xLocaleData->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' )
s_pScanner->SetRule(OSQLScanner::GetGERRule());
else
s_pScanner->SetRule(OSQLScanner::GetENGRule());
}
}
else
s_pScanner->SetRule(OSQLScanner::GetSQLRule());
s_pScanner->prepareScan(rStatement, m_pContext, true);
SQLyylval.pParseNode = nullptr;
// SQLyypvt = NULL;
m_pParseTree = nullptr;
m_sErrorMessage.clear();
// Start the parser
if (SQLyyparse() != 0)
{
m_sFieldName.clear();
m_xField.clear();
m_xFormatter.clear();
m_nFormatKey = 0;
m_nDateFormatKey = 0;
if (m_sErrorMessage.isEmpty())
m_sErrorMessage = s_pScanner->getErrorMessage();
if (m_sErrorMessage.isEmpty())
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::General);
rErrorMessage = m_sErrorMessage;
// clear the garbage collector
(*s_pGarbageCollector)->clearAndDelete();
return nullptr;
}
else
{
(*s_pGarbageCollector)->clear();
m_sFieldName.clear();
m_xField.clear();
m_xFormatter.clear();
m_nFormatKey = 0;
m_nDateFormatKey = 0;
// Return the result (the root parse node):
// Instead, the parse method sets the member pParseTree and simply returns that
OSL_ENSURE(m_pParseTree != nullptr,"OSQLParser: Parser did not return a ParseTree!");
return m_pParseTree;
}
}
OSQLParser::OSQLParser(const css::uno::Reference< css::uno::XComponentContext >& rxContext, const IParseContext* _pContext)
:m_pContext(_pContext)
,m_pParseTree(nullptr)
,m_pData( new OSQLParser_Data )
,m_nFormatKey(0)
,m_nDateFormatKey(0)
,m_xContext(rxContext)
{
setParser(this);
#ifdef SQLYYDEBUG
#ifdef SQLYYDEBUG_ON
SQLyydebug = 1;
#endif
#endif
::osl::MutexGuard aGuard(getMutex());
// Do we have to initialize the data?
if (s_nRefCount == 0)
{
s_pScanner = new OSQLScanner();
s_pScanner->setScanner();
s_pGarbageCollector = new OSQLParseNodesGarbageCollector();
if(!s_xLocaleData.is())
s_xLocaleData = LocaleData::create(m_xContext);
// reset to UNKNOWN_RULE
static_assert(OSQLParseNode::UNKNOWN_RULE==0, "UNKNOWN_RULE must be 0 for memset to 0 to work");
memset(OSQLParser::s_nRuleIDs,0,sizeof(OSQLParser::s_nRuleIDs));
const struct
{
OSQLParseNode::Rule eRule; // the parse node's ID for the rule
OString sRuleName; // the name of the rule ("select_statement")
} aRuleDescriptions[] =
{
{ OSQLParseNode::select_statement, "select_statement" },
{ OSQLParseNode::table_exp, "table_exp" },
{ OSQLParseNode::table_ref_commalist, "table_ref_commalist" },
{ OSQLParseNode::table_ref, "table_ref" },
{ OSQLParseNode::catalog_name, "catalog_name" },
{ OSQLParseNode::schema_name, "schema_name" },
{ OSQLParseNode::table_name, "table_name" },
{ OSQLParseNode::opt_column_commalist, "opt_column_commalist" },
{ OSQLParseNode::column_commalist, "column_commalist" },
{ OSQLParseNode::column_ref_commalist, "column_ref_commalist" },
{ OSQLParseNode::column_ref, "column_ref" },
{ OSQLParseNode::opt_order_by_clause, "opt_order_by_clause" },
{ OSQLParseNode::ordering_spec_commalist, "ordering_spec_commalist" },
{ OSQLParseNode::ordering_spec, "ordering_spec" },
{ OSQLParseNode::opt_asc_desc, "opt_asc_desc" },
{ OSQLParseNode::where_clause, "where_clause" },
{ OSQLParseNode::opt_where_clause, "opt_where_clause" },
{ OSQLParseNode::search_condition, "search_condition" },
{ OSQLParseNode::comparison, "comparison" },
{ OSQLParseNode::comparison_predicate, "comparison_predicate" },
{ OSQLParseNode::between_predicate, "between_predicate" },
{ OSQLParseNode::like_predicate, "like_predicate" },
{ OSQLParseNode::opt_escape, "opt_escape" },
{ OSQLParseNode::test_for_null, "test_for_null" },
{ OSQLParseNode::scalar_exp_commalist, "scalar_exp_commalist" },
{ OSQLParseNode::scalar_exp, "scalar_exp" },
{ OSQLParseNode::parameter_ref, "parameter_ref" },
{ OSQLParseNode::parameter, "parameter" },
{ OSQLParseNode::general_set_fct, "general_set_fct" },
{ OSQLParseNode::range_variable, "range_variable" },
{ OSQLParseNode::column, "column" },
{ OSQLParseNode::delete_statement_positioned, "delete_statement_positioned" },
{ OSQLParseNode::delete_statement_searched, "delete_statement_searched" },
{ OSQLParseNode::update_statement_positioned, "update_statement_positioned" },
{ OSQLParseNode::update_statement_searched, "update_statement_searched" },
{ OSQLParseNode::assignment_commalist, "assignment_commalist" },
{ OSQLParseNode::assignment, "assignment" },
{ OSQLParseNode::values_or_query_spec, "values_or_query_spec" },
{ OSQLParseNode::insert_statement, "insert_statement" },
{ OSQLParseNode::insert_atom_commalist, "insert_atom_commalist" },
{ OSQLParseNode::insert_atom, "insert_atom" },
{ OSQLParseNode::from_clause, "from_clause" },
{ OSQLParseNode::qualified_join, "qualified_join" },
{ OSQLParseNode::cross_union, "cross_union" },
{ OSQLParseNode::select_sublist, "select_sublist" },
{ OSQLParseNode::derived_column, "derived_column" },
{ OSQLParseNode::column_val, "column_val" },
{ OSQLParseNode::set_fct_spec, "set_fct_spec" },
{ OSQLParseNode::boolean_term, "boolean_term" },
{ OSQLParseNode::boolean_primary, "boolean_primary" },
{ OSQLParseNode::num_value_exp, "num_value_exp" },
{ OSQLParseNode::join_type, "join_type" },
{ OSQLParseNode::position_exp, "position_exp" },
{ OSQLParseNode::extract_exp, "extract_exp" },
{ OSQLParseNode::length_exp, "length_exp" },
{ OSQLParseNode::char_value_fct, "char_value_fct" },
{ OSQLParseNode::odbc_call_spec, "odbc_call_spec" },
{ OSQLParseNode::in_predicate, "in_predicate" },
{ OSQLParseNode::existence_test, "existence_test" },
{ OSQLParseNode::unique_test, "unique_test" },
{ OSQLParseNode::all_or_any_predicate, "all_or_any_predicate" },
{ OSQLParseNode::named_columns_join, "named_columns_join" },
{ OSQLParseNode::join_condition, "join_condition" },
{ OSQLParseNode::joined_table, "joined_table" },
{ OSQLParseNode::boolean_factor, "boolean_factor" },
{ OSQLParseNode::sql_not, "sql_not" },
{ OSQLParseNode::manipulative_statement, "manipulative_statement" },
{ OSQLParseNode::subquery, "subquery" },
{ OSQLParseNode::value_exp_commalist, "value_exp_commalist" },
{ OSQLParseNode::odbc_fct_spec, "odbc_fct_spec" },
{ OSQLParseNode::union_statement, "union_statement" },
{ OSQLParseNode::outer_join_type, "outer_join_type" },
{ OSQLParseNode::char_value_exp, "char_value_exp" },
{ OSQLParseNode::term, "term" },
{ OSQLParseNode::value_exp_primary, "value_exp_primary" },
{ OSQLParseNode::value_exp, "value_exp" },
{ OSQLParseNode::selection, "selection" },
{ OSQLParseNode::fold, "fold" },
{ OSQLParseNode::char_substring_fct, "char_substring_fct" },
{ OSQLParseNode::factor, "factor" },
{ OSQLParseNode::base_table_def, "base_table_def" },
{ OSQLParseNode::base_table_element_commalist, "base_table_element_commalist" },
{ OSQLParseNode::data_type, "data_type" },
{ OSQLParseNode::column_def, "column_def" },
{ OSQLParseNode::table_node, "table_node" },
{ OSQLParseNode::as_clause, "as_clause" },
{ OSQLParseNode::opt_as, "opt_as" },
{ OSQLParseNode::op_column_commalist, "op_column_commalist" },
{ OSQLParseNode::table_primary_as_range_column, "table_primary_as_range_column" },
{ OSQLParseNode::datetime_primary, "datetime_primary" },
{ OSQLParseNode::concatenation, "concatenation" },
{ OSQLParseNode::char_factor, "char_factor" },
{ OSQLParseNode::bit_value_fct, "bit_value_fct" },
{ OSQLParseNode::comparison_predicate_part_2, "comparison_predicate_part_2" },
{ OSQLParseNode::parenthesized_boolean_value_expression, "parenthesized_boolean_value_expression" },
{ OSQLParseNode::character_string_type, "character_string_type" },
{ OSQLParseNode::other_like_predicate_part_2, "other_like_predicate_part_2" },
{ OSQLParseNode::between_predicate_part_2, "between_predicate_part_2" },
{ OSQLParseNode::null_predicate_part_2, "null_predicate_part_2" },
{ OSQLParseNode::cast_spec, "cast_spec" },
{ OSQLParseNode::window_function, "window_function" }
};
const size_t nRuleMapCount = SAL_N_ELEMENTS( aRuleDescriptions );
// added a new rule? Adjust this map!
// +1 for UNKNOWN_RULE
static_assert(nRuleMapCount + 1 == static_cast<size_t>(OSQLParseNode::rule_count), "must be equal");
for (const auto & aRuleDescription : aRuleDescriptions)
{
// look up the rule description in the our identifier map
sal_uInt32 nParserRuleID = StrToRuleID( aRuleDescription.sRuleName );
// map the parser's rule ID to the OSQLParseNode::Rule
s_aReverseRuleIDLookup[ nParserRuleID ] = aRuleDescription.eRule;
// and map the OSQLParseNode::Rule to the parser's rule ID
s_nRuleIDs[ aRuleDescription.eRule ] = nParserRuleID;
}
}
++s_nRefCount;
if (m_pContext == nullptr)
// take the default context
m_pContext = &s_aDefaultContext;
m_pData->aLocale = m_pContext->getPreferredLocale();
}
OSQLParser::~OSQLParser()
{
::osl::MutexGuard aGuard(getMutex());
OSL_ENSURE(s_nRefCount > 0, "OSQLParser::~OSQLParser() : suspicious call : has a refcount of 0 !");
if (!--s_nRefCount)
{
s_pScanner->setScanner(true);
delete s_pScanner;
s_pScanner = nullptr;
delete s_pGarbageCollector;
s_pGarbageCollector = nullptr;
// Is only set the first time, so we should delete it only when there are no more instances
s_xLocaleData = nullptr;
RuleIDMap aEmpty;
s_aReverseRuleIDLookup.swap( aEmpty );
}
m_pParseTree = nullptr;
}
void OSQLParseNode::substituteParameterNames(OSQLParseNode const * _pNode)
{
sal_Int32 nCount = _pNode->count();
for(sal_Int32 i=0;i < nCount;++i)
{
OSQLParseNode* pChildNode = _pNode->getChild(i);
if(SQL_ISRULE(pChildNode,parameter) && pChildNode->count() > 1)
{
OSQLParseNode* pNewNode = new OSQLParseNode("?" ,SQLNodeType::Punctuation,0);
delete pChildNode->replace(pChildNode->getChild(0),pNewNode);
sal_Int32 nChildCount = pChildNode->count();
for(sal_Int32 j=1;j < nChildCount;++j)
delete pChildNode->removeAt(1);
}
else
substituteParameterNames(pChildNode);
}
}
bool OSQLParser::extractDate(OSQLParseNode const * pLiteral,double& _rfValue)
{
Reference< XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier();
Reference< XNumberFormatTypes > xFormatTypes;
if ( xFormatSup.is() )
xFormatTypes.set(xFormatSup->getNumberFormats(), css::uno::UNO_QUERY);
// if there is no format key, yet, make sure we have a feasible one for our locale
try
{
if ( !m_nFormatKey && xFormatTypes.is() )
m_nFormatKey = ::dbtools::getDefaultNumberFormat( m_xField, xFormatTypes, m_pData->aLocale );
}
catch( Exception& ) { }
OUString sValue = pLiteral->getTokenValue();
sal_Int32 nTryFormat = m_nFormatKey;
bool bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
// If our format key didn't do, try the default date format for our locale.
if ( !bSuccess && xFormatTypes.is() )
{
try
{
nTryFormat = xFormatTypes->getStandardFormat( NumberFormat::DATE, m_pData->aLocale );
}
catch( Exception& ) { }
bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
}
// if this also didn't do, try ISO format
if ( !bSuccess && xFormatTypes.is() )
{
try
{
nTryFormat = xFormatTypes->getFormatIndex( NumberFormatIndex::DATE_DIN_YYYYMMDD, m_pData->aLocale );
}
catch( Exception& ) { }
bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
}
// if this also didn't do, try fallback date format (en-US)
if ( !bSuccess )
{
nTryFormat = m_nDateFormatKey;
bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue );
}
return bSuccess;
}
OSQLParseNode* OSQLParser::buildDate(sal_Int32 _nType,OSQLParseNode*& pLiteral)
{
// try converting the string into a date, according to our format key
double fValue = 0.0;
OSQLParseNode* pFCTNode = nullptr;
if ( extractDate(pLiteral,fValue) )
pFCTNode = buildNode_Date( fValue, _nType);
delete pLiteral;
pLiteral = nullptr;
if ( !pFCTNode )
m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare);
return pFCTNode;
}
OSQLParseNode::OSQLParseNode(const sal_Char * pNewValue,
SQLNodeType eNewNodeType,
sal_uInt32 nNewNodeID)
:m_pParent(nullptr)
,m_aNodeValue(pNewValue,strlen(pNewValue),RTL_TEXTENCODING_UTF8)
,m_eNodeType(eNewNodeType)
,m_nNodeID(nNewNodeID)
{
OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
}
OSQLParseNode::OSQLParseNode(const OString &_rNewValue,
SQLNodeType eNewNodeType,
sal_uInt32 nNewNodeID)
:m_pParent(nullptr)
,m_aNodeValue(OStringToOUString(_rNewValue,RTL_TEXTENCODING_UTF8))
,m_eNodeType(eNewNodeType)
,m_nNodeID(nNewNodeID)
{
OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
}
OSQLParseNode::OSQLParseNode(const OUString &_rNewValue,
SQLNodeType eNewNodeType,
sal_uInt32 nNewNodeID)
:m_pParent(nullptr)
,m_aNodeValue(_rNewValue)
,m_eNodeType(eNewNodeType)
,m_nNodeID(nNewNodeID)
{
OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType");
}
OSQLParseNode::OSQLParseNode(const OSQLParseNode& rParseNode)
{
// Set the getParent to NULL
m_pParent = nullptr;
// Copy the members
m_aNodeValue = rParseNode.m_aNodeValue;
m_eNodeType = rParseNode.m_eNodeType;
m_nNodeID = rParseNode.m_nNodeID;
// Remember that we derived from Container. According to SV-Help the Container's
// copy ctor creates a new Container with the same pointers for content.
// This means after copying the Container, for all non-NULL pointers a copy is
// created and reattached instead of the old pointer.
// If not a leaf, then process SubTrees
for (auto const& child : rParseNode.m_aChildren)
append(new OSQLParseNode(*child));
}
OSQLParseNode& OSQLParseNode::operator=(const OSQLParseNode& rParseNode)
{
if (this != &rParseNode)
{
// Copy the members - pParent remains the same
m_aNodeValue = rParseNode.m_aNodeValue;
m_eNodeType = rParseNode.m_eNodeType;
m_nNodeID = rParseNode.m_nNodeID;
m_aChildren.clear();
for (auto const& child : rParseNode.m_aChildren)
append(new OSQLParseNode(*child));
}
return *this;
}
bool OSQLParseNode::operator==(OSQLParseNode const & rParseNode) const
{
// The members must be equal
bool bResult = (m_nNodeID == rParseNode.m_nNodeID) &&
(m_eNodeType == rParseNode.m_eNodeType) &&
(m_aNodeValue == rParseNode.m_aNodeValue) &&
count() == rParseNode.count();
// Parameters are not equal!
bResult = bResult && !SQL_ISRULE(this, parameter);
// compare children
for (size_t i=0; bResult && i < count(); i++)
bResult = *getChild(i) == *rParseNode.getChild(i);
return bResult;
}
OSQLParseNode::~OSQLParseNode()
{
}
void OSQLParseNode::append(OSQLParseNode* pNewNode)
{
OSL_ENSURE(pNewNode != nullptr, "OSQLParseNode: invalid NewSubTree");
OSL_ENSURE(pNewNode->getParent() == nullptr, "OSQLParseNode: Node is not an orphan");
OSL_ENSURE(std::find_if(m_aChildren.begin(), m_aChildren.end(),
[&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewNode; })
== m_aChildren.end(),
"OSQLParseNode::append() Node already element of parent");
// Create connection to getParent
pNewNode->setParent( this );
// and attach the SubTree at the end
m_aChildren.emplace_back(pNewNode);
}
bool OSQLParseNode::addDateValue(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
{
// special display for date/time values
if (SQL_ISRULE(this,set_fct_spec) && SQL_ISPUNCTUATION(m_aChildren[0],"{"))
{
const OSQLParseNode* pODBCNode = m_aChildren[1].get();
const OSQLParseNode* pODBCNodeChild = pODBCNode->m_aChildren[0].get();
if (pODBCNodeChild->getNodeType() == SQLNodeType::Keyword && (
SQL_ISTOKEN(pODBCNodeChild, D) ||
SQL_ISTOKEN(pODBCNodeChild, T) ||
SQL_ISTOKEN(pODBCNodeChild, TS) ))
{
OUString suQuote("'");
if (rParam.bPredicate)
{
if (rParam.aMetaData.shouldEscapeDateTime())
{
suQuote = "#";
}
}
else
{
if (rParam.aMetaData.shouldEscapeDateTime())
{
// suQuote = "'";
return false;
}
}
if (!rString.isEmpty())
rString.append(" ");
rString.append(suQuote);
const OUString sTokenValue = pODBCNode->m_aChildren[1]->getTokenValue();
if (SQL_ISTOKEN(pODBCNodeChild, D))
{
rString.append(rParam.bPredicate ? convertDateString(rParam, sTokenValue) : sTokenValue);
}
else if (SQL_ISTOKEN(pODBCNodeChild, T))
{
rString.append(rParam.bPredicate ? convertTimeString(rParam, sTokenValue) : sTokenValue);
}
else
{
rString.append(rParam.bPredicate ? convertDateTimeString(rParam, sTokenValue) : sTokenValue);
}
rString.append(suQuote);
return true;
}
}
return false;
}
void OSQLParseNode::replaceNodeValue(const OUString& rTableAlias, const OUString& rColumnName)
{
for (size_t i=0;i<count();++i)
{
if (SQL_ISRULE(this,column_ref) && count() == 1 && getChild(0)->getTokenValue() == rColumnName)
{
OSQLParseNode * pCol = removeAt(sal_uInt32(0));
append(new OSQLParseNode(rTableAlias,SQLNodeType::Name));
append(new OSQLParseNode(".",SQLNodeType::Punctuation));
append(pCol);
}
else
getChild(i)->replaceNodeValue(rTableAlias,rColumnName);
}
}
OSQLParseNode* OSQLParseNode::getByRule(OSQLParseNode::Rule eRule) const
{
OSQLParseNode* pRetNode = nullptr;
if (isRule() && OSQLParser::RuleID(eRule) == getRuleID())
pRetNode = const_cast<OSQLParseNode*>(this);
else
{
for (auto const& child : m_aChildren)
{
pRetNode = child->getByRule(eRule);
if (pRetNode)
break;
}
}
return pRetNode;
}
OSQLParseNode* MakeANDNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf)
{
OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term));
pNewNode->append(pLeftLeaf);
pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND));
pNewNode->append(pRightLeaf);
return pNewNode;
}
OSQLParseNode* MakeORNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf)
{
OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition));
pNewNode->append(pLeftLeaf);
pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR));
pNewNode->append(pRightLeaf);
return pNewNode;
}
void OSQLParseNode::disjunctiveNormalForm(OSQLParseNode*& pSearchCondition)
{
if(!pSearchCondition) // no where condition at entry point
return;
OSQLParseNode::absorptions(pSearchCondition);
// '(' search_condition ')'
if (SQL_ISRULE(pSearchCondition,boolean_primary))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(1);
disjunctiveNormalForm(pLeft);
}
// search_condition SQL_TOKEN_OR boolean_term
else if (SQL_ISRULE(pSearchCondition,search_condition))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0);
disjunctiveNormalForm(pLeft);
OSQLParseNode* pRight = pSearchCondition->getChild(2);
disjunctiveNormalForm(pRight);
}
// boolean_term SQL_TOKEN_AND boolean_factor
else if (SQL_ISRULE(pSearchCondition,boolean_term))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0);
disjunctiveNormalForm(pLeft);
OSQLParseNode* pRight = pSearchCondition->getChild(2);
disjunctiveNormalForm(pRight);
OSQLParseNode* pNewNode = nullptr;
// '(' search_condition ')' on left side
if(pLeft->count() == 3 && SQL_ISRULE(pLeft,boolean_primary) && SQL_ISRULE(pLeft->getChild(1),search_condition))
{
// and-or tree on left side
OSQLParseNode* pOr = pLeft->getChild(1);
OSQLParseNode* pNewLeft = nullptr;
OSQLParseNode* pNewRight = nullptr;
// cut right from parent
pSearchCondition->removeAt(2);
pNewRight = MakeANDNode(pOr->removeAt(2) ,pRight);
pNewLeft = MakeANDNode(pOr->removeAt(sal_uInt32(0)) ,new OSQLParseNode(*pRight));
pNewNode = MakeORNode(pNewLeft,pNewRight);
// and append new Node
replaceAndReset(pSearchCondition,pNewNode);
disjunctiveNormalForm(pSearchCondition);
}
else if(pRight->count() == 3 && SQL_ISRULE(pRight,boolean_primary) && SQL_ISRULE(pRight->getChild(1),search_condition))
{ // '(' search_condition ')' on right side
// and-or tree on right side
// a and (b or c)
OSQLParseNode* pOr = pRight->getChild(1);
OSQLParseNode* pNewLeft = nullptr;
OSQLParseNode* pNewRight = nullptr;
// cut left from parent
pSearchCondition->removeAt(sal_uInt32(0));
pNewRight = MakeANDNode(pLeft,pOr->removeAt(2));
pNewLeft = MakeANDNode(new OSQLParseNode(*pLeft),pOr->removeAt(sal_uInt32(0)));
pNewNode = MakeORNode(pNewLeft,pNewRight);
// and append new Node
replaceAndReset(pSearchCondition,pNewNode);
disjunctiveNormalForm(pSearchCondition);
}
else if(SQL_ISRULE(pLeft,boolean_primary) && (!SQL_ISRULE(pLeft->getChild(1),search_condition) || !SQL_ISRULE(pLeft->getChild(1),boolean_term)))
pSearchCondition->replace(pLeft, pLeft->removeAt(1));
else if(SQL_ISRULE(pRight,boolean_primary) && (!SQL_ISRULE(pRight->getChild(1),search_condition) || !SQL_ISRULE(pRight->getChild(1),boolean_term)))
pSearchCondition->replace(pRight, pRight->removeAt(1));
}
}
void OSQLParseNode::negateSearchCondition(OSQLParseNode*& pSearchCondition, bool bNegate)
{
if(!pSearchCondition) // no where condition at entry point
return;
// '(' search_condition ')'
if (pSearchCondition->count() == 3 && SQL_ISRULE(pSearchCondition,boolean_primary))
{
OSQLParseNode* pRight = pSearchCondition->getChild(1);
negateSearchCondition(pRight,bNegate);
}
// search_condition SQL_TOKEN_OR boolean_term
else if (SQL_ISRULE(pSearchCondition,search_condition))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0);
OSQLParseNode* pRight = pSearchCondition->getChild(2);
if(bNegate)
{
OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term));
pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0)));
pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND));
pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1)));
replaceAndReset(pSearchCondition,pNewNode);
pLeft = pNewNode->getChild(0);
pRight = pNewNode->getChild(2);
}
negateSearchCondition(pLeft,bNegate);
negateSearchCondition(pRight,bNegate);
}
// boolean_term SQL_TOKEN_AND boolean_factor
else if (SQL_ISRULE(pSearchCondition,boolean_term))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0);
OSQLParseNode* pRight = pSearchCondition->getChild(2);
if(bNegate)
{
OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition));
pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0)));
pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR));
pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1)));
replaceAndReset(pSearchCondition,pNewNode);
pLeft = pNewNode->getChild(0);
pRight = pNewNode->getChild(2);
}
negateSearchCondition(pLeft,bNegate);
negateSearchCondition(pRight,bNegate);
}
// SQL_TOKEN_NOT ( boolean_primary )
else if (SQL_ISRULE(pSearchCondition,boolean_factor))
{
OSQLParseNode *pNot = pSearchCondition->removeAt(sal_uInt32(0));
delete pNot;
OSQLParseNode *pBooleanTest = pSearchCondition->removeAt(sal_uInt32(0));
// TODO is this needed // pBooleanTest->setParent(NULL);
replaceAndReset(pSearchCondition,pBooleanTest);
if (!bNegate)
negateSearchCondition(pSearchCondition, true); // negate all deeper values
}
// row_value_constructor comparison row_value_constructor
// row_value_constructor comparison any_all_some subquery
else if(bNegate && (SQL_ISRULE(pSearchCondition,comparison_predicate) || SQL_ISRULE(pSearchCondition,all_or_any_predicate)))
{
assert(pSearchCondition->count() == 3);
OSQLParseNode* pComparison = pSearchCondition->getChild(1);
if(SQL_ISRULE(pComparison, comparison))
{
assert(pComparison->count() == 2 ||
pComparison->count() == 4);
assert(SQL_ISTOKEN(pComparison->getChild(0), IS));
OSQLParseNode* pNot = pComparison->getChild(1);
OSQLParseNode* pNotNot = nullptr;
if(pNot->isRule()) // no NOT token (empty rule)
pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
else
{
assert(SQL_ISTOKEN(pNot,NOT));
pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
}
pComparison->replace(pNot, pNotNot);
delete pNot;
}
else
{
OSQLParseNode* pNewComparison;
switch(pComparison->getNodeType())
{
default:
case SQLNodeType::Equal:
assert(pComparison->getNodeType() == SQLNodeType::Equal &&
"OSQLParseNode::negateSearchCondition: unexpected node type!");
pNewComparison = new OSQLParseNode("<>",SQLNodeType::NotEqual,SQL_NOTEQUAL);
break;
case SQLNodeType::Less:
pNewComparison = new OSQLParseNode(">=",SQLNodeType::GreatEq,SQL_GREATEQ);
break;
case SQLNodeType::Great:
pNewComparison = new OSQLParseNode("<=",SQLNodeType::LessEq,SQL_LESSEQ);
break;
case SQLNodeType::LessEq:
pNewComparison = new OSQLParseNode(">",SQLNodeType::Great,SQL_GREAT);
break;
case SQLNodeType::GreatEq:
pNewComparison = new OSQLParseNode("<",SQLNodeType::Less,SQL_LESS);
break;
case SQLNodeType::NotEqual:
pNewComparison = new OSQLParseNode("=",SQLNodeType::Equal,SQL_EQUAL);
break;
}
pSearchCondition->replace(pComparison, pNewComparison);
delete pComparison;
}
}
else if(bNegate && (SQL_ISRULE(pSearchCondition,test_for_null) ||
SQL_ISRULE(pSearchCondition,in_predicate) ||
SQL_ISRULE(pSearchCondition,between_predicate) ))
{
OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
sal_uInt32 nNotPos = 0;
if ( SQL_ISRULE( pSearchCondition, test_for_null ) )
nNotPos = 1;
OSQLParseNode* pNot = pPart2->getChild(nNotPos);
OSQLParseNode* pNotNot = nullptr;
if(pNot->isRule()) // no NOT token (empty rule)
pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
else
{
assert(SQL_ISTOKEN(pNot,NOT));
pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
}
pPart2->replace(pNot, pNotNot);
delete pNot;
}
else if(bNegate && SQL_ISRULE(pSearchCondition,like_predicate))
{
OSQLParseNode* pNot = pSearchCondition->getChild( 1 )->getChild( 0 );
OSQLParseNode* pNotNot = nullptr;
if(pNot->isRule())
pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT);
else
pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not));
pSearchCondition->getChild( 1 )->replace(pNot, pNotNot);
delete pNot;
}
}
void OSQLParseNode::eraseBraces(OSQLParseNode*& pSearchCondition)
{
if (pSearchCondition && (SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")"))))
{
OSQLParseNode* pRight = pSearchCondition->getChild(1);
absorptions(pRight);
// if child is not an or and tree then delete () around child
if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) ||
SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || // and can always stand without ()
(SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition)))
{
OSQLParseNode* pNode = pSearchCondition->removeAt(1);
replaceAndReset(pSearchCondition,pNode);
}
}
}
void OSQLParseNode::absorptions(OSQLParseNode*& pSearchCondition)
{
if(!pSearchCondition) // no where condition at entry point
return;
eraseBraces(pSearchCondition);
if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0);
absorptions(pLeft);
OSQLParseNode* pRight = pSearchCondition->getChild(2);
absorptions(pRight);
}
sal_uInt32 nPos = 0;
// a and a || a or a
OSQLParseNode* pNewNode = nullptr;
if(( SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
&& *pSearchCondition->getChild(0) == *pSearchCondition->getChild(2))
{
pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
replaceAndReset(pSearchCondition,pNewNode);
}
// (a or b) and a || ( b or c ) and a
// a and ( a or b) || a and ( b or c )
else if ( SQL_ISRULE(pSearchCondition,boolean_term)
&& (
( SQL_ISRULE(pSearchCondition->getChild(nPos = 0),boolean_primary)
|| SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition)
)
|| ( SQL_ISRULE(pSearchCondition->getChild(nPos = 2),boolean_primary)
|| SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition)
)
)
)
{
OSQLParseNode* p2ndSearch = pSearchCondition->getChild(nPos);
if ( SQL_ISRULE(p2ndSearch,boolean_primary) )
p2ndSearch = p2ndSearch->getChild(1);
if ( *p2ndSearch->getChild(0) == *pSearchCondition->getChild(2-nPos) ) // a and ( a or b) -> a or b
{
pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
replaceAndReset(pSearchCondition,pNewNode);
}
else if ( *p2ndSearch->getChild(2) == *pSearchCondition->getChild(2-nPos) ) // a and ( b or a) -> a or b
{
pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
replaceAndReset(pSearchCondition,pNewNode);
}
else if ( p2ndSearch->getByRule(OSQLParseNode::search_condition) )
{
// a and ( b or c ) -> ( a and b ) or ( a and c )
// ( b or c ) and a -> ( a and b ) or ( a and c )
OSQLParseNode* pC = p2ndSearch->removeAt(sal_uInt32(2));
OSQLParseNode* pB = p2ndSearch->removeAt(sal_uInt32(0));
OSQLParseNode* pA = pSearchCondition->removeAt(sal_uInt32(2)-nPos);
OSQLParseNode* p1stAnd = MakeANDNode(pA,pB);
OSQLParseNode* p2ndAnd = MakeANDNode(new OSQLParseNode(*pA),pC);
pNewNode = MakeORNode(p1stAnd,p2ndAnd);
OSQLParseNode* pNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
pNode->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
pNode->append(pNewNode);
pNode->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
OSQLParseNode::eraseBraces(p1stAnd);
OSQLParseNode::eraseBraces(p2ndAnd);
replaceAndReset(pSearchCondition,pNode);
}
}
// a or a and b || a or b and a
else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term))
{
if(*pSearchCondition->getChild(2)->getChild(0) == *pSearchCondition->getChild(0))
{
pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
replaceAndReset(pSearchCondition,pNewNode);
}
else if(*pSearchCondition->getChild(2)->getChild(2) == *pSearchCondition->getChild(0))
{
pNewNode = pSearchCondition->removeAt(sal_uInt32(0));
replaceAndReset(pSearchCondition,pNewNode);
}
}
// a and b or a || b and a or a
else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term))
{
if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2))
{
pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
replaceAndReset(pSearchCondition,pNewNode);
}
else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2))
{
pNewNode = pSearchCondition->removeAt(sal_uInt32(2));
replaceAndReset(pSearchCondition,pNewNode);
}
}
eraseBraces(pSearchCondition);
}
void OSQLParseNode::compress(OSQLParseNode *&pSearchCondition)
{
if(!pSearchCondition) // no WHERE condition at entry point
return;
OSQLParseNode::eraseBraces(pSearchCondition);
if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0);
compress(pLeft);
OSQLParseNode* pRight = pSearchCondition->getChild(2);
compress(pRight);
}
else if( SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")))
{
OSQLParseNode* pRight = pSearchCondition->getChild(1);
compress(pRight);
// if child is not an or and tree then delete () around child
if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) ||
(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) && SQL_ISRULE(pSearchCondition->getParent(),boolean_term)) ||
(SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition)))
{
OSQLParseNode* pNode = pSearchCondition->removeAt(1);
replaceAndReset(pSearchCondition,pNode);
}
}
// or with two and trees where one element of the and trees are equal
if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term))
{
if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(0))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2);
OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2);
OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
pNewRule->append(pNode);
pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
OSQLParseNode::eraseBraces(pLeft);
OSQLParseNode::eraseBraces(pRight);
pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule);
replaceAndReset(pSearchCondition,pNode);
}
else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(0))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0));
OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2);
OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
pNewRule->append(pNode);
pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
OSQLParseNode::eraseBraces(pLeft);
OSQLParseNode::eraseBraces(pRight);
pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule);
replaceAndReset(pSearchCondition,pNode);
}
else if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(2))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2);
OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0));
OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
pNewRule->append(pNode);
pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
OSQLParseNode::eraseBraces(pLeft);
OSQLParseNode::eraseBraces(pRight);
pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule);
replaceAndReset(pSearchCondition,pNode);
}
else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(2))
{
OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0));
OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0));
OSQLParseNode* pNode = MakeORNode(pLeft,pRight);
OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary));
pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation));
pNewRule->append(pNode);
pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation));
OSQLParseNode::eraseBraces(pLeft);
OSQLParseNode::eraseBraces(pRight);
pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule);
replaceAndReset(pSearchCondition,pNode);
}
}
}
#if OSL_DEBUG_LEVEL > 1
void OSQLParseNode::showParseTree( OUString& rString ) const
{
OUStringBuffer aBuf;
showParseTree( aBuf, 0 );
rString = aBuf.makeStringAndClear();
}
void OSQLParseNode::showParseTree( OUStringBuffer& _inout_rBuffer, sal_uInt32 nLevel ) const
{
for ( sal_uInt32 j=0; j<nLevel; ++j)
_inout_rBuffer.appendAscii( " " );
if ( !isToken() )
{
// Rule name as rule
_inout_rBuffer.appendAscii( "RULE_ID: " );
_inout_rBuffer.append( (sal_Int32)getRuleID() );
_inout_rBuffer.append( '(' );
_inout_rBuffer.append( OSQLParser::RuleIDToStr( getRuleID() ) );
_inout_rBuffer.append( ')' );
_inout_rBuffer.append( '\n' );
// Get the first sub tree
for (auto const& child : m_aChildren)
child->showParseTree( _inout_rBuffer, nLevel+1 );
}
else
{
// Found a token
switch (m_eNodeType)
{
case SQLNodeType::Keyword:
_inout_rBuffer.appendAscii( "SQL_KEYWORD: " );
_inout_rBuffer.append( OStringToOUString( OSQLParser::TokenIDToStr( getTokenID() ), RTL_TEXTENCODING_UTF8 ) );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::Name:
_inout_rBuffer.appendAscii( "SQL_NAME: " );
_inout_rBuffer.append( '"' );
_inout_rBuffer.append( m_aNodeValue );
_inout_rBuffer.append( '"' );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::String:
_inout_rBuffer.appendAscii( "SQL_STRING: " );
_inout_rBuffer.append( '\'' );
_inout_rBuffer.append( m_aNodeValue );
_inout_rBuffer.append( '\'' );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::IntNum:
_inout_rBuffer.appendAscii( "SQL_INTNUM: " );
_inout_rBuffer.append( m_aNodeValue );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::ApproxNum:
_inout_rBuffer.appendAscii( "SQL_APPROXNUM: " );
_inout_rBuffer.append( m_aNodeValue );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::Punctuation:
_inout_rBuffer.appendAscii( "SQL_PUNCTUATION: " );
_inout_rBuffer.append( m_aNodeValue );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::Equal:
case SQLNodeType::Less:
case SQLNodeType::Great:
case SQLNodeType::LessEq:
case SQLNodeType::GreatEq:
case SQLNodeType::NotEqual:
_inout_rBuffer.append( m_aNodeValue );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::AccessDate:
_inout_rBuffer.appendAscii( "SQL_ACCESS_DATE: " );
_inout_rBuffer.append( m_aNodeValue );
_inout_rBuffer.append( '\n' );
break;
case SQLNodeType::Concat:
_inout_rBuffer.appendAscii( "||" );
_inout_rBuffer.append( '\n' );
break;
default:
SAL_INFO( "connectivity.parse", "-- " << int( m_eNodeType ) );
SAL_WARN( "connectivity.parse", "OSQLParser::ShowParseTree: unzulaessiger NodeType" );
}
}
}
#endif // OSL_DEBUG_LEVEL > 0
// Insert methods
void OSQLParseNode::insert(sal_uInt32 nPos, OSQLParseNode* pNewSubTree)
{
OSL_ENSURE(pNewSubTree != nullptr, "OSQLParseNode: invalid NewSubTree");
OSL_ENSURE(pNewSubTree->getParent() == nullptr, "OSQLParseNode: Node is not an orphan");
// Create connection to getParent
pNewSubTree->setParent( this );
m_aChildren.emplace(m_aChildren.begin() + nPos, pNewSubTree);
}
// removeAt methods
OSQLParseNode* OSQLParseNode::removeAt(sal_uInt32 nPos)
{
OSL_ENSURE(nPos < m_aChildren.size(),"Illegal position for removeAt");
auto aPos(m_aChildren.begin() + nPos);
auto pNode = std::move(*aPos);
// Set the getParent of the removed node to NULL
pNode->setParent( nullptr );
m_aChildren.erase(aPos);
return pNode.release();
}
// Replace methods
OSQLParseNode* OSQLParseNode::replace(OSQLParseNode* pOldSubNode, OSQLParseNode* pNewSubNode )
{
OSL_ENSURE(pOldSubNode != nullptr && pNewSubNode != nullptr, "OSQLParseNode: invalid nodes");
OSL_ENSURE(pNewSubNode->getParent() == nullptr, "OSQLParseNode: node already has getParent");
OSL_ENSURE(std::find_if(m_aChildren.begin(), m_aChildren.end(),
[&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pOldSubNode; })
!= m_aChildren.end(),
"OSQLParseNode::Replace() Node not element of parent");
OSL_ENSURE(std::find_if(m_aChildren.begin(), m_aChildren.end(),
[&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewSubNode; })
== m_aChildren.end(),
"OSQLParseNode::Replace() Node already element of parent");
pOldSubNode->setParent( nullptr );
pNewSubNode->setParent( this );
for (auto it = m_aChildren.begin(); it != m_aChildren.end(); ++it)
if (it->get() == pOldSubNode)
{
it->release();
it->reset(pNewSubNode);
break;
}
return pOldSubNode;
}
void OSQLParseNode::parseLeaf(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const
{
// Found a leaf
// Append content to the output string
switch (m_eNodeType)
{
case SQLNodeType::Keyword:
{
if (!rString.isEmpty())
rString.append(" ");
const OString sT = OSQLParser::TokenIDToStr(m_nNodeID, rParam.bInternational ? &rParam.m_rContext : nullptr);
rString.append(OStringToOUString(sT,RTL_TEXTENCODING_UTF8));
} break;
case SQLNodeType::String:
if (!rString.isEmpty())
rString.append(" ");
rString.append(SetQuotation(m_aNodeValue,"\'","\'\'"));
break;
case SQLNodeType::Name:
if (!rString.isEmpty())
{
switch(rString[rString.getLength()-1])
{
case ' ' :
case '.' : break;
default :
if ( rParam.aMetaData.getCatalogSeparator().isEmpty()
|| rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar()
)
rString.append(" ");
break;
}
}
if (rParam.bQuote)
{
if (rParam.bPredicate)
{
rString.append("[");
rString.append(m_aNodeValue);
rString.append("]");
}
else
rString.append(SetQuotation(m_aNodeValue,
rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() ));
}
else
rString.append(m_aNodeValue);
break;
case SQLNodeType::AccessDate:
if (!rString.isEmpty())
rString.append(" ");
rString.append("#");
rString.append(m_aNodeValue);
rString.append("#");
break;
case SQLNodeType::IntNum:
case SQLNodeType::ApproxNum:
{
OUString aTmp = m_aNodeValue;
if (rParam.bInternational && rParam.bPredicate && rParam.cDecSep != '.')
aTmp = aTmp.replace('.', rParam.cDecSep);
if (!rString.isEmpty())
rString.append(" ");
rString.append(aTmp);
} break;
case SQLNodeType::Punctuation:
if ( getParent() && SQL_ISRULE(getParent(),cast_spec) && m_aNodeValue.toChar() == '(' ) // no spaces in front of '('
{
rString.append(m_aNodeValue);
break;
}
SAL_FALLTHROUGH;
default:
if (!rString.isEmpty() && m_aNodeValue.toChar() != '.' && m_aNodeValue.toChar() != ':' )
{
switch( rString[rString.getLength() - 1] )
{
case ' ' :
case '.' : break;
default :
if ( rParam.aMetaData.getCatalogSeparator().isEmpty()
|| rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar()
)
rString.append(" ");
break;
}
}
rString.append(m_aNodeValue);
}
}
sal_Int32 OSQLParser::getFunctionReturnType(const OUString& _sFunctionName, const IParseContext* pContext)
{
sal_Int32 nType = DataType::VARCHAR;
OString sFunctionName(OUStringToOString(_sFunctionName,RTL_TEXTENCODING_UTF8));
if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASCII,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_BIT_LENGTH,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR_LENGTH,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CONCAT,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DIFFERENCE,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_INSERT,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LCASE,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LEFT,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LENGTH,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE_2,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LTRIM,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_OCTET_LENGTH,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POSITION,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPEAT,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPLACE,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RIGHT,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RTRIM,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SOUNDEX,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SPACE,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUBSTRING,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UCASE,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_DATE,pContext))) nType = DataType::DATE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIME,pContext))) nType = DataType::TIME;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIMESTAMP,pContext))) nType = DataType::TIMESTAMP;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURDATE,pContext))) nType = DataType::DATE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEDIFF,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEVALUE,pContext))) nType = DataType::DATE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURTIME,pContext))) nType = DataType::TIME;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYNAME,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFMONTH,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFWEEK,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFYEAR,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXTRACT,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_HOUR,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MINUTE,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTH,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTHNAME,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_NOW,pContext))) nType = DataType::TIMESTAMP;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_QUARTER,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SECOND,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPADD,pContext))) nType = DataType::TIMESTAMP;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPDIFF,pContext))) nType = DataType::TIMESTAMP;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMEVALUE,pContext))) nType = DataType::TIMESTAMP;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_WEEK,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_YEAR,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ABS,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ACOS,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASIN,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN2,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CEILING,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COS,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COT,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DEGREES,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXP,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_FLOOR,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOGF,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG10,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LN,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MOD,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_PI,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POWER,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RADIANS,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RAND,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUND,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUNDMAGIC,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIGN,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIN,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SQRT,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TAN,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TRUNCATE,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COUNT,pContext))) nType = DataType::INTEGER;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MAX,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MIN,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_AVG,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUM,pContext))) nType = DataType::DOUBLE;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOWER,pContext))) nType = DataType::VARCHAR;
else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UPPER,pContext))) nType = DataType::VARCHAR;
return nType;
}
sal_Int32 OSQLParser::getFunctionParameterType(sal_uInt32 _nTokenId, sal_uInt32 _nPos)
{
sal_Int32 nType = DataType::VARCHAR;
if(_nTokenId == SQL_TOKEN_CHAR) nType = DataType::INTEGER;
else if(_nTokenId == SQL_TOKEN_INSERT)
{
if ( _nPos == 2 || _nPos == 3 )
nType = DataType::INTEGER;
}
else if(_nTokenId == SQL_TOKEN_LEFT)
{
if ( _nPos == 2 )
nType = DataType::INTEGER;
}
else if(_nTokenId == SQL_TOKEN_LOCATE)
{
if ( _nPos == 3 )
nType = DataType::INTEGER;
}
else if(_nTokenId == SQL_TOKEN_LOCATE_2)
{
if ( _nPos == 3 )
nType = DataType::INTEGER;
}
else if( _nTokenId == SQL_TOKEN_REPEAT || _nTokenId == SQL_TOKEN_RIGHT )
{
if ( _nPos == 2 )
nType = DataType::INTEGER;
}
else if(_nTokenId == SQL_TOKEN_SPACE )
{
nType = DataType::INTEGER;
}
else if(_nTokenId == SQL_TOKEN_SUBSTRING)
{
if ( _nPos != 1 )
nType = DataType::INTEGER;
}
else if(_nTokenId == SQL_TOKEN_DATEDIFF)
{
if ( _nPos != 1 )
nType = DataType::TIMESTAMP;
}
else if(_nTokenId == SQL_TOKEN_DATEVALUE)
nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_DAYNAME)
nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_DAYOFMONTH)
nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_DAYOFWEEK)
nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_DAYOFYEAR)
nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_EXTRACT) nType = DataType::VARCHAR;
else if(_nTokenId == SQL_TOKEN_HOUR) nType = DataType::TIME;
else if(_nTokenId == SQL_TOKEN_MINUTE) nType = DataType::TIME;
else if(_nTokenId == SQL_TOKEN_MONTH) nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_MONTHNAME) nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_NOW) nType = DataType::TIMESTAMP;
else if(_nTokenId == SQL_TOKEN_QUARTER) nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_SECOND) nType = DataType::TIME;
else if(_nTokenId == SQL_TOKEN_TIMESTAMPADD) nType = DataType::TIMESTAMP;
else if(_nTokenId == SQL_TOKEN_TIMESTAMPDIFF) nType = DataType::TIMESTAMP;
else if(_nTokenId == SQL_TOKEN_TIMEVALUE) nType = DataType::TIMESTAMP;
else if(_nTokenId == SQL_TOKEN_WEEK) nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_YEAR) nType = DataType::DATE;
else if(_nTokenId == SQL_TOKEN_ABS) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_ACOS) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_ASIN) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_ATAN) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_ATAN2) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_CEILING) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_COS) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_COT) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_DEGREES) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_EXP) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_FLOOR) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_LOGF) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_LOG) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_LOG10) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_LN) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_MOD) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_PI) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_POWER) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_RADIANS) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_RAND) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_ROUND) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_ROUNDMAGIC) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_SIGN) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_SIN) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_SQRT) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_TAN) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_TRUNCATE) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_COUNT) nType = DataType::INTEGER;
else if(_nTokenId == SQL_TOKEN_MAX) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_MIN) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_AVG) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_SUM) nType = DataType::DOUBLE;
else if(_nTokenId == SQL_TOKEN_LOWER) nType = DataType::VARCHAR;
else if(_nTokenId == SQL_TOKEN_UPPER) nType = DataType::VARCHAR;
return nType;
}
const SQLError& OSQLParser::getErrorHelper() const
{
return m_pData->aErrors;
}
OSQLParseNode::Rule OSQLParseNode::getKnownRuleID() const
{
if ( !isRule() )
return UNKNOWN_RULE;
return OSQLParser::RuleIDToRule( getRuleID() );
}
OUString OSQLParseNode::getTableRange(const OSQLParseNode* _pTableRef)
{
OSL_ENSURE(_pTableRef && _pTableRef->count() > 1 && _pTableRef->getKnownRuleID() == OSQLParseNode::table_ref,"Invalid node give, only table ref is allowed!");
const sal_uInt32 nCount = _pTableRef->count();
OUString sTableRange;
if ( nCount == 2 || (nCount == 3 && !_pTableRef->getChild(0)->isToken()) )
{
const OSQLParseNode* pNode = _pTableRef->getChild(nCount - (nCount == 2 ? 1 : 2));
OSL_ENSURE(pNode && (pNode->getKnownRuleID() == OSQLParseNode::table_primary_as_range_column
|| pNode->getKnownRuleID() == OSQLParseNode::range_variable)
,"SQL grammar changed!");
if ( !pNode->isLeaf() )
sTableRange = pNode->getChild(1)->getTokenValue();
} // if ( nCount == 2 || nCount == 3 )
return sTableRange;
}
OSQLParseNodesContainer::OSQLParseNodesContainer()
{
}
OSQLParseNodesContainer::~OSQLParseNodesContainer()
{
}
void OSQLParseNodesContainer::push_back(OSQLParseNode* _pNode)
{
::osl::MutexGuard aGuard(m_aMutex);
m_aNodes.push_back(_pNode);
}
void OSQLParseNodesContainer::erase(OSQLParseNode* _pNode)
{
::osl::MutexGuard aGuard(m_aMutex);
if ( !m_aNodes.empty() )
{
std::vector< OSQLParseNode* >::iterator aFind = std::find(m_aNodes.begin(), m_aNodes.end(),_pNode);
if ( aFind != m_aNodes.end() )
m_aNodes.erase(aFind);
}
}
void OSQLParseNodesContainer::clear()
{
::osl::MutexGuard aGuard(m_aMutex);
m_aNodes.clear();
}
void OSQLParseNodesContainer::clearAndDelete()
{
::osl::MutexGuard aGuard(m_aMutex);
// clear the garbage collector
while ( !m_aNodes.empty() )
{
OSQLParseNode* pNode = m_aNodes[0];
while ( pNode->getParent() )
{
pNode = pNode->getParent();
}
delete pNode;
}
}
} // namespace connectivity
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */