Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/connectivity/source/parse/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 116 kB image not shown  

Quelle  sqlnode.cxx   Sprache: 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 <comphelper/diagnose_ex.hxx>
#include <string.h>
#include <algorithm>
#include <functional>
#include <memory>
#include <string_view>

#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <utility>

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()->replaceAndDelete(_pResetNode, _pNewNode);
        _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  rQuote
            The quote
        @param  rQuoteToReplace
            The quote to replace with
        @return
            The quoted string.
    */

    OUString SetQuotation(const OUString& rValue, std::u16string_view rQuote, std::u16string_view rQuoteToReplace)
    {
        // Replace quotes with double quotes or the parser gets into problems
        if (!rQuote.empty())
            return rQuote + rValue.replaceAll(rQuote, rQuoteToReplace) + rQuote;
        return rValue;
    }

    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())
            return false;

        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,
        OUString _sPredicateTableAlias,
        const Locale& _rLocale, const IParseContext* _pContext,
        bool _bIntl, bool _bQuote, OUString _sDecSep, bool _bPredicate, bool _bParseToSDBC )
    :rLocale(_rLocale)
    ,aMetaData( _rxConnection )
    ,pParser( nullptr )
    ,pSubQueryHistory( std::make_shared<QueryNameSet>() )
    ,xFormatter(_xFormatter)
    ,xField(_xField)
    ,sPredicateTableAlias(std::move(_sPredicateTableAlias))
    ,m_rContext( _pContext ? *_pContext : OSQLParser::s_aDefaultContext )
    ,sDecSep(std::move(_sDecSep))
    ,bQuote(_bQuote)
    ,bInternational(_bIntl)
    ,bPredicate(_bPredicate)
    ,bParseToSDBCLevel( _bParseToSDBC )
{
}

OUString OSQLParseNode::convertDateString(const SQLParseNodeParameter& rParam, std::u16string_view 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->getFormatIndex(NumberFormatIndex::DATE_SYS_DDMMYYYY, rParam.rLocale);
    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->getFormatIndex(NumberFormatIndex::DATETIME_SYS_DDMMYYYY_HHMMSS, rParam.rLocale);
    return rParam.xFormatter->convertNumberToString(nKey, fDateTime);
}


OUString OSQLParseNode::convertTimeString(const SQLParseNodeParameter& rParam, std::u16string_view 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->getFormatIndex(NumberFormatIndex::TIME_HHMMSS, rParam.rLocale);
    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, u"."_ustr, false );
}


void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
                                              const Reference< XConnection >& _rxConnection,
                                              const Reference< XNumberFormatter > & xFormatter,
                                              const css::lang::Locale& rIntl,
                                              const OUString& rDec,
                                              const IParseContext* pContext ) const
{
    OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");

    if (xFormatter.is())
        parseNodeToStr(rString, _rxConnection, xFormatter, nullptr, OUString(), rIntl, pContext, truetrue, rDec, 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,
                                              const OUString& rDec,
                                              const IParseContext* pContext ) const
{
    OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!");

    if (xFormatter.is())
        parseNodeToStr( rString, _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext, truetrue, rDec, 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,
                      const OUString& _rDecSep,
                      bool _bPredicate) const
{
    OSL_ENSURE( _rxConnection.is(), "OSQLParseNode::parseNodeToStr: invalid connection!" );

    if ( !_rxConnection.is() )
        return;

    OUStringBuffer sBuffer(rString);
    try
    {
        OSQLParseNode::impl_parseNodeToString_throw( sBuffer,
            SQLParseNodeParameter(
                 _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext,
                _bIntl, _bQuote, _rDecSep, _bPredicate, false
            ) );
    }
    catchconst 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, falsetrueu"."_ustr, falsetrue );

    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();
        delete pTableExp->removeAt(6);
    }

    _out_rString.clear();
    OUStringBuffer sBuffer;
    bool bSuccess = false;
    try
    {
        impl_parseNodeToString_throw( sBuffer, aParseParam );
        bSuccess = true;
    }
    catchconst SQLException& e )
    {
        if ( _pErrorHolder )
            *_pErrorHolder = e;
    }

    if(sLimitValue.getLength() > 0)
    {
        static constexpr char SELECT_KEYWORD[] = "SELECT";
        sBuffer.insert(sBuffer.indexOf(SELECT_KEYWORD) + strlen(SELECT_KEYWORD),
                Concat2View(" 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;
    }

    // Let's 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);
        }
        bHandled = true;
        break;

    case factor:
        bSimple = false;
        if (nCount == 2 && m_aChildren[0] && m_aChildren[1]
            && (SQL_ISPUNCTUATION(m_aChildren[0], "-") || SQL_ISPUNCTUATION(m_aChildren[0], "+"))
            && (m_aChildren[1]->getNodeType() == SQLNodeType::IntNum
                || m_aChildren[1]->getNodeType() == SQLNodeType::ApproxNum))
        {
            // A signed number ("+" or "-" plus either IntNum or ApproxNum)
            // The default processing would first add the sign, then process the number, which
            // would see that rString is not empty already, and insert a space between the sign
            // and the digits. Avoid that unneeded space.
            OUStringBuffer aFactorPara;
            m_aChildren[1]->impl_parseNodeToString_throw(aFactorPara, rParam, bSimple);
            // Insert a space before the signed number, similar to parseLeaf for IntNum / ApproxNum
            if (!rString.isEmpty())
                rString.append(" ");
            rString.append(m_aChildren[0]->getTokenValue() + aFactorPara);
            bHandled = true;
        }
        break;

    case odbc_call_spec:
    case subquery:
    case term:
    case window_function:
    case cast_spec:
    case num_value_exp:
        bSimple = false;
        break;
    default:
        break;
    }   // switch ( getKnownRuleID() )

    if ( bHandled )
        return;

    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)
            {
                // 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;
    }
    catchconst SQLException& )
    {
        throw;
    }
    catchconst 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;

    const 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, u"\'", u"\'\'"));
    }
    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 )
    {
        auto& s_xLocaleData = getLocaleData();
        if ( s_xLocaleData.get()->get()->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, u"Decimals"_ustr );
                                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, u"Decimals"_ustr );
                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 );
    auto& s_xLocaleData = getLocaleData();
    if( s_xLocaleData.get() )
    {
        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, u"");
                OUString sDecimalSeparator = s_xLocaleData.get()->get()->getLocaleItem(m_pData->aLocale).decimalSeparator;
                aValue = aValue.replaceAt(aValue.lastIndexOf('.'), 1, sDecimalSeparator);
                return aValue;
            }
        }
        catch(Exception&)
        {
        }
    }
    return aValue;
}


std::mutex& OSQLParser::getMutex()
{
    static std::mutex aMutex;
    return aMutex;
}


std::unique_ptr<OSQLParseNode> OSQLParser::predicateTree(OUString& rErrorMessageconst OUString& rStatement,
                                         const Reference< css::util::XNumberFormatter > & xFormatter,
                                         const Reference< XPropertySet > & xField,
                                         bool bUseRealName)
{
    // Guard the parsing
    std::unique_lock 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(u"YYYY-MM-DD"_ustr);
                        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:
            {
                auto& s_xLocaleData = getLocaleData();
                if ( s_xLocaleData.get()->get()->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();
        // coverity[leaked_storage : FALSE] - because the garbage collector deleted it
        m_pParseTree.release();
        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 std::move(m_pParseTree);
    }
}


OSQLParser::OSQLParser(css::uno::Reference< css::uno::XComponentContext > xContext,
                       const IParseContext* _pContext,
                       const IParseContext* _pNeutral)
    :m_pContext(_pContext)
    ,m_pNeutral(_pNeutral)
    ,m_pData( new OSQLParser_Data )
    ,m_nFormatKey(0)
    ,m_nDateFormatKey(0)
    ,m_xContext(std::move(xContext))
{


    setParser(this);

#ifdef SQLYYDEBUG
#ifdef SQLYYDEBUG_ON
    SQLyydebug = 1;
#endif
#endif

    std::unique_lock aGuard(getMutex());
    // Do we have to initialize the data?
    if (s_nRefCount == 0)
    {
        s_pScanner = new OSQLScanner();
        s_pScanner->setScanner();
        s_pGarbageCollector = new OSQLParseNodesGarbageCollector();

        auto& s_xLocaleData = getLocaleData();
        if(!s_xLocaleData.get())
            s_xLocaleData.set(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"_ostr },
            { OSQLParseNode::table_exp, "table_exp"_ostr },
            { OSQLParseNode::table_ref_commalist, "table_ref_commalist"_ostr },
            { OSQLParseNode::table_ref, "table_ref"_ostr },
            { OSQLParseNode::catalog_name, "catalog_name"_ostr },
            { OSQLParseNode::schema_name, "schema_name"_ostr },
            { OSQLParseNode::table_name, "table_name"_ostr },
            { OSQLParseNode::opt_column_commalist, "opt_column_commalist"_ostr },
            { OSQLParseNode::column_commalist, "column_commalist"_ostr },
            { OSQLParseNode::column_ref_commalist, "column_ref_commalist"_ostr },
            { OSQLParseNode::column_ref, "column_ref"_ostr },
            { OSQLParseNode::opt_order_by_clause, "opt_order_by_clause"_ostr },
            { OSQLParseNode::ordering_spec_commalist, "ordering_spec_commalist"_ostr },
            { OSQLParseNode::ordering_spec, "ordering_spec"_ostr },
            { OSQLParseNode::opt_asc_desc, "opt_asc_desc"_ostr },
            { OSQLParseNode::where_clause, "where_clause"_ostr },
            { OSQLParseNode::opt_where_clause, "opt_where_clause"_ostr },
            { OSQLParseNode::search_condition, "search_condition"_ostr },
            { OSQLParseNode::comparison, "comparison"_ostr },
            { OSQLParseNode::comparison_predicate, "comparison_predicate"_ostr },
            { OSQLParseNode::between_predicate, "between_predicate"_ostr },
            { OSQLParseNode::like_predicate, "like_predicate"_ostr },
            { OSQLParseNode::opt_escape, "opt_escape"_ostr },
            { OSQLParseNode::test_for_null, "test_for_null"_ostr },
            { OSQLParseNode::scalar_exp_commalist, "scalar_exp_commalist"_ostr },
            { OSQLParseNode::scalar_exp, "scalar_exp"_ostr },
            { OSQLParseNode::parameter_ref, "parameter_ref"_ostr },
            { OSQLParseNode::parameter, "parameter"_ostr },
            { OSQLParseNode::general_set_fct, "general_set_fct"_ostr },
            { OSQLParseNode::range_variable, "range_variable"_ostr },
            { OSQLParseNode::column, "column"_ostr },
            { OSQLParseNode::delete_statement_positioned, "delete_statement_positioned"_ostr },
            { OSQLParseNode::delete_statement_searched, "delete_statement_searched"_ostr },
            { OSQLParseNode::update_statement_positioned, "update_statement_positioned"_ostr },
            { OSQLParseNode::update_statement_searched, "update_statement_searched"_ostr },
            { OSQLParseNode::assignment_commalist, "assignment_commalist"_ostr },
            { OSQLParseNode::assignment, "assignment"_ostr },
            { OSQLParseNode::values_or_query_spec, "values_or_query_spec"_ostr },
            { OSQLParseNode::insert_statement, "insert_statement"_ostr },
            { OSQLParseNode::insert_atom_commalist, "insert_atom_commalist"_ostr },
            { OSQLParseNode::insert_atom, "insert_atom"_ostr },
            { OSQLParseNode::from_clause, "from_clause"_ostr },
            { OSQLParseNode::qualified_join, "qualified_join"_ostr },
            { OSQLParseNode::cross_union, "cross_union"_ostr },
            { OSQLParseNode::select_sublist, "select_sublist"_ostr },
            { OSQLParseNode::derived_column, "derived_column"_ostr },
            { OSQLParseNode::column_val, "column_val"_ostr },
            { OSQLParseNode::set_fct_spec, "set_fct_spec"_ostr },
            { OSQLParseNode::boolean_term, "boolean_term"_ostr },
            { OSQLParseNode::boolean_primary, "boolean_primary"_ostr },
            { OSQLParseNode::num_value_exp, "num_value_exp"_ostr },
            { OSQLParseNode::join_type, "join_type"_ostr },
            { OSQLParseNode::position_exp, "position_exp"_ostr },
            { OSQLParseNode::extract_exp, "extract_exp"_ostr },
            { OSQLParseNode::length_exp, "length_exp"_ostr },
            { OSQLParseNode::char_value_fct, "char_value_fct"_ostr },
            { OSQLParseNode::odbc_call_spec, "odbc_call_spec"_ostr },
            { OSQLParseNode::in_predicate, "in_predicate"_ostr },
            { OSQLParseNode::existence_test, "existence_test"_ostr },
            { OSQLParseNode::unique_test, "unique_test"_ostr },
            { OSQLParseNode::all_or_any_predicate, "all_or_any_predicate"_ostr },
            { OSQLParseNode::named_columns_join, "named_columns_join"_ostr },
            { OSQLParseNode::join_condition, "join_condition"_ostr },
            { OSQLParseNode::joined_table, "joined_table"_ostr },
            { OSQLParseNode::boolean_factor, "boolean_factor"_ostr },
            { OSQLParseNode::sql_not, "sql_not"_ostr },
            { OSQLParseNode::manipulative_statement, "manipulative_statement"_ostr },
            { OSQLParseNode::subquery, "subquery"_ostr },
            { OSQLParseNode::value_exp_commalist, "value_exp_commalist"_ostr },
            { OSQLParseNode::odbc_fct_spec, "odbc_fct_spec"_ostr },
            { OSQLParseNode::union_statement, "union_statement"_ostr },
            { OSQLParseNode::outer_join_type, "outer_join_type"_ostr },
            { OSQLParseNode::char_value_exp, "char_value_exp"_ostr },
            { OSQLParseNode::term, "term"_ostr },
            { OSQLParseNode::value_exp_primary, "value_exp_primary"_ostr },
            { OSQLParseNode::value_exp, "value_exp"_ostr },
            { OSQLParseNode::selection, "selection"_ostr },
            { OSQLParseNode::fold, "fold"_ostr },
            { OSQLParseNode::char_substring_fct, "char_substring_fct"_ostr },
            { OSQLParseNode::factor, "factor"_ostr },
            { OSQLParseNode::base_table_def, "base_table_def"_ostr },
            { OSQLParseNode::base_table_element_commalist, "base_table_element_commalist"_ostr },
            { OSQLParseNode::data_type, "data_type"_ostr },
            { OSQLParseNode::column_def, "column_def"_ostr },
            { OSQLParseNode::table_node, "table_node"_ostr },
            { OSQLParseNode::as_clause, "as_clause"_ostr },
            { OSQLParseNode::opt_as, "opt_as"_ostr },
            { OSQLParseNode::op_column_commalist, "op_column_commalist"_ostr },
            { OSQLParseNode::table_primary_as_range_column, "table_primary_as_range_column"_ostr },
            { OSQLParseNode::datetime_primary, "datetime_primary"_ostr },
            { OSQLParseNode::concatenation, "concatenation"_ostr },
            { OSQLParseNode::char_factor, "char_factor"_ostr },
            { OSQLParseNode::bit_value_fct, "bit_value_fct"_ostr },
            { OSQLParseNode::comparison_predicate_part_2, "comparison_predicate_part_2"_ostr },
            { OSQLParseNode::parenthesized_boolean_value_expression, "parenthesized_boolean_value_expression"_ostr },
            { OSQLParseNode::character_string_type, "character_string_type"_ostr },
            { OSQLParseNode::other_like_predicate_part_2, "other_like_predicate_part_2"_ostr },
            { OSQLParseNode::between_predicate_part_2, "between_predicate_part_2"_ostr },
            { OSQLParseNode::null_predicate_part_2, "null_predicate_part_2"_ostr },
            { OSQLParseNode::cast_spec, "cast_spec"_ostr },
            { OSQLParseNode::window_function, "window_function"_ostr }
        };
        const size_t nRuleMapCount = std::size( 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();
}

//static
tools::DeleteOnDeinit<css::uno::Reference< css::i18n::XLocaleData4>>& OSQLParser::getLocaleData()
{
    static tools::DeleteOnDeinit<css::uno::Reference< css::i18n::XLocaleData4>> s_xLocaleData(tools::DeleteOnDeinitFlag::Empty);
    return s_xLocaleData;
}

OSQLParser::~OSQLParser()
{
    std::unique_lock 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;

        RuleIDMap().swap(s_aReverseRuleIDLookup);
    }
    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);
            pChildNode->replaceAndDelete(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& ) { }
    const 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 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(std::string_view _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(OUString _aNewValue,
                                 SQLNodeType eNewNodeType,
                                 sal_uInt32 nNewNodeID)
        :m_pParent(nullptr)
        ,m_aNodeValue(std::move(_aNewValue))
        ,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));
}


--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=89 H=97 G=93

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.