summaryrefslogtreecommitdiffstats
path: root/connectivity/source/parse
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--connectivity/source/parse/PColumn.cxx271
-rw-r--r--connectivity/source/parse/internalnode.cxx64
-rw-r--r--connectivity/source/parse/sqlbison.y4835
-rw-r--r--connectivity/source/parse/sqlflex.l808
-rw-r--r--connectivity/source/parse/sqliterator.cxx2117
-rw-r--r--connectivity/source/parse/sqlnode.cxx2789
6 files changed, 10884 insertions, 0 deletions
diff --git a/connectivity/source/parse/PColumn.cxx b/connectivity/source/parse/PColumn.cxx
new file mode 100644
index 000000000..5ada4136c
--- /dev/null
+++ b/connectivity/source/parse/PColumn.cxx
@@ -0,0 +1,271 @@
+/* -*- 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 <connectivity/PColumn.hxx>
+#include <TConnection.hxx>
+
+#include <comphelper/types.hxx>
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace dbtools;
+using namespace connectivity::parse;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+
+OParseColumn::OParseColumn(const Reference<XPropertySet>& _xColumn, bool _bCase)
+ : connectivity::sdbcx::OColumn( getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
+ , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
+ , false
+ , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
+ , _bCase
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
+ , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))
+ )
+ , m_bFunction(false)
+ , m_bDbasePrecisionChanged(false)
+ , m_bAggregateFunction(false)
+ , m_bIsSearchable( true )
+{
+ construct();
+}
+
+
+OParseColumn::OParseColumn( const OUString& Name,
+ const OUString& TypeName,
+ const OUString& DefaultValue,
+ const OUString& Description,
+ sal_Int32 IsNullable,
+ sal_Int32 Precision,
+ sal_Int32 Scale,
+ sal_Int32 Type,
+ bool IsAutoIncrement,
+ bool IsCurrency,
+ bool _bCase,
+ const OUString& CatalogName,
+ const OUString& SchemaName,
+ const OUString& TableName
+ ) : connectivity::sdbcx::OColumn(Name,
+ TypeName,
+ DefaultValue,
+ Description,
+ IsNullable,
+ Precision,
+ Scale,
+ Type,
+ IsAutoIncrement,
+ false,
+ IsCurrency,
+ _bCase,
+ CatalogName,
+ SchemaName,
+ TableName)
+ , m_bFunction(false)
+ , m_bDbasePrecisionChanged(false)
+ , m_bAggregateFunction(false)
+ , m_bIsSearchable( true )
+{
+ construct();
+}
+
+
+::rtl::Reference< OSQLColumns > OParseColumn::createColumnsForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData,
+ const Reference< XDatabaseMetaData >& _rxDBMetaData,const Reference< XNameAccess>& i_xQueryColumns )
+{
+ sal_Int32 nColumnCount = _rxResMetaData->getColumnCount();
+ ::rtl::Reference aReturn( new OSQLColumns ); aReturn->reserve( nColumnCount );
+
+ StringMap aColumnMap;
+ for ( sal_Int32 i = 1; i <= nColumnCount; ++i )
+ {
+ rtl::Reference<OParseColumn> pColumn = createColumnForResultSet( _rxResMetaData, _rxDBMetaData, i,aColumnMap );
+ aReturn->push_back( pColumn );
+ if ( i_xQueryColumns.is() && i_xQueryColumns->hasByName(pColumn->getRealName()) )
+ {
+ Reference<XPropertySet> xColumn(i_xQueryColumns->getByName(pColumn->getRealName()),UNO_QUERY_THROW);
+ OUString sLabel;
+ xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL)) >>= sLabel;
+ if ( !sLabel.isEmpty() )
+ pColumn->setLabel(sLabel);
+ }
+ }
+
+ return aReturn;
+}
+
+
+rtl::Reference<OParseColumn> OParseColumn::createColumnForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData,
+ const Reference< XDatabaseMetaData >& _rxDBMetaData, sal_Int32 _nColumnPos, StringMap& _rColumns )
+{
+ OUString sLabel = _rxResMetaData->getColumnLabel( _nColumnPos );
+ // retrieve the name of the column
+ // check for duplicate entries
+ if(_rColumns.find(sLabel) != _rColumns.end())
+ {
+ OUString sAlias(sLabel);
+ sal_Int32 searchIndex=1;
+ while(_rColumns.find(sAlias) != _rColumns.end())
+ {
+ sAlias = sLabel + OUString::number(searchIndex++);
+ }
+ sLabel = sAlias;
+ }
+ _rColumns.emplace(sLabel,0);
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(
+ sLabel,
+ _rxResMetaData->getColumnTypeName( _nColumnPos ),
+ OUString(),
+ OUString(),
+ _rxResMetaData->isNullable( _nColumnPos ),
+ _rxResMetaData->getPrecision( _nColumnPos ),
+ _rxResMetaData->getScale( _nColumnPos ),
+ _rxResMetaData->getColumnType( _nColumnPos ),
+ _rxResMetaData->isAutoIncrement( _nColumnPos ),
+ _rxResMetaData->isCurrency( _nColumnPos ),
+ _rxDBMetaData->supportsMixedCaseQuotedIdentifiers(),
+ _rxResMetaData->getCatalogName( _nColumnPos ),
+ _rxResMetaData->getSchemaName( _nColumnPos ),
+ _rxResMetaData->getTableName( _nColumnPos )
+ );
+ pColumn->setIsSearchable( _rxResMetaData->isSearchable( _nColumnPos ) );
+ pColumn->setRealName(_rxResMetaData->getColumnName( _nColumnPos ));
+ pColumn->setLabel(sLabel);
+ return pColumn;
+}
+
+
+OParseColumn::~OParseColumn()
+{
+}
+
+void OParseColumn::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION), PROPERTY_ID_FUNCTION, 0, &m_bFunction, cppu::UnoType<decltype(m_bFunction)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AGGREGATEFUNCTION), PROPERTY_ID_AGGREGATEFUNCTION, 0, &m_bAggregateFunction, cppu::UnoType<decltype(m_bAggregateFunction)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME), PROPERTY_ID_REALNAME, 0, &m_aRealName, cppu::UnoType<decltype(m_aRealName)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DBASEPRECISIONCHANGED), PROPERTY_ID_DBASEPRECISIONCHANGED, 0, &m_bDbasePrecisionChanged, cppu::UnoType<decltype(m_bDbasePrecisionChanged)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSEARCHABLE), PROPERTY_ID_ISSEARCHABLE, 0, &m_bIsSearchable, cppu::UnoType<decltype(m_bIsSearchable)>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL), PROPERTY_ID_LABEL, 0, &m_sLabel, cppu::UnoType<decltype(m_sLabel)>::get());
+}
+
+::cppu::IPropertyArrayHelper* OParseColumn::createArrayHelper() const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL OParseColumn::getInfoHelper()
+{
+ OSL_ENSURE( !isNew(), "OParseColumn::getInfoHelper: a *new* ParseColumn?" );
+ return *OParseColumn_PROP::getArrayHelper();
+}
+
+
+OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, const OUString& i_rOriginatingTableName,
+ bool _bCase, bool _bAscending )
+ : connectivity::sdbcx::OColumn(
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))),
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))),
+ false,
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))),
+ _bCase,
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))),
+ i_rOriginatingTableName
+ )
+ ,m_bAscending(_bAscending)
+{
+ construct();
+}
+
+
+OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, bool _bCase, bool _bAscending )
+ : connectivity::sdbcx::OColumn(
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))),
+ getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))),
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))),
+ false,
+ getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))),
+ _bCase,
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))),
+ getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))
+ )
+ ,m_bAscending(_bAscending)
+{
+ construct();
+}
+
+
+OOrderColumn::~OOrderColumn()
+{
+}
+
+
+void OOrderColumn::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING,
+ PropertyAttribute::READONLY, const_cast< bool* >( &m_bAscending ), cppu::UnoType<decltype(m_bAscending)>::get() );
+}
+
+::cppu::IPropertyArrayHelper* OOrderColumn::createArrayHelper() const
+{
+ return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL OOrderColumn::getInfoHelper()
+{
+ OSL_ENSURE( !isNew(), "OOrderColumn::getInfoHelper: a *new* OrderColumn?" );
+ return *OOrderColumn_PROP::getArrayHelper();
+}
+
+css::uno::Sequence< OUString > SAL_CALL OOrderColumn::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.OrderColumn" };
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/internalnode.cxx b/connectivity/source/parse/internalnode.cxx
new file mode 100644
index 000000000..1906ad3d4
--- /dev/null
+++ b/connectivity/source/parse/internalnode.cxx
@@ -0,0 +1,64 @@
+/* -*- 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 <connectivity/sqlparse.hxx>
+#include <connectivity/internalnode.hxx>
+
+using namespace connectivity;
+
+
+OSQLInternalNode::OSQLInternalNode(const char* pNewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ : OSQLParseNode(pNewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::OSQLInternalNode(std::string_view NewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ :OSQLParseNode(NewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::OSQLInternalNode(const OUString &NewValue,
+ SQLNodeType eNodeType,
+ sal_uInt32 nNodeID)
+ :OSQLParseNode(NewValue,eNodeType,nNodeID)
+{
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->push_back(this);
+}
+
+
+OSQLInternalNode::~OSQLInternalNode()
+{
+ // remove the node from the garbage list
+
+ OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized");
+ (*OSQLParser::s_pGarbageCollector)->erase(this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/sqlbison.y b/connectivity/source/parse/sqlbison.y
new file mode 100644
index 000000000..e0e9969ab
--- /dev/null
+++ b/connectivity/source/parse/sqlbison.y
@@ -0,0 +1,4835 @@
+%glr-parser
+%token-table
+%{
+/*
+ * 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 <vector>
+#include <string.h>
+
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlbison_exports.hxx>
+#include <connectivity/sqlscan.hxx>
+#include <connectivity/internalnode.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/XNumberFormatter.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/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/i18n/KParseType.hpp>
+#include <com/sun/star/i18n/KParseTokens.hpp>
+
+#include <osl/diagnose.h>
+#include "connectivity/dbconversion.hxx"
+#include <rtl/ustrbuf.hxx>
+#include <sal/macros.h>
+#include <sal/log.hxx>
+
+#if defined _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4324) // structure was padded due to alignment specifier
+#pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels
+#pragma warning(disable: 4702) // unreachable code
+#endif
+
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wwrite-strings"
+# pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+inline connectivity::OSQLInternalNode* newNode(const char* pNewValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+inline connectivity::OSQLInternalNode* newNode(const OString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+inline connectivity::OSQLInternalNode* newNode(const OUString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID = 0);
+
+
+// yyi is the internal number of the rule that is currently being reduced
+// This can be mapped to external rule number via the yyrmap.
+#if defined YYBISON && YYBISON >= 30800
+#define SQL_NEW_RULE newNode("", SQLNodeType::Rule, yyr1[yyrule])
+#define SQL_NEW_LISTRULE newNode("", SQLNodeType::ListRule, yyr1[yyrule])
+#define SQL_NEW_COMMALISTRULE newNode("", SQLNodeType::CommaListRule, yyr1[yyrule])
+#else
+#define SQL_NEW_RULE newNode("", SQLNodeType::Rule, yyr1[yyn])
+#define SQL_NEW_LISTRULE newNode("", SQLNodeType::ListRule, yyr1[yyn])
+#define SQL_NEW_COMMALISTRULE newNode("", SQLNodeType::CommaListRule, yyr1[yyn])
+#endif
+
+
+extern connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER;
+
+#define YYERROR_VERBOSE
+
+#define SQLyyerror(s) \
+{ \
+ xxx_pGLOBAL_SQLPARSER->error(s); \
+}
+
+using namespace connectivity;
+#define SQLyylex xxx_pGLOBAL_SQLPARSER->SQLlex
+%}
+ /* symbolic tokens */
+
+%union {
+ connectivity::OSQLParseNode * pParseNode;
+}
+%type <pParseNode> '(' ')' ',' ':' ';' '?' '[' ']' '{' '}' '.' 'K' 'M' 'G' 'T' 'P'
+
+%token <pParseNode> SQL_TOKEN_STRING SQL_TOKEN_ACCESS_DATE SQL_TOKEN_INT SQL_TOKEN_REAL_NUM
+%token <pParseNode> SQL_TOKEN_INTNUM SQL_TOKEN_APPROXNUM SQL_TOKEN_NOT SQL_TOKEN_NAME
+
+
+%nonassoc <pParseNode> SQL_TOKEN_UMINUS
+
+
+
+ /* literal keyword tokens */
+
+%token <pParseNode> SQL_TOKEN_ALL SQL_TOKEN_ALTER SQL_TOKEN_AMMSC SQL_TOKEN_ANY SQL_TOKEN_AS SQL_TOKEN_ASC SQL_TOKEN_AT SQL_TOKEN_AUTHORIZATION SQL_TOKEN_AVG
+
+%token <pParseNode> SQL_TOKEN_BETWEEN SQL_TOKEN_BIT SQL_TOKEN_BOTH SQL_TOKEN_BY
+
+%token <pParseNode> SQL_TOKEN_CAST SQL_TOKEN_CHARACTER SQL_TOKEN_CHECK SQL_TOKEN_COLLATE SQL_TOKEN_COMMIT SQL_TOKEN_CONTINUE SQL_TOKEN_CONVERT SQL_TOKEN_COUNT SQL_TOKEN_CREATE SQL_TOKEN_CROSS
+%token <pParseNode> SQL_TOKEN_CURRENT SQL_TOKEN_CURSOR
+
+%token <pParseNode> SQL_TOKEN_DATE SQL_TOKEN_DATEVALUE SQL_TOKEN_DAY SQL_TOKEN_DEC SQL_TOKEN_DECIMAL SQL_TOKEN_DECLARE SQL_TOKEN_DEFAULT SQL_TOKEN_DELETE SQL_TOKEN_DESC
+%token <pParseNode> SQL_TOKEN_DISTINCT SQL_TOKEN_DOUBLE SQL_TOKEN_DROP
+
+%token <pParseNode> SQL_TOKEN_ESCAPE SQL_TOKEN_EXCEPT SQL_TOKEN_EXISTS SQL_TOKEN_FALSE SQL_TOKEN_FETCH SQL_TOKEN_FLOAT SQL_TOKEN_FOR SQL_TOKEN_FOREIGN SQL_TOKEN_FOUND SQL_TOKEN_FROM SQL_TOKEN_FULL
+
+%token <pParseNode> SQL_TOKEN_GRANT SQL_TOKEN_GROUP SQL_TOKEN_HAVING SQL_TOKEN_IN SQL_TOKEN_INDICATOR SQL_TOKEN_INNER SQL_TOKEN_INTEGER SQL_TOKEN_INTO SQL_TOKEN_IS SQL_TOKEN_INTERSECT
+
+%left <pParseNode> SQL_TOKEN_JOIN
+%token <pParseNode> SQL_TOKEN_KEY SQL_TOKEN_LEADING SQL_TOKEN_LIKE SQL_TOKEN_LOCAL SQL_TOKEN_LOWER
+%token <pParseNode> SQL_TOKEN_MAX SQL_TOKEN_MIN SQL_TOKEN_NATURAL SQL_TOKEN_NCHAR SQL_TOKEN_NULL SQL_TOKEN_NUMERIC
+
+%token <pParseNode> SQL_TOKEN_OCTET_LENGTH SQL_TOKEN_OF SQL_TOKEN_ON SQL_TOKEN_OPTION SQL_TOKEN_ORDER SQL_TOKEN_OUTER
+
+%token <pParseNode> SQL_TOKEN_PRECISION SQL_TOKEN_PRIMARY SQL_TOKEN_PRIVILEGES SQL_TOKEN_PROCEDURE SQL_TOKEN_PUBLIC
+%token <pParseNode> SQL_TOKEN_REAL SQL_TOKEN_REFERENCES SQL_TOKEN_ROLLBACK
+
+%token <pParseNode> SQL_TOKEN_SCHEMA SQL_TOKEN_SELECT SQL_TOKEN_SET SQL_TOKEN_SIZE SQL_TOKEN_SMALLINT SQL_TOKEN_SOME SQL_TOKEN_SQLCODE SQL_TOKEN_SQLERROR SQL_TOKEN_SUM
+
+%token <pParseNode> SQL_TOKEN_TABLE SQL_TOKEN_TIME SQL_TOKEN_TIMESTAMP SQL_TOKEN_TIMEZONE_HOUR SQL_TOKEN_TIMEZONE_MINUTE SQL_TOKEN_TO SQL_TOKEN_TRAILING SQL_TOKEN_TRANSLATE SQL_TOKEN_TRIM SQL_TOKEN_TRUE SQL_TOKEN_UNION
+%token <pParseNode> SQL_TOKEN_UNIQUE SQL_TOKEN_UNKNOWN SQL_TOKEN_UPDATE SQL_TOKEN_UPPER SQL_TOKEN_USAGE SQL_TOKEN_USER SQL_TOKEN_USING SQL_TOKEN_VALUES SQL_TOKEN_VIEW
+%token <pParseNode> SQL_TOKEN_WHERE SQL_TOKEN_WITH SQL_TOKEN_WORK SQL_TOKEN_ZONE
+
+/* ODBC KEYWORDS */
+%token <pParseNode> SQL_TOKEN_CALL SQL_TOKEN_D SQL_TOKEN_FN SQL_TOKEN_T SQL_TOKEN_TS SQL_TOKEN_OJ
+/* string functions */
+%token <pParseNode> SQL_TOKEN_ASCII SQL_TOKEN_BIT_LENGTH SQL_TOKEN_CHAR SQL_TOKEN_CHAR_LENGTH SQL_TOKEN_SQL_TOKEN_INTNUM
+%token <pParseNode> SQL_TOKEN_CONCAT
+%token <pParseNode> SQL_TOKEN_DIFFERENCE SQL_TOKEN_INSERT SQL_TOKEN_LCASE SQL_TOKEN_LEFT SQL_TOKEN_LENGTH SQL_TOKEN_LOCATE
+%token <pParseNode> SQL_TOKEN_LOCATE_2 SQL_TOKEN_LTRIM SQL_TOKEN_POSITION SQL_TOKEN_REPEAT SQL_TOKEN_REPLACE
+%token <pParseNode> SQL_TOKEN_RIGHT SQL_TOKEN_RTRIM SQL_TOKEN_SOUNDEX SQL_TOKEN_SPACE SQL_TOKEN_SUBSTRING SQL_TOKEN_UCASE
+
+/* time and date functions */
+%token <pParseNode> SQL_TOKEN_CURRENT_DATE SQL_TOKEN_CURRENT_TIME SQL_TOKEN_CURRENT_TIMESTAMP SQL_TOKEN_CURDATE SQL_TOKEN_CURTIME
+%token <pParseNode> SQL_TOKEN_DAYNAME SQL_TOKEN_DAYOFMONTH SQL_TOKEN_DAYOFWEEK SQL_TOKEN_DAYOFYEAR SQL_TOKEN_EXTRACT
+%token <pParseNode> SQL_TOKEN_HOUR SQL_TOKEN_MILLISECOND SQL_TOKEN_MINUTE SQL_TOKEN_MONTH SQL_TOKEN_MONTHNAME SQL_TOKEN_NOW SQL_TOKEN_QUARTER SQL_TOKEN_DATEDIFF
+%token <pParseNode> SQL_TOKEN_SECOND SQL_TOKEN_TIMESTAMPADD SQL_TOKEN_TIMESTAMPDIFF SQL_TOKEN_TIMEVALUE SQL_TOKEN_WEEK SQL_TOKEN_WEEKDAY SQL_TOKEN_YEAR SQL_TOKEN_YEARDAY
+
+/* numeric functions */
+%token <pParseNode> SQL_TOKEN_ABS SQL_TOKEN_ACOS SQL_TOKEN_ASIN SQL_TOKEN_ATAN SQL_TOKEN_ATAN2 SQL_TOKEN_CEILING
+%token <pParseNode> SQL_TOKEN_COS SQL_TOKEN_COT SQL_TOKEN_DEGREES SQL_TOKEN_EXP SQL_TOKEN_FLOOR SQL_TOKEN_LOGF SQL_TOKEN_LOG SQL_TOKEN_LN
+%token <pParseNode> SQL_TOKEN_LOG10 SQL_TOKEN_MOD SQL_TOKEN_PI SQL_TOKEN_POWER SQL_TOKEN_RADIANS SQL_TOKEN_RAND SQL_TOKEN_ROUNDMAGIC
+%token <pParseNode> SQL_TOKEN_ROUND SQL_TOKEN_SIGN SQL_TOKEN_SIN SQL_TOKEN_SQRT SQL_TOKEN_TAN SQL_TOKEN_TRUNCATE
+
+// computational operation
+%token <pParseNode> SQL_TOKEN_EVERY SQL_TOKEN_INTERSECTION SQL_TOKEN_FUSION SQL_TOKEN_COLLECT SQL_TOKEN_VAR_POP SQL_TOKEN_VAR_SAMP
+%token <pParseNode> SQL_TOKEN_STDDEV_SAMP SQL_TOKEN_STDDEV_POP
+
+%token <pParseNode> SQL_TOKEN_RANK SQL_TOKEN_DENSE_RANK SQL_TOKEN_PERCENT_RANK SQL_TOKEN_CUME_DIST SQL_TOKEN_PERCENTILE_CONT SQL_TOKEN_PERCENTILE_DISC SQL_TOKEN_WITHIN SQL_TOKEN_ARRAY_AGG
+%token <pParseNode> SQL_TOKEN_CASE SQL_TOKEN_THEN SQL_TOKEN_END SQL_TOKEN_NULLIF SQL_TOKEN_COALESCE SQL_TOKEN_WHEN SQL_TOKEN_ELSE
+%token <pParseNode> SQL_TOKEN_BEFORE SQL_TOKEN_AFTER SQL_TOKEN_INSTEAD SQL_TOKEN_EACH SQL_TOKEN_REFERENCING SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_TOKEN_TRIGGER SQL_TOKEN_ROW SQL_TOKEN_STATEMENT
+%token <pParseNode> SQL_TOKEN_NEW SQL_TOKEN_OLD
+%token <pParseNode> SQL_TOKEN_VALUE SQL_TOKEN_CURRENT_CATALOG SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP SQL_TOKEN_CURRENT_PATH SQL_TOKEN_CURRENT_ROLE SQL_TOKEN_CURRENT_SCHEMA SQL_TOKEN_CURRENT_USER
+%token <pParseNode> SQL_TOKEN_SESSION_USER SQL_TOKEN_SYSTEM_USER SQL_TOKEN_VARCHAR SQL_TOKEN_VARBINARY SQL_TOKEN_VARYING SQL_TOKEN_OBJECT SQL_TOKEN_NCLOB SQL_TOKEN_NATIONAL
+%token <pParseNode> SQL_TOKEN_LARGE SQL_TOKEN_CLOB SQL_TOKEN_BLOB SQL_TOKEN_BIGINT SQL_TOKEN_BINARY SQL_TOKEN_WITHOUT SQL_TOKEN_BOOLEAN SQL_TOKEN_INTERVAL
+// window function
+%token <pParseNode> SQL_TOKEN_OVER SQL_TOKEN_ROW_NUMBER SQL_TOKEN_NTILE SQL_TOKEN_LEAD SQL_TOKEN_LAG SQL_TOKEN_RESPECT SQL_TOKEN_IGNORE SQL_TOKEN_NULLS
+%token <pParseNode> SQL_TOKEN_FIRST_VALUE SQL_TOKEN_LAST_VALUE SQL_TOKEN_NTH_VALUE SQL_TOKEN_FIRST SQL_TOKEN_LAST
+%token <pParseNode> SQL_TOKEN_EXCLUDE SQL_TOKEN_OTHERS SQL_TOKEN_TIES SQL_TOKEN_FOLLOWING SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING SQL_TOKEN_RANGE SQL_TOKEN_ROWS
+%token <pParseNode> SQL_TOKEN_PARTITION SQL_TOKEN_WINDOW SQL_TOKEN_NO
+// LIMIT and OFFSEt
+%token <pParseNode> SQL_TOKEN_LIMIT SQL_TOKEN_OFFSET SQL_TOKEN_NEXT SQL_TOKEN_ONLY
+
+ /* operators */
+%left SQL_TOKEN_NAME
+%left <pParseNode> SQL_TOKEN_OR
+%left <pParseNode> SQL_TOKEN_AND
+
+%left <pParseNode> SQL_LESSEQ SQL_GREATEQ SQL_NOTEQUAL SQL_LESS SQL_GREAT SQL_EQUAL /* '<' '>' = <> < > <= >= != */
+%left <pParseNode> '+' '-' SQL_CONCAT
+%left <pParseNode> '*' '/'
+%left SQL_TOKEN_NATURAL SQL_TOKEN_CROSS SQL_TOKEN_FULL SQL_TOKEN_LEFT SQL_TOKEN_RIGHT
+%left ')'
+%right '='
+%right '.'
+%right '('
+
+
+%token <pParseNode> SQL_TOKEN_INVALIDSYMBOL
+
+/*%type <pParseNode> sql_single_statement */
+
+%type <pParseNode> sql /*schema */
+%type <pParseNode> column_def_opt_list column_def_opt table_constraint_def column_commalist
+%type <pParseNode> view_def opt_with_check_option opt_column_commalist privilege_def
+%type <pParseNode> opt_with_grant_option privileges operation_commalist operation
+%type <pParseNode> grantee_commalist grantee opt_order_by_clause ordering_spec_commalist
+%type <pParseNode> ordering_spec opt_asc_desc manipulative_statement commit_statement
+%type <pParseNode> /*delete_statement_positioned*/ delete_statement_searched fetch_statement
+%type <pParseNode> insert_statement values_or_query_spec
+%type <pParseNode> rollback_statement select_statement_into opt_all_distinct
+%type <pParseNode> /*update_statement_positioned*/ assignment_commalist assignment
+%type <pParseNode> update_statement_searched target_commalist target opt_where_clause
+%type <pParseNode> select_statement selection table_exp from_clause table_ref_commalist table_ref
+%type <pParseNode> where_clause opt_group_by_clause column_ref_commalist opt_having_clause
+%type <pParseNode> search_condition predicate comparison_predicate comparison_predicate_part_2 between_predicate between_predicate_part_2
+%type <pParseNode> like_predicate opt_escape test_for_null null_predicate_part_2 in_predicate in_predicate_part_2 character_like_predicate_part_2 other_like_predicate_part_2
+%type <pParseNode> all_or_any_predicate any_all_some existence_test subquery quantified_comparison_predicate_part_2
+%type <pParseNode> scalar_exp_commalist parameter_ref literal parenthesized_boolean_value_expression
+%type <pParseNode> column_ref data_type column cursor parameter range_variable user /*like_check*/
+/* new rules at OJ */
+%type <pParseNode> derived_column as_clause table_name num_primary term num_value_exp
+%type <pParseNode> value_exp_primary num_value_fct unsigned_value_spec cast_spec set_fct_spec scalar_subquery
+%type <pParseNode> position_exp extract_exp length_exp general_value_spec
+%type <pParseNode> general_set_fct set_fct_type query_exp non_join_query_exp joined_table
+%type <pParseNode> non_join_query_term non_join_query_primary simple_table
+%type <pParseNode> table_value_const_list row_value_constructor /*row_value_const_list*/ row_value_constructor_elem
+%type <pParseNode> qualified_join value_exp query_term join_type outer_join_type join_condition boolean_term
+%type <pParseNode> boolean_factor boolean_primary named_columns_join join_spec
+%type <pParseNode> cast_operand cast_target factor datetime_value_exp /*interval_value_exp*/ datetime_term datetime_factor
+%type <pParseNode> datetime_primary datetime_value_fct time_zone time_zone_specifier /*interval_term*/ interval_qualifier
+%type <pParseNode> start_field non_second_datetime_field end_field single_datetime_field extract_field datetime_field time_zone_field
+%type <pParseNode> char_length_exp octet_length_exp bit_length_exp select_sublist string_value_exp
+%type <pParseNode> char_value_exp concatenation char_factor char_primary string_value_fct char_substring_fct fold
+%type <pParseNode> form_conversion char_translation trim_fct trim_operands trim_spec bit_value_fct bit_substring_fct op_column_commalist
+%type <pParseNode> /*bit_concatenation*/ bit_value_exp bit_factor bit_primary collate_clause char_value_fct unique_spec value_exp_commalist in_predicate_value unique_test update_source
+%type <pParseNode> function_arg_commalist3 string_function_3Argument function_arg_commalist4 string_function_4Argument function_arg_commalist2 string_function_1Argument string_function_2Argument
+%type <pParseNode> date_function_0Argument date_function_1Argument function_name12 function_name23 function_name1 function_name2 function_name3 function_name0 numeric_function_0Argument numeric_function_1Argument numeric_function_2Argument
+%type <pParseNode> all query_primary sql_not for_length upper_lower comparison column_val cross_union /*opt_schema_element_list*/
+%type <pParseNode> /*op_authorization op_schema*/ nil_fkt schema_element base_table_def base_table_element base_table_element_commalist
+%type <pParseNode> column_def odbc_fct_spec odbc_call_spec odbc_fct_type op_parameter union_statement
+%type <pParseNode> op_odbc_call_parameter odbc_parameter_commalist odbc_parameter function_args_commalist function_arg
+%type <pParseNode> catalog_name schema_name table_node numeric_function string_function function_name date_function table_primary_as_range_column opt_as
+%type <pParseNode> ordered_set_function inverse_distribution_function hypothetical_set_function hypothetical_set_function_value_expression_list rank_function_type within_group_specification inverse_distribution_function_type array_aggregate_function inverse_distribution_function_argument
+%type <pParseNode> case_expression else_clause result_expression result case_abbreviation case_specification searched_when_clause simple_when_clause searched_case simple_case
+%type <pParseNode> when_operand_list when_operand case_operand
+%type <pParseNode> trigger_definition trigger_name trigger_action_time trigger_event transition_table_or_variable_list triggered_action trigger_column_list triggered_when_clause triggered_SQL_statement SQL_procedure_statement old_transition_variable_name new_transition_variable_name
+%type <pParseNode> op_referencing op_trigger_columnlist op_triggered_action_for opt_row trigger_for SQL_procedure_statement_list transition_table_or_variable old_transition_table_name new_transition_table_name transition_table_name
+%type <pParseNode> searched_when_clause_list simple_when_clause_list predefined_type opt_char_set_spec opt_collate_clause character_string_type national_character_string_type
+%type <pParseNode> binary_string_type numeric_type boolean_type datetime_type interval_type opt_paren_precision paren_char_length opt_paren_char_large_length paren_character_large_object_length
+%type <pParseNode> large_object_length opt_multiplier character_large_object_type national_character_large_object_type binary_large_object_string_type opt_with_or_without_time_zone
+%type <pParseNode> approximate_numeric_type exact_numeric_type opt_paren_precision_scale
+/* window function rules */
+%type <pParseNode> window_function window_function_type ntile_function number_of_tiles lead_or_lag_function lead_or_lag lead_or_lag_extent offset default_expression null_treatment
+%type <pParseNode> first_or_last_value_function first_or_last_value nth_value_function nth_row from_first_or_last window_name_or_specification in_line_window_specification opt_lead_or_lag_function
+%type <pParseNode> opt_null_treatment opt_from_first_or_last simple_value_specification dynamic_parameter_specification window_name window_clause window_definition_list window_definition
+%type <pParseNode> new_window_name existing_window_name window_partition_clause window_partition_column_reference_list window_partition_column_reference window_frame_clause
+%type <pParseNode> window_frame_units window_frame_extent window_frame_start window_frame_preceding window_frame_between window_frame_bound_1 window_frame_bound_2 window_frame_bound window_frame_following window_frame_exclusion
+%type <pParseNode> opt_window_frame_clause opt_window_partition_clause opt_existing_window_name window_specification opt_window_frame_exclusion opt_window_clause opt_offset
+%type <pParseNode> opt_fetch_first_row_count fetch_first_clause offset_row_count fetch_first_row_count first_or_next row_or_rows opt_result_offset_clause result_offset_clause
+/* LIMIT and OFFSET */
+%type <pParseNode> opt_limit_offset_clause limit_offset_clause opt_fetch_first_clause
+%%
+
+/* Return Parse Tree to OSQLParser
+ * (the access over yyval after calling the parser fails,
+ *
+ */
+sql_single_statement:
+ sql
+ { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); }
+ | sql ';'
+ { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); }
+ ;
+
+ /* schema definition language */
+ /* Note: other ``sql:sal_Unicode() rules appear later in the grammar */
+
+sql:
+ manipulative_statement
+ | schema_element
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+
+/***
+
+op_authorization:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AUTHORIZATION user
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+op_schema:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_NAME
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+
+schema:
+ SQL_TOKEN_CREATE SQL_TOKEN_SCHEMA op_schema op_authorization opt_schema_element_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+
+opt_schema_element_list:
+ {$$ = SQL_NEW_RULE;}
+ | schema_glement_list
+ ;
+
+schema_element_list:
+ schema_element
+ {$$ = SQL_NEW_LISTRULE;
+ $$->append($1);}
+ | schema_element_list schema_element
+ {$1->append($2);
+ $$ = $1;}
+ ;
+*/
+
+schema_element:
+ base_table_def
+ | view_def
+ | privilege_def
+ | trigger_definition
+ ;
+
+base_table_def:
+ SQL_TOKEN_CREATE SQL_TOKEN_TABLE table_node '(' base_table_element_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+base_table_element_commalist:
+ base_table_element
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | base_table_element_commalist ',' base_table_element
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+base_table_element:
+ column_def
+ | table_constraint_def
+ ;
+
+column_def:
+ column data_type column_def_opt_list
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+
+column_def_opt_list:
+ /* empty */ {$$ = SQL_NEW_LISTRULE;}
+ | column_def_opt_list column_def_opt
+ {$1->append($2);
+ $$ = $1;}
+ ;
+
+nil_fkt:
+ datetime_value_fct
+ ;
+unique_spec:
+ SQL_TOKEN_UNIQUE
+ | SQL_TOKEN_PRIMARY SQL_TOKEN_KEY
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+column_def_opt:
+ SQL_TOKEN_NOT SQL_TOKEN_NULL
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | unique_spec
+ | SQL_TOKEN_DEFAULT literal
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT SQL_TOKEN_NULL
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT SQL_TOKEN_USER
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DEFAULT nil_fkt
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHECK
+ | SQL_TOKEN_CHECK '(' search_condition ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_REFERENCES table_node
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_REFERENCES table_node '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+table_constraint_def:
+ unique_spec '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ $$->append($7);}
+ | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ $$->append($7);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($9);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ | SQL_TOKEN_CHECK '(' search_condition ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+op_column_commalist:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+column_commalist:
+ column_commalist ',' column
+ {$1->append($3);
+ $$ = $1;}
+ | column
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+
+view_def:
+ SQL_TOKEN_CREATE SQL_TOKEN_VIEW table_node opt_column_commalist SQL_TOKEN_AS select_statement opt_with_check_option
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+
+opt_with_check_option:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_CHECK SQL_TOKEN_OPTION
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+opt_column_commalist:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | '(' column_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+privilege_def:
+ SQL_TOKEN_GRANT privileges SQL_TOKEN_ON table_node SQL_TOKEN_TO grantee_commalist
+ opt_with_grant_option
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+
+opt_with_grant_option:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_GRANT SQL_TOKEN_OPTION
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+privileges:
+ SQL_TOKEN_ALL SQL_TOKEN_PRIVILEGES
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | operation_commalist
+ ;
+
+operation_commalist:
+ operation
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | operation_commalist ',' operation
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+operation:
+ SQL_TOKEN_SELECT
+ | SQL_TOKEN_INSERT opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_DELETE
+ | SQL_TOKEN_UPDATE opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_REFERENCES opt_column_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | SQL_TOKEN_USAGE
+ ;
+
+
+grantee_commalist:
+ grantee
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | grantee_commalist ',' grantee
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+grantee:
+ SQL_TOKEN_PUBLIC
+ | user
+ ;
+
+ /* module language */
+
+opt_order_by_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ORDER SQL_TOKEN_BY ordering_spec_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+ordering_spec_commalist:
+ ordering_spec
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | ordering_spec_commalist ',' ordering_spec
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+ordering_spec:
+/* SQL_TOKEN_INTNUM opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+*/
+ predicate opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+
+ | row_value_constructor_elem opt_asc_desc
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+opt_asc_desc:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ASC
+ | SQL_TOKEN_DESC
+ ;
+
+
+/***
+manipulative_statement_list:
+ manipulative_statement
+ {$$ = SQL_NEW_LISTRULE;
+ $$->append($1);}
+ | manipulative_statement_list manipulative_statement
+ {$1->append($2);
+ $$ = $1;}
+ ;
+***/
+
+sql_not:
+/* vide */
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_NOT
+ ;
+
+/* manipulative statements */
+
+manipulative_statement:
+ commit_statement
+/* | delete_statement_positioned*/
+ | delete_statement_searched
+ | fetch_statement
+ | insert_statement
+ | rollback_statement
+ | select_statement_into
+/* | update_statement_positioned*/
+ | update_statement_searched
+ | union_statement
+ | '{' odbc_call_spec '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ ;
+
+union_statement:
+ select_statement
+ | union_statement SQL_TOKEN_UNION all select_statement
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+commit_statement:
+ SQL_TOKEN_COMMIT SQL_TOKEN_WORK
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+/*
+delete_statement_positioned:
+ SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);}
+ ;
+*/
+delete_statement_searched:
+ SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node opt_where_clause
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);}
+ ;
+
+fetch_statement:
+ SQL_TOKEN_FETCH cursor SQL_TOKEN_INTO target_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);}
+ ;
+
+insert_statement:
+ SQL_TOKEN_INSERT SQL_TOKEN_INTO table_node opt_column_commalist query_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);}
+ ;
+values_or_query_spec:
+ SQL_TOKEN_VALUES '(' table_value_const_list ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+table_value_const_list:
+ row_value_constructor
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | table_value_const_list ',' row_value_constructor
+ {$1->append($3);
+ $$ = $1;}
+ ;
+/*
+row_value_const_list:
+ row_value_constructor_elem
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | row_value_const_list ',' row_value_constructor_elem
+ {$1->append($3);
+ $$ = $1;}
+ ;
+*/
+row_value_constructor:
+ row_value_constructor_elem
+/* | '(' row_value_const_list ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ */
+ ;
+row_value_constructor_elem:
+ value_exp /*[^')']*/
+ | SQL_TOKEN_DEFAULT
+ ;
+
+
+rollback_statement:
+ SQL_TOKEN_ROLLBACK SQL_TOKEN_WORK
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+
+ /* INTO target_commalist herausgenommen */
+select_statement_into:
+ SQL_TOKEN_SELECT opt_all_distinct selection SQL_TOKEN_INTO target_commalist table_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6); }
+ ;
+
+opt_all_distinct:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ALL
+ | SQL_TOKEN_DISTINCT
+
+ ;
+/*
+update_statement_positioned:
+ SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist
+ SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);}
+ ;
+*/
+assignment_commalist:
+ assignment
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | assignment_commalist ',' assignment
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+assignment:
+ column SQL_EQUAL update_source
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+update_source:
+ value_exp
+ | SQL_TOKEN_DEFAULT
+ ;
+update_statement_searched:
+ SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist opt_where_clause
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);}
+ ;
+
+target_commalist:
+ target
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | target_commalist ',' target
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+target:
+ parameter_ref
+ ;
+
+opt_where_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | where_clause
+ ;
+
+ /* query expressions */
+
+query_term:
+ non_join_query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/* SELECT STATEMENT */
+select_statement:
+ SQL_TOKEN_SELECT opt_all_distinct selection table_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+selection:
+ '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+ | scalar_exp_commalist
+ ;
+opt_result_offset_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | result_offset_clause
+ ;
+result_offset_clause:
+ SQL_TOKEN_OFFSET offset_row_count row_or_rows
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_fetch_first_row_count:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | fetch_first_row_count
+ ;
+first_or_next:
+ SQL_TOKEN_FIRST
+ | SQL_TOKEN_NEXT
+ ;
+row_or_rows:
+ SQL_TOKEN_ROW
+ | SQL_TOKEN_ROWS
+ ;
+opt_fetch_first_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | fetch_first_clause
+ ;
+fetch_first_clause:
+ SQL_TOKEN_FETCH first_or_next opt_fetch_first_row_count row_or_rows SQL_TOKEN_ONLY
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+offset_row_count:
+ literal
+ ;
+fetch_first_row_count:
+ literal
+ ;
+
+opt_limit_offset_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | limit_offset_clause
+ ;
+opt_offset:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_OFFSET SQL_TOKEN_INTNUM
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+limit_offset_clause:
+ SQL_TOKEN_LIMIT SQL_TOKEN_INTNUM opt_offset
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+table_exp:
+ from_clause opt_where_clause opt_group_by_clause opt_having_clause opt_window_clause opt_order_by_clause opt_limit_offset_clause opt_result_offset_clause opt_fetch_first_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);
+ $$->append($9);
+ }
+ ;
+
+from_clause:
+ SQL_TOKEN_FROM table_ref_commalist
+ { $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2); }
+ ;
+
+table_ref_commalist:
+
+ table_ref
+ { $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1); }
+ | table_ref_commalist ',' table_ref
+ { $1->append($3);
+ $$ = $1; }
+ ;
+
+opt_as:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AS
+ ;
+opt_row:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ROW
+ ;
+table_primary_as_range_column:
+ {$$ = SQL_NEW_RULE;}
+ | opt_as SQL_TOKEN_NAME op_column_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+table_ref:
+ table_node table_primary_as_range_column
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | subquery range_variable op_column_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | joined_table
+ | '{' SQL_TOKEN_OJ joined_table '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ | '(' joined_table ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+where_clause:
+ SQL_TOKEN_WHERE search_condition
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+opt_group_by_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_GROUP SQL_TOKEN_BY column_ref_commalist
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);}
+ ;
+
+column_ref_commalist:
+ column_ref
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | set_fct_spec
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | column_ref_commalist ',' column_ref
+ {$1->append($3);
+ $$ = $1;}
+ | column_ref_commalist ',' set_fct_spec
+ {$1->append($3);
+ $$ = $1;}
+ ;
+
+opt_having_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_HAVING search_condition
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+
+ /* search conditions */
+boolean_primary:
+ predicate
+ | '(' search_condition ')'
+ { // boolean_primary: rule 2
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | row_value_constructor_elem /*[^')' ',']*/
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// boolean_primary: rule 3
+ {
+ $$ = SQL_NEW_RULE;
+ sal_Int16 nErg = 0;
+ if ( SQL_ISTOKEN( $1, NULL))
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+ OSQLParseNode* pTFN = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::test_for_null));
+ pTFN->append(pColumnRef);
+
+ OSQLParseNode* pNPP2 = new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::null_predicate_part_2));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_IS));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::sql_not)));
+ pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_NULL));
+ pTFN->append(pNPP2);
+
+ $$->append(pTFN);
+
+ nErg = 1;
+ }
+ else
+ {
+ nErg = xxx_pGLOBAL_SQLPARSER->buildComparisonRule($$,$1);
+ }
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ delete pTemp;
+ }
+ else
+ {
+ delete $$;
+ if(nErg)
+ YYERROR;
+ else
+ YYABORT;
+ }
+ }
+ else
+ YYERROR;
+ }
+ ;
+parenthesized_boolean_value_expression:
+ '(' search_condition ')'
+ { // boolean_primary: rule 2
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+boolean_factor:
+ boolean_primary %dprec 2
+ | SQL_TOKEN_NOT boolean_primary %dprec 1
+ { // boolean_factor: rule 1
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+boolean_term:
+ boolean_factor
+ | boolean_term SQL_TOKEN_AND boolean_factor
+ {
+ $$ = SQL_NEW_RULE; // boolean_term: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+search_condition:
+ boolean_term
+ | search_condition SQL_TOKEN_OR boolean_term
+ {
+ $$ = SQL_NEW_RULE; // search_condition
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+predicate:
+ comparison_predicate %dprec 1
+ | between_predicate
+ | all_or_any_predicate
+ | existence_test
+ | unique_test
+ | test_for_null %dprec 2
+ | in_predicate
+ | like_predicate
+ ;
+comparison_predicate_part_2:
+ comparison row_value_constructor
+ {
+ $$ = SQL_NEW_RULE; // comparison_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+comparison_predicate:
+ row_value_constructor comparison row_value_constructor
+ {
+ $$ = SQL_NEW_RULE; // comparison_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | comparison row_value_constructor
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // comparison_predicate: rule 2
+ {
+ $$ = SQL_NEW_RULE;
+ sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$2,$1);
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ delete pTemp;
+ }
+ else
+ {
+ delete $$;
+ YYABORT;
+ }
+ }
+ else
+ {
+ YYERROR;
+ }
+ }
+ ;
+comparison:
+ SQL_LESS
+ | SQL_NOTEQUAL
+ | SQL_EQUAL
+ | SQL_GREAT
+ | SQL_LESSEQ
+ | SQL_GREATEQ
+ | SQL_TOKEN_IS sql_not SQL_TOKEN_DISTINCT SQL_TOKEN_FROM
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_IS sql_not
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+between_predicate_part_2:
+ sql_not SQL_TOKEN_BETWEEN row_value_constructor SQL_TOKEN_AND row_value_constructor
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // between_predicate: rule 2
+ {
+ $$ = SQL_NEW_RULE;
+
+ sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$3,$2,$5);
+ if(nErg == 1)
+ {
+ OSQLParseNode* pTemp = $$;
+ $$ = pTemp->removeAt((sal_uInt32)0);
+ OSQLParseNode* pColumnRef = $$->removeAt((sal_uInt32)0);
+ $$->insert(0,$1);
+ OSQLParseNode* pBetween_predicate = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate));
+ pBetween_predicate->append(pColumnRef);
+ pBetween_predicate->append($$);
+ $$ = pBetween_predicate;
+
+ delete pTemp;
+ delete $4;
+ }
+ else
+ {
+ delete $$;
+ YYABORT;
+ }
+ }
+ else
+ {
+ $$ = SQL_NEW_RULE; // between_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ }
+between_predicate:
+ row_value_constructor between_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // between_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | between_predicate_part_2
+ ;
+character_like_predicate_part_2:
+ sql_not SQL_TOKEN_LIKE string_value_exp opt_escape
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+other_like_predicate_part_2:
+ sql_not SQL_TOKEN_LIKE value_exp_primary opt_escape
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+like_predicate:
+ row_value_constructor character_like_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | row_value_constructor other_like_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // like_predicate: rule 3
+ $$->append($1);
+ $$->append($2);
+ }
+ | character_like_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 5
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ OSQLParseNode* p2nd = $1->removeAt(2);
+ OSQLParseNode* p3rd = $1->removeAt(2);
+ if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) )
+ {
+ delete $$;
+ YYABORT;
+ }
+ $1->append(p3rd);
+ }
+ else
+ YYERROR;
+ }
+ | other_like_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 6
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ OSQLParseNode* p2nd = $1->removeAt(2);
+ OSQLParseNode* p3rd = $1->removeAt(2);
+ if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) )
+ {
+ delete $$;
+ YYABORT;
+ }
+ $1->append(p3rd);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+opt_escape:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ESCAPE string_value_exp
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ | '{' SQL_TOKEN_ESCAPE SQL_TOKEN_STRING '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ ;
+
+null_predicate_part_2:
+ SQL_TOKEN_IS sql_not SQL_TOKEN_NULL
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_IS sql_not SQL_TOKEN_UNKNOWN
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+test_for_null:
+ row_value_constructor null_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE; // test_for_null: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | null_predicate_part_2
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// test_for_null: rule 2
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+in_predicate_value:
+ subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | '(' value_exp_commalist ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+in_predicate_part_2:
+ sql_not SQL_TOKEN_IN in_predicate_value
+ {
+ $$ = SQL_NEW_RULE;// in_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+in_predicate:
+ row_value_constructor in_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE;// in_predicate: rule 1
+ $$->append($1);
+ $$->append($2);
+ }
+ | in_predicate_part_2
+ {
+ if ( xxx_pGLOBAL_SQLPARSER->inPredicateCheck() )// in_predicate: rule 2
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+quantified_comparison_predicate_part_2:
+ comparison any_all_some subquery
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+all_or_any_predicate:
+ row_value_constructor quantified_comparison_predicate_part_2
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | quantified_comparison_predicate_part_2
+ {
+ if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name));
+
+ $$ = SQL_NEW_RULE;
+ $$->append(pColumnRef);
+ $$->append($1);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+any_all_some:
+ SQL_TOKEN_ANY
+ | SQL_TOKEN_ALL
+ | SQL_TOKEN_SOME
+ ;
+
+existence_test:
+ SQL_TOKEN_EXISTS subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+unique_test:
+ SQL_TOKEN_UNIQUE subquery
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);}
+ ;
+subquery:
+ '(' query_exp ')'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));}
+ ;
+
+ /* scalar expressions */
+scalar_exp_commalist:
+ select_sublist
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ }
+ | scalar_exp_commalist ',' select_sublist
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+select_sublist:
+/* table_node '.' '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+*/
+ derived_column
+
+ ;
+
+parameter_ref:
+ parameter
+ ;
+
+/*
+op_like:
+ '*'
+ {
+ $$ = newNode("*", SQLNodeType::Punctuation);
+ }
+ | '?'
+ {
+ $$ = newNode("?", SQLNodeType::Punctuation);
+ }
+ | op_like '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False);
+ }
+ | op_like '?'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("?", SQLNodeType::Punctuation));
+ xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False);
+ }
+ ;
+*/
+
+literal:
+/* SQL_TOKEN_STRING
+ | */SQL_TOKEN_INT
+ | SQL_TOKEN_REAL_NUM
+ | SQL_TOKEN_INTNUM
+ | SQL_TOKEN_APPROXNUM
+ | SQL_TOKEN_ACCESS_DATE
+/* rules for predicate check */
+ | literal SQL_TOKEN_STRING
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_INT
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_REAL_NUM
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ | literal SQL_TOKEN_APPROXNUM
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ OSQLParser::reduceLiteral($$, true);
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+ /* miscellaneous */
+as_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_AS column
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | column
+ ;
+position_exp:
+ SQL_TOKEN_POSITION '(' value_exp SQL_TOKEN_IN value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_POSITION '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+num_value_fct:
+ position_exp
+ | extract_exp
+ | length_exp
+ ;
+char_length_exp:
+ SQL_TOKEN_CHAR_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_SQL_TOKEN_INTNUM '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+
+ ;
+octet_length_exp:
+ SQL_TOKEN_OCTET_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+bit_length_exp:
+ SQL_TOKEN_BIT_LENGTH '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+length_exp:
+ char_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | octet_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | bit_length_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+datetime_field:
+ non_second_datetime_field
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_SECOND
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+extract_field:
+ time_zone_field
+ | datetime_field
+ | value_exp
+ ;
+time_zone_field:
+ SQL_TOKEN_TIMEZONE_HOUR
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_TIMEZONE_MINUTE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+extract_exp:
+ SQL_TOKEN_EXTRACT '(' extract_field SQL_TOKEN_FROM value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+unsigned_value_spec:
+ general_value_spec
+ | literal
+ ;
+general_value_spec:
+ parameter
+ | SQL_TOKEN_USER
+ | SQL_TOKEN_NULL
+ | SQL_TOKEN_FALSE
+ | SQL_TOKEN_TRUE
+ | SQL_TOKEN_VALUE
+ | SQL_TOKEN_CURRENT_CATALOG
+ | SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP
+ | SQL_TOKEN_CURRENT_PATH
+ | SQL_TOKEN_CURRENT_ROLE
+ | SQL_TOKEN_CURRENT_SCHEMA
+ | SQL_TOKEN_CURRENT_USER
+ | SQL_TOKEN_SESSION_USER
+ | SQL_TOKEN_SYSTEM_USER
+ ;
+set_fct_spec:
+ general_set_fct
+ | '{' odbc_fct_spec '}'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("{", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("}", SQLNodeType::Punctuation));
+ }
+ | function_name '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name0 '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name1 '(' function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name2 '(' function_arg_commalist2 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name3 '(' function_arg_commalist3 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | string_function_4Argument '(' function_arg_commalist4 ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name '(' function_args_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | function_name12 '(' function_args_commalist ')'
+ {
+ if ( $3->count() == 1 || $3->count() == 2 )
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ else
+ YYERROR;
+ }
+ | function_name23 '(' function_args_commalist ')'
+ {
+ if ( $3->count() == 2 || $3->count() == 3)
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ else
+ YYERROR;
+ }
+ ;
+function_name0:
+ date_function_0Argument
+ | numeric_function_0Argument
+ ;
+function_name1:
+ string_function_1Argument
+ | date_function_1Argument
+ | numeric_function_1Argument
+ ;
+function_name2:
+ string_function_2Argument
+ | numeric_function_2Argument
+ ;
+function_name12:
+ SQL_TOKEN_ROUND
+ | SQL_TOKEN_WEEK
+ | SQL_TOKEN_LOGF
+ | SQL_TOKEN_LOG
+ ;
+function_name23:
+ SQL_TOKEN_LOCATE
+ | SQL_TOKEN_DATEDIFF
+ ;
+function_name3:
+ string_function_3Argument
+ ;
+function_name:
+ string_function
+ | date_function
+ | numeric_function
+ | SQL_TOKEN_NAME
+ ;
+string_function_1Argument:
+ SQL_TOKEN_LENGTH
+ | SQL_TOKEN_ASCII
+ | SQL_TOKEN_LCASE
+ | SQL_TOKEN_LTRIM
+ | SQL_TOKEN_RTRIM
+ | SQL_TOKEN_SPACE
+ | SQL_TOKEN_UCASE
+ ;
+
+string_function_2Argument:
+ SQL_TOKEN_REPEAT
+ | SQL_TOKEN_LEFT
+ | SQL_TOKEN_RIGHT
+ ;
+string_function_3Argument:
+ SQL_TOKEN_REPLACE
+ ;
+string_function_4Argument:
+ SQL_TOKEN_INSERT
+ ;
+
+string_function:
+ SQL_TOKEN_CHAR
+ | SQL_TOKEN_CONCAT
+ | SQL_TOKEN_DIFFERENCE
+ | SQL_TOKEN_LOCATE_2
+ | SQL_TOKEN_SOUNDEX
+ ;
+date_function_0Argument:
+ SQL_TOKEN_CURDATE
+ | SQL_TOKEN_CURTIME
+ | SQL_TOKEN_NOW
+ ;
+date_function_1Argument:
+ SQL_TOKEN_DAYOFWEEK
+ | SQL_TOKEN_DAYOFMONTH
+ | SQL_TOKEN_DAYOFYEAR
+ | SQL_TOKEN_MONTH
+ | SQL_TOKEN_DAYNAME
+ | SQL_TOKEN_MONTHNAME
+ | SQL_TOKEN_QUARTER
+ | SQL_TOKEN_HOUR
+ | SQL_TOKEN_MINUTE
+ | SQL_TOKEN_SECOND
+ | SQL_TOKEN_YEAR
+ | SQL_TOKEN_DAY
+ | SQL_TOKEN_TIMEVALUE
+ | SQL_TOKEN_DATEVALUE
+ ;
+
+date_function:
+ SQL_TOKEN_TIMESTAMPADD
+ | SQL_TOKEN_TIMESTAMPDIFF
+ ;
+numeric_function_0Argument:
+ SQL_TOKEN_PI
+ ;
+numeric_function_1Argument:
+ SQL_TOKEN_ABS
+ | SQL_TOKEN_ACOS
+ | SQL_TOKEN_ASIN
+ | SQL_TOKEN_ATAN
+ | SQL_TOKEN_CEILING
+ | SQL_TOKEN_COS
+ | SQL_TOKEN_COT
+ | SQL_TOKEN_DEGREES
+ | SQL_TOKEN_FLOOR
+ | SQL_TOKEN_SIGN
+ | SQL_TOKEN_SIN
+ | SQL_TOKEN_SQRT
+ | SQL_TOKEN_TAN
+ | SQL_TOKEN_EXP
+ | SQL_TOKEN_LOG10
+ | SQL_TOKEN_LN
+ | SQL_TOKEN_RADIANS
+ | SQL_TOKEN_ROUNDMAGIC
+ ;
+numeric_function_2Argument:
+ SQL_TOKEN_ATAN2
+ | SQL_TOKEN_MOD
+ | SQL_TOKEN_POWER
+ ;
+numeric_function:
+ SQL_TOKEN_RAND
+ | SQL_TOKEN_TRUNCATE
+ ;
+
+window_function:
+ window_function_type SQL_TOKEN_OVER window_name_or_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_function_type :
+ rank_function_type '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_ROW_NUMBER '(' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | general_set_fct
+ | ntile_function
+ | lead_or_lag_function
+ | first_or_last_value_function
+ | nth_value_function
+;
+ntile_function :
+ SQL_TOKEN_NTILE '(' number_of_tiles ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+dynamic_parameter_specification:
+ parameter
+ ;
+simple_value_specification:
+ literal
+ ;
+number_of_tiles :
+ simple_value_specification
+ | dynamic_parameter_specification
+ ;
+opt_lead_or_lag_function:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | ',' offset
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ | ',' offset ',' default_expression
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($4);
+ }
+ ;
+opt_null_treatment:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | null_treatment
+ ;
+
+lead_or_lag_function:
+ lead_or_lag '(' lead_or_lag_extent opt_lead_or_lag_function ')' opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ }
+ ;
+lead_or_lag:
+ SQL_TOKEN_LEAD
+ | SQL_TOKEN_LAG
+ ;
+lead_or_lag_extent:
+ value_exp
+ ;
+offset:
+ SQL_TOKEN_INTNUM
+ ;
+default_expression:
+ value_exp
+ ;
+null_treatment:
+ SQL_TOKEN_RESPECT SQL_TOKEN_NULLS
+ | SQL_TOKEN_IGNORE SQL_TOKEN_NULLS
+ ;
+first_or_last_value_function:
+ first_or_last_value '(' value_exp ')' opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ ;
+first_or_last_value :
+ SQL_TOKEN_FIRST_VALUE
+ | SQL_TOKEN_LAST_VALUE
+ ;
+opt_from_first_or_last:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | from_first_or_last
+ ;
+nth_value_function:
+ SQL_TOKEN_NTH_VALUE '(' value_exp ',' nth_row ')' opt_from_first_or_last opt_null_treatment
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($7);
+ $$->append($8);
+ }
+ ;
+nth_row:
+ simple_value_specification
+ | dynamic_parameter_specification
+ ;
+from_first_or_last:
+ SQL_TOKEN_FROM SQL_TOKEN_FIRST
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_FROM SQL_TOKEN_LAST
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_name:
+ SQL_TOKEN_NAME
+ ;
+window_name_or_specification:
+ window_name
+ | in_line_window_specification
+ ;
+in_line_window_specification:
+ window_specification
+ ;
+opt_window_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_clause
+ ;
+window_clause:
+ SQL_TOKEN_WINDOW window_definition_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_definition_list:
+ window_definition_list ',' window_definition
+ {$1->append($3);
+ $$ = $1;}
+ | window_definition
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+window_definition:
+ new_window_name SQL_TOKEN_AS window_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+new_window_name:
+ window_name
+ ;
+window_specification:
+ '('
+ opt_existing_window_name
+ opt_window_partition_clause
+ opt_order_by_clause
+ opt_window_frame_clause
+ ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+opt_existing_window_name:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | existing_window_name
+ ;
+opt_window_partition_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_partition_clause
+ ;
+opt_window_frame_clause:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_frame_clause
+ ;
+existing_window_name:
+ window_name
+ ;
+window_partition_clause:
+ SQL_TOKEN_PARTITION SQL_TOKEN_BY window_partition_column_reference_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_partition_column_reference_list:
+ window_partition_column_reference_list ',' window_partition_column_reference
+ {$1->append($3);
+ $$ = $1;}
+ | window_partition_column_reference
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ ;
+window_partition_column_reference:
+ column_ref opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+opt_window_frame_exclusion:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | window_frame_exclusion
+ ;
+window_frame_clause:
+ window_frame_units window_frame_extent opt_window_frame_exclusion
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+window_frame_units:
+ SQL_TOKEN_ROWS
+ | SQL_TOKEN_RANGE
+ ;
+window_frame_extent:
+ window_frame_start
+ | window_frame_between
+ ;
+window_frame_start:
+ SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | window_frame_preceding
+ | SQL_TOKEN_CURRENT SQL_TOKEN_ROW
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_preceding:
+ unsigned_value_spec SQL_TOKEN_PRECEDING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_between:
+ SQL_TOKEN_BETWEEN window_frame_bound_1 SQL_TOKEN_AND window_frame_bound_2
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+window_frame_bound_1:
+ window_frame_bound
+ ;
+window_frame_bound_2:
+ window_frame_bound
+ ;
+window_frame_bound:
+ window_frame_start
+ | SQL_TOKEN_UNBOUNDED SQL_TOKEN_FOLLOWING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | window_frame_following
+ ;
+window_frame_following:
+ unsigned_value_spec SQL_TOKEN_FOLLOWING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+window_frame_exclusion:
+ SQL_TOKEN_EXCLUDE SQL_TOKEN_CURRENT SQL_TOKEN_ROW
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_GROUP
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_TIES
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_EXCLUDE SQL_TOKEN_NO SQL_TOKEN_OTHERS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+op_parameter:
+ {$$ = SQL_NEW_RULE;}
+ | '?' SQL_EQUAL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("?", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ ;
+odbc_call_spec:
+ op_parameter SQL_TOKEN_CALL table_node op_odbc_call_parameter
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+op_odbc_call_parameter:
+ {$$ = SQL_NEW_RULE;}
+ | '(' odbc_parameter_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+odbc_parameter_commalist:
+ odbc_parameter
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | odbc_parameter_commalist ',' odbc_parameter
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+odbc_parameter:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | literal
+ | parameter
+ ;
+
+odbc_fct_spec:
+ odbc_fct_type SQL_TOKEN_STRING
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_FN set_fct_spec
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+odbc_fct_type:
+ SQL_TOKEN_D
+ | SQL_TOKEN_T
+ | SQL_TOKEN_TS
+ ;
+
+general_set_fct:
+ set_fct_type '(' opt_all_distinct function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COUNT '(' '*' ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COUNT '(' opt_all_distinct function_arg ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | ordered_set_function
+ | array_aggregate_function
+ ;
+set_fct_type:
+ SQL_TOKEN_AVG
+ | SQL_TOKEN_MAX
+ | SQL_TOKEN_MIN
+ | SQL_TOKEN_SUM
+ | SQL_TOKEN_EVERY
+ | SQL_TOKEN_ANY
+ | SQL_TOKEN_SOME
+ | SQL_TOKEN_STDDEV_POP
+ | SQL_TOKEN_STDDEV_SAMP
+ | SQL_TOKEN_VAR_SAMP
+ | SQL_TOKEN_VAR_POP
+ | SQL_TOKEN_COLLECT
+ | SQL_TOKEN_FUSION
+ | SQL_TOKEN_INTERSECTION
+ ;
+
+ordered_set_function:
+ hypothetical_set_function
+ | inverse_distribution_function
+ ;
+hypothetical_set_function:
+ rank_function_type '(' hypothetical_set_function_value_expression_list ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ | rank_function_type '(' hypothetical_set_function_value_expression_list SQL_TOKEN_BY value_exp_commalist ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+ ;
+
+within_group_specification:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_WITHIN SQL_TOKEN_GROUP '(' opt_order_by_clause ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+hypothetical_set_function_value_expression_list:
+ value_exp_commalist
+ ;
+
+inverse_distribution_function:
+ inverse_distribution_function_type '('inverse_distribution_function_argument ')' within_group_specification
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+inverse_distribution_function_argument:
+ num_value_exp
+ ;
+inverse_distribution_function_type:
+ SQL_TOKEN_PERCENTILE_CONT
+ | SQL_TOKEN_PERCENTILE_DISC
+ ;
+
+array_aggregate_function:
+ SQL_TOKEN_ARRAY_AGG '(' value_exp opt_order_by_clause ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+rank_function_type:
+ SQL_TOKEN_RANK
+ | SQL_TOKEN_DENSE_RANK
+ | SQL_TOKEN_PERCENT_RANK
+ | SQL_TOKEN_CUME_DIST
+ ;
+outer_join_type:
+ SQL_TOKEN_LEFT %prec SQL_TOKEN_LEFT
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_RIGHT %prec SQL_TOKEN_RIGHT
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_FULL %prec SQL_TOKEN_FULL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+join_condition:
+ SQL_TOKEN_ON search_condition
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+join_spec:
+ join_condition
+ | named_columns_join
+ ;
+join_type:
+ /* empty */ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_INNER
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | outer_join_type
+ | outer_join_type SQL_TOKEN_OUTER
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+cross_union:
+ table_ref SQL_TOKEN_CROSS SQL_TOKEN_JOIN table_ref
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+
+qualified_join:
+ /* when SQL_TOKEN_NATURAL, then no join_spec */
+ table_ref SQL_TOKEN_NATURAL join_type SQL_TOKEN_JOIN table_ref
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | table_ref join_type SQL_TOKEN_JOIN table_ref join_spec
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | cross_union
+ ;
+joined_table:
+ qualified_join
+ ;
+named_columns_join:
+ SQL_TOKEN_USING '(' column_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+simple_table:
+ select_statement
+ | values_or_query_spec
+ ;
+
+non_join_query_primary:
+ simple_table
+ | '(' non_join_query_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+non_join_query_term:
+ non_join_query_primary
+ | query_term SQL_TOKEN_INTERSECT all query_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+query_primary:
+ non_join_query_primary
+ ;
+non_join_query_exp:
+ non_join_query_term
+ | query_exp SQL_TOKEN_UNION all query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | query_exp SQL_TOKEN_EXCEPT all query_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+all:
+ /* empty*/ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ALL
+ ;
+query_exp:
+ non_join_query_exp /*[^')']*/
+ ;
+scalar_subquery:
+ subquery
+ ;
+cast_operand:
+ value_exp
+ ;
+cast_target:
+ table_node
+ | data_type
+ ;
+cast_spec:
+ SQL_TOKEN_CAST '(' cast_operand SQL_TOKEN_AS cast_target ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+value_exp_primary:
+ unsigned_value_spec
+ | column_ref
+ | set_fct_spec
+ | scalar_subquery
+ | case_expression
+ | window_function
+ | '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | cast_spec
+ ;
+
+num_primary:
+ value_exp_primary
+ | num_value_fct
+ ;
+factor:
+ num_primary
+ | '-' num_primary %prec SQL_TOKEN_UMINUS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ | '+' num_primary %prec SQL_TOKEN_UMINUS
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($2);
+ }
+ ;
+
+term:
+ factor
+ | term '*' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | term '/' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("/", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+
+num_value_exp:
+ term
+ | num_value_exp '+' term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | num_value_exp '-' term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+datetime_primary:
+/* value_exp_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ |*/ datetime_value_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+datetime_value_fct:
+ SQL_TOKEN_CURRENT_DATE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_CURRENT_TIME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | SQL_TOKEN_CURRENT_TIMESTAMP
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+time_zone:
+ SQL_TOKEN_AT time_zone_specifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+time_zone_specifier:
+ SQL_TOKEN_LOCAL
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+/* | SQL_TOKEN_TIME SQL_TOKEN_ZONE interval_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }*/
+ ;
+datetime_factor:
+ datetime_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | datetime_primary time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+datetime_term:
+ datetime_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/*
+interval_term:
+ literal
+ | interval_term '*' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | interval_term '/' factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("/", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+*/
+datetime_value_exp:
+ datetime_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+/* | interval_value_exp '+' datetime_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | datetime_value_exp '+' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | datetime_value_exp '-' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+*/ ;
+/*
+interval_value_exp:
+ interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | interval_value_exp '+' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | interval_value_exp '-' interval_term
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | '(' datetime_value_exp '-' datetime_term ')' interval_qualifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("-", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ $$->append($6);
+ }
+ ;
+*/
+non_second_datetime_field:
+ SQL_TOKEN_YEAR
+ | SQL_TOKEN_MONTH
+ | SQL_TOKEN_DAY
+ | SQL_TOKEN_HOUR
+ | SQL_TOKEN_MINUTE
+ ;
+start_field:
+ non_second_datetime_field opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+end_field:
+ non_second_datetime_field
+ | SQL_TOKEN_SECOND opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+single_datetime_field:
+ non_second_datetime_field opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_SECOND opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+interval_qualifier:
+ start_field SQL_TOKEN_TO end_field
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | single_datetime_field
+ ;
+
+function_arg_commalist2:
+ function_arg ',' function_arg
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);}
+ ;
+function_arg_commalist3:
+ function_arg ',' function_arg ',' function_arg
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);
+ $$->append($5);
+ }
+ ;
+function_arg_commalist4:
+ function_arg ',' function_arg ',' function_arg ',' function_arg
+ {
+ $$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);
+ $$->append($3);
+ $$->append($5);
+ $$->append($7);
+ }
+ ;
+value_exp_commalist:
+ value_exp
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | value_exp_commalist ',' value_exp
+ {$1->append($3);
+ $$ = $1;}
+ /* this rule is only valid if we check predicates */
+ | value_exp_commalist ';' value_exp
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ else
+ YYERROR;
+ }
+ ;
+function_arg:
+ result
+ | value_exp comparison value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | value_exp SQL_TOKEN_USING value_exp comparison value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | value_exp SQL_TOKEN_BY value_exp_commalist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+function_args_commalist:
+ function_arg
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | function_args_commalist ',' function_arg
+ {$1->append($3);
+ $$ = $1;}
+ /* this rule is only valid if we check predicates */
+ | function_args_commalist ';' function_arg
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ else
+ YYERROR;
+ }
+ ;
+
+value_exp:
+ num_value_exp /*[^')']*/
+ | string_value_exp
+ | datetime_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+string_value_exp:
+ char_value_exp
+/* | bit_value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+*/ ;
+char_value_exp:
+ char_factor
+ | concatenation
+ ;
+concatenation:
+ char_value_exp '+' char_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | value_exp SQL_CONCAT value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+
+char_primary:
+ SQL_TOKEN_STRING
+ | string_value_fct
+ ;
+collate_clause:
+ SQL_TOKEN_COLLATE table_node
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+char_factor:
+ char_primary
+ | char_primary collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+string_value_fct:
+ char_value_fct
+ | bit_value_fct
+ ;
+bit_value_fct:
+ bit_substring_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+bit_substring_fct:
+ SQL_TOKEN_SUBSTRING '(' bit_value_exp SQL_TOKEN_FROM string_value_exp for_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+bit_value_exp:
+ bit_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+/*
+ bit_concatenation
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ |
+bit_concatenation:
+ bit_value_exp '+' bit_factor
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("+", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ ;
+*/
+bit_factor:
+ bit_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+bit_primary:
+ {$$ = SQL_NEW_RULE;}
+/* value_exp_primary
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | string_value_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }*/
+ ;
+char_value_fct:
+ char_substring_fct
+ | fold
+ | form_conversion
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | char_translation
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ | trim_fct
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ }
+ ;
+for_length:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_FOR value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+char_substring_fct:
+ SQL_TOKEN_SUBSTRING '(' value_exp SQL_TOKEN_FROM value_exp for_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_SUBSTRING '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+upper_lower:
+ SQL_TOKEN_UPPER
+ | SQL_TOKEN_LOWER
+ ;
+fold:
+ upper_lower '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+form_conversion:
+ SQL_TOKEN_CONVERT '(' string_value_exp SQL_TOKEN_USING table_node ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_CONVERT '(' cast_operand ',' cast_target ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+char_translation:
+ SQL_TOKEN_TRANSLATE '(' string_value_exp SQL_TOKEN_USING table_node ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+trim_fct:
+ SQL_TOKEN_TRIM '(' trim_operands ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+trim_operands:
+ trim_spec value_exp SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | trim_spec SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | value_exp SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_FROM value_exp
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | value_exp
+ ;
+
+trim_spec:
+ SQL_TOKEN_BOTH
+ | SQL_TOKEN_LEADING
+ | SQL_TOKEN_TRAILING
+ ;
+
+derived_column:
+ value_exp as_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+/* Tabellenname */
+table_node:
+ table_name
+ | schema_name
+ | catalog_name
+;
+catalog_name:
+ SQL_TOKEN_NAME '.' schema_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | SQL_TOKEN_NAME ':' schema_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+;
+schema_name:
+ SQL_TOKEN_NAME '.' table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+;
+
+table_name:
+ SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+;
+/* Columns */
+column_ref:
+ column
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+/* | table_node '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);}
+*/
+ | SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ }
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);}
+ | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+ | SQL_TOKEN_NAME ':' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.'
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+/* | SQL_TOKEN_NAME ';' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode(";", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($5);
+ $$->append(newNode(".", SQLNodeType::Punctuation));
+ $$->append($7);
+ }
+*/ ;
+
+ /* data types */
+column_val:
+ column
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ | '*'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("*", SQLNodeType::Punctuation));
+ }
+ ;
+data_type:
+ predefined_type
+ ;
+opt_char_set_spec:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_CHARACTER SQL_TOKEN_SET SQL_TOKEN_NAME
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_collate_clause:
+ {$$ = SQL_NEW_RULE;}
+ | collate_clause
+ ;
+predefined_type:
+ character_string_type opt_char_set_spec opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | national_character_string_type opt_collate_clause
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | binary_string_type
+ | numeric_type
+ | boolean_type
+ | datetime_type
+ | interval_type
+ ;
+character_string_type:
+ SQL_TOKEN_CHARACTER opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_VARCHAR paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | character_large_object_type
+ ;
+opt_paren_precision:
+ {$$ = SQL_NEW_RULE;}
+ | paren_char_length
+ ;
+paren_char_length:
+ '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+opt_paren_char_large_length:
+ {$$ = SQL_NEW_RULE;}
+ | paren_character_large_object_length
+ ;
+paren_character_large_object_length:
+ '(' large_object_length ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+
+large_object_length:
+ SQL_TOKEN_INTNUM opt_multiplier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+opt_multiplier:
+ {$$ = SQL_NEW_RULE;}
+ | 'K'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("K", SQLNodeType::Punctuation));
+ }
+ | 'M'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("M", SQLNodeType::Punctuation));
+ }
+ | 'G'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("G", SQLNodeType::Punctuation));
+ }
+ | 'T'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("T", SQLNodeType::Punctuation));
+ }
+ | 'P'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("P", SQLNodeType::Punctuation));
+ }
+ ;
+character_large_object_type:
+ SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_CHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_CLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+national_character_string_type:
+ SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_NCHAR opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NCHAR SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | national_character_large_object_type
+ ;
+national_character_large_object_type:
+ SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ | SQL_TOKEN_NCHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NCLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+binary_string_type:
+ SQL_TOKEN_BINARY opt_paren_precision
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_BINARY SQL_TOKEN_VARYING paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_VARBINARY paren_char_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | binary_large_object_string_type
+ ;
+binary_large_object_string_type:
+ SQL_TOKEN_BINARY SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_BLOB opt_paren_char_large_length
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+numeric_type:
+ exact_numeric_type
+ | approximate_numeric_type
+ ;
+opt_paren_precision_scale:
+ {$$ = SQL_NEW_RULE;}
+ | '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | '(' SQL_TOKEN_INTNUM ',' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode(",", SQLNodeType::Punctuation));
+ $$->append($4);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+exact_numeric_type:
+ SQL_TOKEN_NUMERIC opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_DECIMAL opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_DEC opt_paren_precision_scale
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ | SQL_TOKEN_SMALLINT
+ | SQL_TOKEN_INTEGER
+ | SQL_TOKEN_INT
+ | SQL_TOKEN_BIGINT
+ ;
+approximate_numeric_type:
+ SQL_TOKEN_FLOAT '(' SQL_TOKEN_INTNUM ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_FLOAT
+ | SQL_TOKEN_REAL
+ | SQL_TOKEN_DOUBLE
+ | SQL_TOKEN_DOUBLE SQL_TOKEN_PRECISION
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+boolean_type:
+ SQL_TOKEN_BOOLEAN
+;
+datetime_type:
+ SQL_TOKEN_DATE
+ | SQL_TOKEN_TIME opt_paren_precision opt_with_or_without_time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_TIMESTAMP opt_paren_precision opt_with_or_without_time_zone
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+opt_with_or_without_time_zone:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_WITH SQL_TOKEN_TIME SQL_TOKEN_ZONE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ | SQL_TOKEN_WITHOUT SQL_TOKEN_TIME SQL_TOKEN_ZONE
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+interval_type:
+ SQL_TOKEN_INTERVAL interval_qualifier
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+ /* the various things you can name */
+
+column:
+ SQL_TOKEN_NAME
+ | SQL_TOKEN_POSITION
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ | SQL_TOKEN_CHAR_LENGTH
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ | SQL_TOKEN_EXTRACT
+ {
+ sal_uInt32 nNod = $$->getRuleID();
+ delete $$;
+ $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name);
+ }
+ ;
+case_expression:
+ case_abbreviation
+ | case_specification
+ ;
+case_abbreviation:
+ SQL_TOKEN_NULLIF '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COALESCE '(' value_exp ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ | SQL_TOKEN_COALESCE '(' value_exp_commalist ')'
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append(newNode("(", SQLNodeType::Punctuation));
+ $$->append($3);
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ ;
+case_specification:
+ simple_case
+ | searched_case
+ ;
+simple_case:
+ SQL_TOKEN_CASE case_operand simple_when_clause_list else_clause SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ }
+ ;
+searched_case:
+ SQL_TOKEN_CASE searched_when_clause_list else_clause SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+simple_when_clause_list:
+ simple_when_clause
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | searched_when_clause_list simple_when_clause
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+simple_when_clause:
+ SQL_TOKEN_WHEN when_operand_list SQL_TOKEN_THEN result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+when_operand_list:
+ when_operand
+ {$$ = SQL_NEW_COMMALISTRULE;
+ $$->append($1);}
+ | when_operand_list ',' when_operand
+ {$1->append($3);
+ $$ = $1;}
+ ;
+when_operand:
+ row_value_constructor_elem
+ | comparison_predicate_part_2 %dprec 1
+ | between_predicate_part_2
+ | in_predicate_part_2
+ | character_like_predicate_part_2
+ | null_predicate_part_2 %dprec 2
+;
+searched_when_clause_list:
+ searched_when_clause
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | searched_when_clause_list searched_when_clause
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+searched_when_clause:
+ SQL_TOKEN_WHEN search_condition SQL_TOKEN_THEN result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ ;
+else_clause:
+ {$$ = SQL_NEW_RULE;}
+ | SQL_TOKEN_ELSE result
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+result:
+ result_expression
+ ;
+result_expression:
+ value_exp
+ ;
+case_operand:
+ row_value_constructor_elem
+ ;
+
+cursor: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+
+/***
+module: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+***/
+
+parameter:
+ ':' SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode(":", SQLNodeType::Punctuation));
+ $$->append($2);}
+ | '?'
+ {$$ = SQL_NEW_RULE; // test
+ $$->append(newNode("?", SQLNodeType::Punctuation));}
+ | '[' SQL_TOKEN_NAME ']'
+ {$$ = SQL_NEW_RULE;
+ $$->append(newNode("[", SQLNodeType::Punctuation));
+ $$->append($2);
+ $$->append(newNode("]", SQLNodeType::Punctuation));}
+ ;
+
+/***
+procedure: SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);}
+ ;
+***/
+
+range_variable:
+ {$$ = SQL_NEW_RULE;}
+ | opt_as SQL_TOKEN_NAME
+ {$$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+
+user: SQL_TOKEN_NAME
+ ;
+
+/* PREDICATECHECK RULES */
+sql:
+ search_condition /* checking predicats */
+ {
+ if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // sql: rule 1
+ {
+ $$ = $1;
+ if ( SQL_ISRULE($$,search_condition) )
+ {
+ $$->insert(0,newNode("(", SQLNodeType::Punctuation));
+ $$->append(newNode(")", SQLNodeType::Punctuation));
+ }
+ }
+ else
+ YYERROR;
+ }
+ | '(' sql ')' /* checking predicats */
+ ;
+trigger_definition:
+ SQL_TOKEN_CREATE SQL_TOKEN_TRIGGER trigger_name trigger_action_time trigger_event SQL_TOKEN_ON table_name op_referencing triggered_action
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ $$->append($5);
+ $$->append($6);
+ $$->append($7);
+ $$->append($8);
+ $$->append($9);
+ }
+ ;
+op_referencing:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_REFERENCING transition_table_or_variable_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+trigger_action_time:
+ SQL_TOKEN_BEFORE
+ | SQL_TOKEN_AFTER
+ | SQL_TOKEN_INSTEAD SQL_TOKEN_OF
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+;
+trigger_event:
+ SQL_TOKEN_INSERT
+ | SQL_TOKEN_DELETE
+ | SQL_TOKEN_UPDATE op_trigger_columnlist
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+op_trigger_columnlist:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_OF trigger_column_list
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+trigger_column_list:
+ column_commalist
+ ;
+triggered_action:
+ op_triggered_action_for triggered_when_clause triggered_SQL_statement
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+op_triggered_action_for:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_FOR SQL_TOKEN_EACH trigger_for
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ }
+ ;
+trigger_for:
+ SQL_TOKEN_ROW
+ | SQL_TOKEN_STATEMENT
+ ;
+triggered_when_clause:
+ {
+ $$ = SQL_NEW_RULE;
+ }
+ | SQL_TOKEN_WHEN parenthesized_boolean_value_expression
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ }
+ ;
+triggered_SQL_statement:
+ SQL_procedure_statement
+ | SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_procedure_statement_list ';' SQL_TOKEN_END
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append(newNode(";", SQLNodeType::Punctuation));
+ $$->append($5);
+ }
+ ;
+SQL_procedure_statement_list:
+ SQL_procedure_statement
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | SQL_procedure_statement_list ';' SQL_procedure_statement
+ {
+ $1->append($3);
+ $$ = $1;
+ }
+ ;
+SQL_procedure_statement:
+ sql
+ ;
+
+transition_table_or_variable_list:
+ transition_table_or_variable
+ {
+ $$ = SQL_NEW_LISTRULE;
+ $$->append($1);
+ }
+ | transition_table_or_variable_list transition_table_or_variable
+ {
+ $1->append($2);
+ $$ = $1;
+ }
+ ;
+
+transition_table_or_variable:
+ SQL_TOKEN_OLD opt_row opt_as old_transition_variable_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NEW opt_row opt_as new_transition_variable_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_OLD SQL_TOKEN_TABLE opt_as old_transition_table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+ | SQL_TOKEN_NEW SQL_TOKEN_TABLE opt_as new_transition_table_name
+ {
+ $$ = SQL_NEW_RULE;
+ $$->append($1);
+ $$->append($2);
+ $$->append($3);
+ $$->append($4);
+ }
+;
+old_transition_table_name:
+ transition_table_name
+;
+new_transition_table_name:
+ transition_table_name
+;
+transition_table_name:
+ SQL_TOKEN_NAME
+;
+old_transition_variable_name:
+ SQL_TOKEN_NAME
+;
+new_transition_variable_name:
+ SQL_TOKEN_NAME
+;
+trigger_name:
+ SQL_TOKEN_NAME
+;
+%%
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::dbtools;
+
+connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER;
+
+connectivity::OSQLInternalNode* newNode(const char* pNewValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(pNewValue, eNodeType, nNodeID);
+}
+
+connectivity::OSQLInternalNode* newNode(const OString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID);
+}
+
+connectivity::OSQLInternalNode* newNode(const OUString& _newValue,
+ const connectivity::SQLNodeType eNodeType,
+ const sal_uInt32 nNodeID)
+{
+ return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID);
+}
+
+OParseContext::OParseContext()
+{
+}
+
+
+OParseContext::~OParseContext()
+{
+}
+
+
+OUString OParseContext::getErrorMessage(ErrorCode _eCode) const
+{
+ OUString aMsg;
+ switch (_eCode)
+ {
+ case ErrorCode::General: aMsg = "Syntax error in SQL expression"; break;
+ case ErrorCode::ValueNoLike: aMsg = "The value #1 can not be used with LIKE."; break;
+ case ErrorCode::FieldNoLike: aMsg = "LIKE can not be used with this field."; break;
+ case ErrorCode::InvalidCompare: aMsg = "The entered criterion can not be compared with this field."; break;
+ case ErrorCode::InvalidIntCompare: aMsg = "The field can not be compared with a number."; break;
+ case ErrorCode::InvalidDateCompare: aMsg = "The field can not be compared with a date."; break;
+ case ErrorCode::InvalidRealCompare: aMsg = "The field can not be compared with a floating point number."; break;
+ case ErrorCode::InvalidTableNosuch: aMsg = "The database does not contain a table named \"#\"."; break;
+ case ErrorCode::InvalidTableOrQuery: aMsg = "The database does contain neither a table nor a query named \"#\"."; break;
+ case ErrorCode::InvalidColumn: aMsg = "The column \"#1\" is unknown in the table \"#2\"."; break;
+ case ErrorCode::InvalidTableExist: aMsg = "The database already contains a table or view with name \"#\"."; break;
+ case ErrorCode::InvalidQueryExist: aMsg = "The database already contains a query with name \"#\"."; break;
+ default:
+ OSL_FAIL( "OParseContext::getErrorMessage: unknown error code!" );
+ break;
+ }
+ return aMsg;
+}
+
+
+OString OParseContext::getIntlKeywordAscii(InternationalKeyCode _eKey) const
+{
+ OString aKeyword;
+ switch (_eKey)
+ {
+ case InternationalKeyCode::Like: aKeyword = "LIKE"; break;
+ case InternationalKeyCode::Not: aKeyword = "NOT"; break;
+ case InternationalKeyCode::Null: aKeyword = "NULL"; break;
+ case InternationalKeyCode::True: aKeyword = "True"; break;
+ case InternationalKeyCode::False: aKeyword = "False"; break;
+ case InternationalKeyCode::Is: aKeyword = "IS"; break;
+ case InternationalKeyCode::Between: aKeyword = "BETWEEN"; break;
+ case InternationalKeyCode::Or: aKeyword = "OR"; break;
+ case InternationalKeyCode::And: aKeyword = "AND"; break;
+ case InternationalKeyCode::Avg: aKeyword = "AVG"; break;
+ case InternationalKeyCode::Count: aKeyword = "COUNT"; break;
+ case InternationalKeyCode::Max: aKeyword = "MAX"; break;
+ case InternationalKeyCode::Min: aKeyword = "MIN"; break;
+ case InternationalKeyCode::Sum: aKeyword = "SUM"; break;
+ case InternationalKeyCode::Every: aKeyword = "EVERY"; break;
+ case InternationalKeyCode::Any: aKeyword = "ANY"; break;
+ case InternationalKeyCode::Some: aKeyword = "SOME"; break;
+ case InternationalKeyCode::StdDevPop: aKeyword = "STDDEV_POP"; break;
+ case InternationalKeyCode::StdDevSamp: aKeyword = "STDDEV_SAMP"; break;
+ case InternationalKeyCode::VarSamp: aKeyword = "VAR_SAMP"; break;
+ case InternationalKeyCode::VarPop: aKeyword = "VAR_POP"; break;
+ case InternationalKeyCode::Collect: aKeyword = "COLLECT"; break;
+ case InternationalKeyCode::Fusion: aKeyword = "FUSION"; break;
+ case InternationalKeyCode::Intersection:aKeyword = "INTERSECTION"; break;
+ case InternationalKeyCode::None: break;
+ default:
+ OSL_FAIL( "OParseContext::getIntlKeywordAscii: unknown key!" );
+ break;
+ }
+ return aKeyword;
+}
+
+
+IParseContext::InternationalKeyCode OParseContext::getIntlKeyCode(const OString& rToken) const
+{
+ static IParseContext::InternationalKeyCode Intl_TokenID[] =
+ {
+ InternationalKeyCode::Like, InternationalKeyCode::Not, InternationalKeyCode::Null, InternationalKeyCode::True,
+ InternationalKeyCode::False, InternationalKeyCode::Is, InternationalKeyCode::Between, InternationalKeyCode::Or,
+ InternationalKeyCode::And, InternationalKeyCode::Avg, InternationalKeyCode::Count, InternationalKeyCode::Max,
+ InternationalKeyCode::Min, InternationalKeyCode::Sum, InternationalKeyCode::Every,InternationalKeyCode::Any,InternationalKeyCode::Some,
+ InternationalKeyCode::StdDevPop,InternationalKeyCode::StdDevSamp,InternationalKeyCode::VarSamp,
+ InternationalKeyCode::VarPop,InternationalKeyCode::Collect,InternationalKeyCode::Fusion,InternationalKeyCode::Intersection
+ };
+
+ sal_uInt32 nCount = SAL_N_ELEMENTS( Intl_TokenID );
+ for (sal_uInt32 i = 0; i < nCount; i++)
+ {
+ OString aKey = getIntlKeywordAscii(Intl_TokenID[i]);
+ if (rToken.equalsIgnoreAsciiCase(aKey))
+ return Intl_TokenID[i];
+ }
+
+ return InternationalKeyCode::None;
+}
+
+
+static Locale& impl_getLocaleInstance( )
+{
+ static Locale s_aLocale( "en", "US", "" );
+ return s_aLocale;
+}
+
+
+Locale OParseContext::getPreferredLocale( ) const
+{
+ return getDefaultLocale();
+}
+
+
+const Locale& OParseContext::getDefaultLocale()
+{
+ return impl_getLocaleInstance();
+}
+
+// The (unfortunately global) yylval for the handing over of
+// values from the Scanner to the Parser. The global variable
+// is only used for a short term, the Parser reads the variable
+// immediately after the call of the Scanner into a same named own
+// member variable.
+
+
+OUString ConvertLikeToken(const OSQLParseNode* pTokenNode, const OSQLParseNode* pEscapeNode, bool bInternational)
+{
+ OUStringBuffer aMatchStr(0);
+ if (pTokenNode->isToken())
+ {
+ sal_Unicode cEscape = 0;
+ if (pEscapeNode->count())
+ cEscape = pEscapeNode->getChild(1)->getTokenValue().toChar();
+
+ // Change place holder
+ aMatchStr = pTokenNode->getTokenValue();
+ const sal_Int32 nLen = aMatchStr.getLength();
+ OUStringBuffer sSearch,sReplace;
+ if ( bInternational )
+ {
+ sSearch.append("%_");
+ sReplace.append("*?");
+ }
+ else
+ {
+ sSearch.append("*?");
+ sReplace.append("%_");
+ }
+
+ bool wasEscape = false;
+ for (sal_Int32 i = 0; i < nLen; i++)
+ {
+ const sal_Unicode c = aMatchStr[i];
+ // SQL standard requires the escape to be followed
+ // by a meta-character ('%', '_' or itself), else error
+ // We are more lenient here and let it escape anything.
+ // Especially since some databases (e.g. Microsoft SQL Server)
+ // have more meta-characters than the standard, such as e.g. '[' and ']'
+ if (wasEscape)
+ {
+ wasEscape=false;
+ continue;
+ }
+ if (c == cEscape)
+ {
+ wasEscape=true;
+ continue;
+ }
+ int match = -1;
+ if (c == sSearch[0])
+ match=0;
+ else if (c == sSearch[1])
+ match=1;
+
+ if (match != -1)
+ {
+ aMatchStr[i] = sReplace[match];
+ }
+ }
+ }
+ return aMatchStr.makeStringAndClear();
+}
+
+sal_uInt32 OSQLParser::s_nRuleIDs[OSQLParseNode::rule_count + 1];
+OSQLParser::RuleIDMap OSQLParser::s_aReverseRuleIDLookup;
+OParseContext OSQLParser::s_aDefaultContext;
+
+sal_Int32 OSQLParser::s_nRefCount = 0;
+// ::osl::Mutex OSQLParser::s_aMutex;
+OSQLScanner* OSQLParser::s_pScanner = nullptr;
+OSQLParseNodesGarbageCollector* OSQLParser::s_pGarbageCollector = nullptr;
+css::uno::Reference< css::i18n::XLocaleData4> OSQLParser::s_xLocaleData = nullptr;
+
+void setParser(OSQLParser* _pParser)
+{
+ xxx_pGLOBAL_SQLPARSER = _pParser;
+}
+
+void OSQLParser::setParseTree(OSQLParseNode* pNewParseTree)
+{
+ ::osl::MutexGuard aGuard(getMutex());
+ m_pParseTree.reset(pNewParseTree);
+}
+
+
+/** Delete all comments in a query.
+
+ See also getComment()/concatComment() implementation for
+ OQueryController::translateStatement().
+ */
+static OUString delComment( const OUString& rQuery )
+{
+ // First a quick search if there is any "--" or "//" or "/*", if not then the whole
+ // copying loop is pointless.
+ if (rQuery.indexOf("--") < 0 && rQuery.indexOf("//") < 0 &&
+ rQuery.indexOf("/*") < 0)
+ return rQuery;
+
+ const sal_Unicode* pCopy = rQuery.getStr();
+ sal_Int32 nQueryLen = rQuery.getLength();
+ bool bIsText1 = false; // "text"
+ bool bIsText2 = false; // 'text'
+ bool bComment2 = false; // /* comment */
+ bool bComment = false; // -- or // comment
+ OUStringBuffer aBuf(nQueryLen);
+ for (sal_Int32 i=0; i < nQueryLen; ++i)
+ {
+ if (bComment2)
+ {
+ if ((i+1) < nQueryLen)
+ {
+ if (pCopy[i]=='*' && pCopy[i+1]=='/')
+ {
+ bComment2 = false;
+ ++i;
+ }
+ }
+ else
+ {
+ // comment can't close anymore, actually an error, but...
+ }
+ continue;
+ }
+ if (pCopy[i] == '\n')
+ bComment = false;
+ else if (!bComment)
+ {
+ if (pCopy[i] == '\"' && !bIsText2)
+ bIsText1 = !bIsText1;
+ else if (pCopy[i] == '\'' && !bIsText1)
+ bIsText2 = !bIsText2;
+ if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
+ {
+ if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
+ bComment = true;
+ else if ((pCopy[i]=='/' && pCopy[i+1]=='*'))
+ bComment2 = true;
+ }
+ }
+ if (!bComment && !bComment2)
+ aBuf.append( &pCopy[i], 1);
+ }
+ return aBuf.makeStringAndClear();
+}
+
+std::unique_ptr<OSQLParseNode> OSQLParser::parseTree(OUString& rErrorMessage,
+ const OUString& rStatement,
+ bool bInternational)
+{
+
+
+ // Guard the parsing
+ ::osl::MutexGuard aGuard(getMutex());
+ // must be reset
+ setParser(this);
+
+ // delete comments before parsing
+ OUString sTemp = delComment(rStatement);
+
+ // defines how to scan
+ s_pScanner->SetRule(OSQLScanner::GetSQLRule()); // initial
+ s_pScanner->prepareScan(sTemp, m_pContext, bInternational);
+
+ SQLyylval.pParseNode = nullptr;
+ // SQLyypvt = NULL;
+ m_pParseTree = nullptr;
+ m_sErrorMessage = "";
+
+ // start parsing
+ if (SQLyyparse() != 0)
+ {
+ // only set the error message, if it's not already set
+ 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();
+ m_pParseTree.release(); // because the garbage collector deleted it
+ return nullptr;
+ }
+ else
+ {
+ (*s_pGarbageCollector)->clear();
+
+ // return result:
+ // to work around a bug in MKS YACC return the member m_pParseTree
+ // instead of Sdbyyval.pParseNode
+
+ SAL_WARN_IF(!m_pParseTree, "connectivity.parse",
+ "OSQLParser: Parser did not create ParseTree");
+ return std::move(m_pParseTree);
+ }
+}
+
+OString OSQLParser::TokenIDToStr(sal_uInt32 nTokenID, const IParseContext* pContext)
+{
+ OString aStr;
+ if (pContext)
+ {
+ IParseContext::InternationalKeyCode eKeyCode = IParseContext::InternationalKeyCode::None;
+ switch( nTokenID )
+ {
+ case SQL_TOKEN_LIKE: eKeyCode = IParseContext::InternationalKeyCode::Like; break;
+ case SQL_TOKEN_NOT: eKeyCode = IParseContext::InternationalKeyCode::Not; break;
+ case SQL_TOKEN_NULL: eKeyCode = IParseContext::InternationalKeyCode::Null; break;
+ case SQL_TOKEN_TRUE: eKeyCode = IParseContext::InternationalKeyCode::True; break;
+ case SQL_TOKEN_FALSE: eKeyCode = IParseContext::InternationalKeyCode::False; break;
+ case SQL_TOKEN_IS: eKeyCode = IParseContext::InternationalKeyCode::Is; break;
+ case SQL_TOKEN_BETWEEN: eKeyCode = IParseContext::InternationalKeyCode::Between; break;
+ case SQL_TOKEN_OR: eKeyCode = IParseContext::InternationalKeyCode::Or; break;
+ case SQL_TOKEN_AND: eKeyCode = IParseContext::InternationalKeyCode::And; break;
+ case SQL_TOKEN_AVG: eKeyCode = IParseContext::InternationalKeyCode::Avg; break;
+ case SQL_TOKEN_COUNT: eKeyCode = IParseContext::InternationalKeyCode::Count; break;
+ case SQL_TOKEN_MAX: eKeyCode = IParseContext::InternationalKeyCode::Max; break;
+ case SQL_TOKEN_MIN: eKeyCode = IParseContext::InternationalKeyCode::Min; break;
+ case SQL_TOKEN_SUM: eKeyCode = IParseContext::InternationalKeyCode::Sum; break;
+ }
+ if ( eKeyCode != IParseContext::InternationalKeyCode::None )
+ aStr = pContext->getIntlKeywordAscii(eKeyCode);
+ }
+
+ if (aStr.isEmpty())
+ {
+ // coverity[unsigned_compare : SUPPRESS] - YYTRANSLATE is out of our control
+ aStr = yytname[YYTRANSLATE(nTokenID)];
+ if(aStr.startsWith("SQL_TOKEN_"))
+ aStr = aStr.copy(10);
+ switch( nTokenID )
+ {
+ case SQL_TOKEN_OJ:
+ case SQL_TOKEN_TS:
+ case SQL_TOKEN_T:
+ case SQL_TOKEN_D:
+ aStr = aStr.toAsciiLowerCase();
+ }
+ }
+ return aStr;
+}
+
+#if OSL_DEBUG_LEVEL > 0
+OUString OSQLParser::RuleIDToStr(sal_uInt32 nRuleID)
+{
+ OSL_ENSURE(nRuleID < SAL_N_ELEMENTS(yytname), "OSQLParser::RuleIDToStr: Invalid nRuleId!");
+ return OUString::createFromAscii(yytname[nRuleID]);
+}
+#endif
+
+
+sal_uInt32 OSQLParser::StrToRuleID(const OString & rValue)
+{
+ // Search for the given name in yytname and return the index
+ // (or UNKNOWN_RULE, if not found)
+ static sal_uInt32 nLen = SAL_N_ELEMENTS(yytname);
+ for (sal_uInt32 i = YYTRANSLATE(SQL_TOKEN_INVALIDSYMBOL); i < (nLen-1); i++)
+ {
+ if (rValue == yytname[i])
+ return i;
+ }
+
+ // Not found
+ return OSQLParseNode::UNKNOWN_RULE;
+}
+
+
+OSQLParseNode::Rule OSQLParser::RuleIDToRule( sal_uInt32 _nRule )
+{
+ OSQLParser::RuleIDMap::const_iterator i (s_aReverseRuleIDLookup.find(_nRule));
+ if (i == s_aReverseRuleIDLookup.end())
+ {
+ SAL_INFO("connectivity.parse",
+ "connectivity::OSQLParser::RuleIDToRule cannot reverse-lookup rule. "
+ "Reverse mapping incomplete? "
+ "_nRule='" << _nRule << "' "
+ "yytname[_nRule]='" << yytname[_nRule] << "'");
+ return OSQLParseNode::UNKNOWN_RULE;
+ }
+ else
+ return i->second;
+}
+
+
+sal_uInt32 OSQLParser::RuleID(OSQLParseNode::Rule eRule)
+{
+ return s_nRuleIDs[(sal_uInt16)eRule];
+}
+
+sal_Int16 OSQLParser::buildNode(OSQLParseNode*& pAppend,OSQLParseNode* pCompare,OSQLParseNode* pLiteral,OSQLParseNode* pLiteral2)
+{
+ OSQLParseNode* pColumnRef = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref));
+ pColumnRef->append(new OSQLInternalNode(m_sFieldName,SQLNodeType::Name));
+ OSQLParseNode* pComp = nullptr;
+ if ( SQL_ISTOKEN( pCompare, BETWEEN) && pLiteral2 )
+ pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate_part_2));
+ else
+ pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::comparison_predicate));
+
+ pComp->append(pColumnRef);
+ pComp->append(pCompare);
+ pComp->append(pLiteral);
+ if ( pLiteral2 )
+ {
+ pComp->append(new OSQLInternalNode("", SQLNodeType::Keyword,SQL_TOKEN_AND));
+ pComp->append(pLiteral2);
+ }
+ pAppend->append(pComp);
+ return 1;
+}
+
+sal_Int16 OSQLParser::buildStringNodes(OSQLParseNode*& pLiteral)
+{
+ if(!pLiteral)
+ return 1;
+
+ if(SQL_ISRULE(pLiteral,set_fct_spec) || SQL_ISRULE(pLiteral,general_set_fct) || SQL_ISRULE(pLiteral,column_ref)
+ || SQL_ISRULE(pLiteral,subquery))
+ return 1; // here I have a function that I can't transform into a string
+
+ if(pLiteral->getNodeType() == SQLNodeType::IntNum || pLiteral->getNodeType() == SQLNodeType::ApproxNum || pLiteral->getNodeType() == SQLNodeType::AccessDate)
+ {
+ OSQLParseNode* pParent = pLiteral->getParent();
+
+ OSQLParseNode* pNewNode = new OSQLInternalNode(pLiteral->getTokenValue(), SQLNodeType::String);
+ pParent->replace(pLiteral, pNewNode);
+ delete pLiteral;
+ pLiteral = nullptr;
+ return 1;
+ }
+
+ for(size_t i=0;i<pLiteral->count();++i)
+ {
+ OSQLParseNode* pChild = pLiteral->getChild(i);
+ buildStringNodes(pChild);
+ }
+ if(SQL_ISRULE(pLiteral,term) || SQL_ISRULE(pLiteral,value_exp_primary))
+ {
+ m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare);
+ return 0;
+ }
+ return 1;
+}
+
+sal_Int16 OSQLParser::buildComparisonRule(OSQLParseNode*& pAppend,OSQLParseNode* pLiteral)
+{
+ OSQLParseNode* pComp = new OSQLInternalNode("=", SQLNodeType::Equal);
+ return buildPredicateRule(pAppend,pLiteral,pComp);
+}
+
+
+
+void OSQLParser::reduceLiteral(OSQLParseNode*& pLiteral, bool bAppendBlank)
+{
+ OSL_ENSURE(pLiteral->isRule(), "This is no Rule");
+ OSL_ENSURE(pLiteral->count() == 2, "OSQLParser::ReduceLiteral() Invalid count");
+ OSQLParseNode* pTemp = pLiteral;
+ OUStringBuffer aValue(pLiteral->getChild(0)->getTokenValue());
+ if (bAppendBlank)
+ {
+ aValue.append(" ");
+ }
+
+ aValue.append(pLiteral->getChild(1)->getTokenValue());
+
+ pLiteral = new OSQLInternalNode(aValue.makeStringAndClear(),SQLNodeType::String);
+ delete pTemp;
+}
+
+
+void OSQLParser::error(const char *fmt)
+{
+ if(m_sErrorMessage.isEmpty())
+ {
+ OUString sStr(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8);
+ OUString sSQL_TOKEN("SQL_TOKEN_");
+
+ sal_Int32 nPos1 = sStr.indexOf(sSQL_TOKEN);
+ if(nPos1 != -1)
+ {
+ OUString sFirst = sStr.copy(0,nPos1);
+ sal_Int32 nPos2 = sStr.indexOf(sSQL_TOKEN,nPos1+1);
+ if(nPos2 != -1)
+ {
+ sFirst += sStr.subView(nPos1+sSQL_TOKEN.getLength(),nPos2-nPos1-sSQL_TOKEN.getLength());
+ sFirst += sStr.subView(nPos2+sSQL_TOKEN.getLength());
+ }
+ else
+ sFirst += sStr.subView(nPos1+sSQL_TOKEN.getLength());
+
+ m_sErrorMessage = sFirst;
+ }
+ else
+ m_sErrorMessage = sStr;
+
+ OUString aError = s_pScanner->getErrorMessage();
+ if(!aError.isEmpty())
+ {
+ m_sErrorMessage += ", ";
+ m_sErrorMessage += aError;
+ }
+ }
+}
+
+int OSQLParser::SQLlex()
+{
+ return OSQLScanner::SQLlex();
+}
diff --git a/connectivity/source/parse/sqlflex.l b/connectivity/source/parse/sqlflex.l
new file mode 100644
index 000000000..34a4067ea
--- /dev/null
+++ b/connectivity/source/parse/sqlflex.l
@@ -0,0 +1,808 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/config.h"
+
+#define YY_EXIT 1 // YY_FATAL will not halt the application
+
+#ifndef _CSTDARG_
+#include <cstdarg>
+#endif
+
+#include <string.h>
+
+#if defined _MSC_VER
+#pragma warning ( push )
+// Silence warnings about redefinition of INT8_MIN etc in stdint.h
+// The flex-generated workdir/LexTarget/idlc/source/scanner.cxx defines them prior to these includes
+#pragma warning ( disable : 4005 )
+#endif
+#include <connectivity/internalnode.hxx>
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#ifndef INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L
+#define INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L
+
+#ifndef SQLYYDEBUG
+#define SQLYYDEBUG 1
+#endif
+
+#include "sqlbison.hxx"
+#undef SQLyylex
+#undef SQLyyerror
+#endif
+#include <osl/diagnose.h>
+#include <rtl/strbuf.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqlscan.hxx>
+
+#if defined _MSC_VER
+/**/
+#ifdef yywrap
+#undef yywrap
+#define yywrap() 1
+#endif
+/**/
+#endif
+#define YY_NO_UNISTD_H
+
+using namespace connectivity;
+
+// Creation of the pages for the tokens
+// Pages generally are created from the Lexer
+
+static sal_Int32 gatherString(int delim, sal_Int32 nTyp);
+static sal_Int32 gatherName(const char*);
+static sal_Int32 gatherNamePre(const char* );
+// has to be set before the parser starts
+OSQLScanner* xxx_pGLOBAL_SQLSCAN = nullptr;
+
+#define SQL_NEW_NODE(text, token) \
+ SQLyylval.pParseNode = new OSQLInternalNode(text, token);
+
+#define SQL_NEW_KEYWORD(token) \
+ SQLyylval.pParseNode = new OSQLInternalNode("", SQLNodeType::Keyword, (token)); return token;
+
+#define SQL_NEW_INTNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::IntNum); return SQL_TOKEN_INTNUM;
+#define SQL_NEW_APPROXNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::ApproxNum); return SQL_TOKEN_APPROXNUM;
+#define SQL_NEW_DATE SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate); return SQL_TOKEN_ACCESS_DATE;
+
+#define YY_INPUT(buf,result,max_size) \
+{ \
+ int c = xxx_pGLOBAL_SQLSCAN->SQLyygetc(); \
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1);\
+}
+
+// coverity[+kill]
+static void do_fatal_error(const char* msg)
+{
+ xxx_pGLOBAL_SQLSCAN->SQLyyerror(msg);
+ /*hack to silence -Wunused-function*/
+ if ((0)) yy_fatal_error(msg);
+}
+
+#define YY_FATAL_ERROR(msg) \
+{ \
+ do_fatal_error(msg); \
+}
+
+%}
+
+%s SQL
+%s PREDICATE_ENG
+%s PREDICATE_GER
+%s DATE
+%s STRING
+
+%option noyywrap
+%option never-interactive
+%%
+
+ABS {SQL_NEW_KEYWORD(SQL_TOKEN_ABS); }
+ACOS {SQL_NEW_KEYWORD(SQL_TOKEN_ACOS); }
+AFTER {SQL_NEW_KEYWORD(SQL_TOKEN_AFTER); }
+ALL {SQL_NEW_KEYWORD(SQL_TOKEN_ALL); }
+ALTER {SQL_NEW_KEYWORD(SQL_TOKEN_ALTER); }
+AND {SQL_NEW_KEYWORD(SQL_TOKEN_AND); }
+ANY {SQL_NEW_KEYWORD(SQL_TOKEN_ANY); }
+ARRAY_AGG {SQL_NEW_KEYWORD(SQL_TOKEN_ARRAY_AGG); }
+AS {SQL_NEW_KEYWORD(SQL_TOKEN_AS); }
+ASC {SQL_NEW_KEYWORD(SQL_TOKEN_ASC); }
+ASCII {SQL_NEW_KEYWORD(SQL_TOKEN_ASCII); }
+ASIN {SQL_NEW_KEYWORD(SQL_TOKEN_ASIN); }
+AT {SQL_NEW_KEYWORD(SQL_TOKEN_AT); }
+ATAN {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN); }
+ATAN2 {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN2); }
+ATOMIC {SQL_NEW_KEYWORD(SQL_TOKEN_ATOMIC); }
+AUTHORIZATION {SQL_NEW_KEYWORD(SQL_TOKEN_AUTHORIZATION); }
+AVG {SQL_NEW_KEYWORD(SQL_TOKEN_AVG); }
+
+BEFORE {SQL_NEW_KEYWORD(SQL_TOKEN_BEFORE); }
+BEGIN {SQL_NEW_KEYWORD(SQL_TOKEN_BEGIN); }
+BETWEEN {SQL_NEW_KEYWORD(SQL_TOKEN_BETWEEN); }
+BIGINT {SQL_NEW_KEYWORD(SQL_TOKEN_BIGINT); }
+BINARY {SQL_NEW_KEYWORD(SQL_TOKEN_BINARY); }
+BIT {SQL_NEW_KEYWORD(SQL_TOKEN_BIT); }
+BIT_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_BIT_LENGTH); }
+BLOB {SQL_NEW_KEYWORD(SQL_TOKEN_BLOB); }
+BOTH {SQL_NEW_KEYWORD(SQL_TOKEN_BOTH); }
+BY {SQL_NEW_KEYWORD(SQL_TOKEN_BY); }
+
+CALL {SQL_NEW_KEYWORD(SQL_TOKEN_CALL); }
+CASE {SQL_NEW_KEYWORD(SQL_TOKEN_CASE); }
+CAST {SQL_NEW_KEYWORD(SQL_TOKEN_CAST); }
+CEILING {SQL_NEW_KEYWORD(SQL_TOKEN_CEILING); }
+CHAR {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR); }
+CHARACTER {SQL_NEW_KEYWORD(SQL_TOKEN_CHARACTER); }
+CHAR(ACTER)?_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR_LENGTH); }
+CHECK {SQL_NEW_KEYWORD(SQL_TOKEN_CHECK); }
+CLOB {SQL_NEW_KEYWORD(SQL_TOKEN_CLOB); }
+COALESCE {SQL_NEW_KEYWORD(SQL_TOKEN_COALESCE); }
+COLLATE {SQL_NEW_KEYWORD(SQL_TOKEN_COLLATE); }
+COLLECT {SQL_NEW_KEYWORD(SQL_TOKEN_COLLECT); }
+COMMIT {SQL_NEW_KEYWORD(SQL_TOKEN_COMMIT); }
+CONCAT {SQL_NEW_KEYWORD(SQL_TOKEN_CONCAT); }
+CONTINUE {SQL_NEW_KEYWORD(SQL_TOKEN_CONTINUE); }
+CONVERT {SQL_NEW_KEYWORD(SQL_TOKEN_CONVERT); }
+COS {SQL_NEW_KEYWORD(SQL_TOKEN_COS); }
+COT {SQL_NEW_KEYWORD(SQL_TOKEN_COT); }
+COUNT {SQL_NEW_KEYWORD(SQL_TOKEN_COUNT); }
+CREATE {SQL_NEW_KEYWORD(SQL_TOKEN_CREATE); }
+CROSS {SQL_NEW_KEYWORD(SQL_TOKEN_CROSS); }
+CUME_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_CUME_DIST); }
+CURRENT {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT); }
+CURRENT_DATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DATE); }
+CURRENT_CATALOG {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_CATALOG); }
+CURRENT_DEFAULT_TRANSFORM_GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP); }
+CURRENT_PATH {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_PATH); }
+CURRENT_ROLE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_ROLE); }
+CURRENT_SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_SCHEMA); }
+CURRENT_USER {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_USER); }
+CURDATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURDATE); }
+CURRENT_TIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIME); }
+CURTIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURTIME); }
+CURRENT_TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIMESTAMP); }
+CURSOR {SQL_NEW_KEYWORD(SQL_TOKEN_CURSOR); }
+
+D {SQL_NEW_KEYWORD(SQL_TOKEN_D); }
+DATE {SQL_NEW_KEYWORD(SQL_TOKEN_DATE); }
+DATEDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_DATEDIFF); }
+DATEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_DATEVALUE); }
+DAY {SQL_NEW_KEYWORD(SQL_TOKEN_DAY); }
+DAYNAME {SQL_NEW_KEYWORD(SQL_TOKEN_DAYNAME); }
+DAYOFMONTH {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFMONTH); }
+DAYOFWEEK {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFWEEK); }
+DAYOFYEAR {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFYEAR); }
+DEC {SQL_NEW_KEYWORD(SQL_TOKEN_DEC); }
+DECIMAL {SQL_NEW_KEYWORD(SQL_TOKEN_DECIMAL); }
+DECLARE {SQL_NEW_KEYWORD(SQL_TOKEN_DECLARE); }
+DEFAULT {SQL_NEW_KEYWORD(SQL_TOKEN_DEFAULT); }
+DEGREES {SQL_NEW_KEYWORD(SQL_TOKEN_DEGREES); }
+DELETE {SQL_NEW_KEYWORD(SQL_TOKEN_DELETE); }
+DENSE_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_DENSE_RANK); }
+DESC {SQL_NEW_KEYWORD(SQL_TOKEN_DESC); }
+DIFFERENCE {SQL_NEW_KEYWORD(SQL_TOKEN_DIFFERENCE); }
+DISTINCT {SQL_NEW_KEYWORD(SQL_TOKEN_DISTINCT); }
+DOUBLE {SQL_NEW_KEYWORD(SQL_TOKEN_DOUBLE); }
+DROP {SQL_NEW_KEYWORD(SQL_TOKEN_DROP); }
+
+EACH {SQL_NEW_KEYWORD(SQL_TOKEN_EACH); }
+ELSE {SQL_NEW_KEYWORD(SQL_TOKEN_ELSE); }
+END {SQL_NEW_KEYWORD(SQL_TOKEN_END); }
+EVERY {SQL_NEW_KEYWORD(SQL_TOKEN_EVERY); }
+ESCAPE {SQL_NEW_KEYWORD(SQL_TOKEN_ESCAPE); }
+EXCEPT {SQL_NEW_KEYWORD(SQL_TOKEN_EXCEPT); }
+EXCLUDE {SQL_NEW_KEYWORD(SQL_TOKEN_EXCLUDE); }
+EXISTS {SQL_NEW_KEYWORD(SQL_TOKEN_EXISTS); }
+EXP {SQL_NEW_KEYWORD(SQL_TOKEN_EXP); }
+EXTRACT {SQL_NEW_KEYWORD(SQL_TOKEN_EXTRACT); }
+
+FALSE {SQL_NEW_KEYWORD(SQL_TOKEN_FALSE); }
+FETCH {SQL_NEW_KEYWORD(SQL_TOKEN_FETCH); }
+FIRST {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST); }
+FIRST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST_VALUE); }
+FLOAT {SQL_NEW_KEYWORD(SQL_TOKEN_FLOAT); }
+FLOOR {SQL_NEW_KEYWORD(SQL_TOKEN_FLOOR); }
+FN {SQL_NEW_KEYWORD(SQL_TOKEN_FN); }
+FOLLOWING {SQL_NEW_KEYWORD(SQL_TOKEN_FOLLOWING); }
+FOR {SQL_NEW_KEYWORD(SQL_TOKEN_FOR); }
+FOREIGN {SQL_NEW_KEYWORD(SQL_TOKEN_FOREIGN); }
+FOUND {SQL_NEW_KEYWORD(SQL_TOKEN_FOUND); }
+FROM {SQL_NEW_KEYWORD(SQL_TOKEN_FROM); }
+FULL {SQL_NEW_KEYWORD(SQL_TOKEN_FULL); }
+FUSION {SQL_NEW_KEYWORD(SQL_TOKEN_FUSION); }
+
+GRANT {SQL_NEW_KEYWORD(SQL_TOKEN_GRANT); }
+GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_GROUP); }
+
+HAVING {SQL_NEW_KEYWORD(SQL_TOKEN_HAVING); }
+HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_HOUR); }
+
+IGNORE {SQL_NEW_KEYWORD(SQL_TOKEN_IGNORE); }
+IN {SQL_NEW_KEYWORD(SQL_TOKEN_IN); }
+INNER {SQL_NEW_KEYWORD(SQL_TOKEN_INNER); }
+INSERT {SQL_NEW_KEYWORD(SQL_TOKEN_INSERT); }
+INSTEAD {SQL_NEW_KEYWORD(SQL_TOKEN_INSTEAD); }
+INT(EGER)? {SQL_NEW_KEYWORD(SQL_TOKEN_INTEGER); }
+INTERSECT {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECT); }
+INTERVAL {SQL_NEW_KEYWORD(SQL_TOKEN_INTERVAL); }
+INTERSECTION {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECTION); }
+INTO {SQL_NEW_KEYWORD(SQL_TOKEN_INTO); }
+IS {SQL_NEW_KEYWORD(SQL_TOKEN_IS); }
+
+JOIN {SQL_NEW_KEYWORD(SQL_TOKEN_JOIN); }
+
+KEY {SQL_NEW_KEYWORD(SQL_TOKEN_KEY); }
+
+LAG {SQL_NEW_KEYWORD(SQL_TOKEN_LAG); }
+LARGE {SQL_NEW_KEYWORD(SQL_TOKEN_LARGE); }
+LAST {SQL_NEW_KEYWORD(SQL_TOKEN_LAST); }
+LAST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_LAST_VALUE); }
+LCASE {SQL_NEW_KEYWORD(SQL_TOKEN_LCASE); }
+LEAD {SQL_NEW_KEYWORD(SQL_TOKEN_LEAD); }
+LEADING {SQL_NEW_KEYWORD(SQL_TOKEN_LEADING); }
+LEFT {SQL_NEW_KEYWORD(SQL_TOKEN_LEFT); }
+LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_LENGTH); }
+LIKE {SQL_NEW_KEYWORD(SQL_TOKEN_LIKE); }
+LIMIT {SQL_NEW_KEYWORD(SQL_TOKEN_LIMIT); }
+LN {SQL_NEW_KEYWORD(SQL_TOKEN_LN); }
+LOCAL {SQL_NEW_KEYWORD(SQL_TOKEN_LOCAL); }
+LOCATE {SQL_NEW_KEYWORD(SQL_TOKEN_LOCATE); }
+LOG {SQL_NEW_KEYWORD(SQL_TOKEN_LOG); }
+LOGF {SQL_NEW_KEYWORD(SQL_TOKEN_LOGF); }
+LOG10 {SQL_NEW_KEYWORD(SQL_TOKEN_LOG10); }
+LOWER {SQL_NEW_KEYWORD(SQL_TOKEN_LOWER); }
+LTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_LTRIM); }
+
+MAX {SQL_NEW_KEYWORD(SQL_TOKEN_MAX); }
+MILLISECOND {SQL_NEW_KEYWORD(SQL_TOKEN_MILLISECOND); }
+MIN {SQL_NEW_KEYWORD(SQL_TOKEN_MIN); }
+MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_MINUTE); }
+MOD {SQL_NEW_KEYWORD(SQL_TOKEN_MOD); }
+MONTH {SQL_NEW_KEYWORD(SQL_TOKEN_MONTH); }
+MONTHNAME {SQL_NEW_KEYWORD(SQL_TOKEN_MONTHNAME); }
+
+NATIONAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATIONAL); }
+NATURAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATURAL); }
+NCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_NCHAR); }
+NCLOB {SQL_NEW_KEYWORD(SQL_TOKEN_NCLOB); }
+NEW {SQL_NEW_KEYWORD(SQL_TOKEN_NEW); }
+NEXT {SQL_NEW_KEYWORD(SQL_TOKEN_NEXT); }
+NO {SQL_NEW_KEYWORD(SQL_TOKEN_NO); }
+NOT {SQL_NEW_KEYWORD(SQL_TOKEN_NOT); }
+NOW {SQL_NEW_KEYWORD(SQL_TOKEN_NOW); }
+NTH_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_NTH_VALUE); }
+NTILE {SQL_NEW_KEYWORD(SQL_TOKEN_NTILE); }
+NULL {SQL_NEW_KEYWORD(SQL_TOKEN_NULL); }
+NULLIF {SQL_NEW_KEYWORD(SQL_TOKEN_NULLIF); }
+NULLS {SQL_NEW_KEYWORD(SQL_TOKEN_NULLS); }
+NUMERIC {SQL_NEW_KEYWORD(SQL_TOKEN_NUMERIC); }
+
+OBJECT {SQL_NEW_KEYWORD(SQL_TOKEN_OBJECT); }
+OCTET_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_OCTET_LENGTH); }
+OF {SQL_NEW_KEYWORD(SQL_TOKEN_OF); }
+OFFSET {SQL_NEW_KEYWORD(SQL_TOKEN_OFFSET); }
+OJ {SQL_NEW_KEYWORD(SQL_TOKEN_OJ); }
+OLD {SQL_NEW_KEYWORD(SQL_TOKEN_OLD); }
+ON {SQL_NEW_KEYWORD(SQL_TOKEN_ON); }
+ONLY {SQL_NEW_KEYWORD(SQL_TOKEN_ONLY); }
+OPTION {SQL_NEW_KEYWORD(SQL_TOKEN_OPTION); }
+OR {SQL_NEW_KEYWORD(SQL_TOKEN_OR); }
+ORDER {SQL_NEW_KEYWORD(SQL_TOKEN_ORDER); }
+OTHERS {SQL_NEW_KEYWORD(SQL_TOKEN_OTHERS); }
+OUTER {SQL_NEW_KEYWORD(SQL_TOKEN_OUTER); }
+OVER {SQL_NEW_KEYWORD(SQL_TOKEN_OVER); }
+
+PARTITION {SQL_NEW_KEYWORD(SQL_TOKEN_PARTITION); }
+PERCENT_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENT_RANK); }
+PERCENTILE_CONT {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_CONT); }
+PERCENTILE_DISC {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_DISC); }
+PI {SQL_NEW_KEYWORD(SQL_TOKEN_PI); }
+POSITION {SQL_NEW_KEYWORD(SQL_TOKEN_POSITION); }
+POWER {SQL_NEW_KEYWORD(SQL_TOKEN_POWER); }
+PRECEDING {SQL_NEW_KEYWORD(SQL_TOKEN_PRECEDING); }
+PRECISION {SQL_NEW_KEYWORD(SQL_TOKEN_PRECISION); }
+PRIMARY {SQL_NEW_KEYWORD(SQL_TOKEN_PRIMARY); }
+PRIVILEGES {SQL_NEW_KEYWORD(SQL_TOKEN_PRIVILEGES); }
+PROCEDURE {SQL_NEW_KEYWORD(SQL_TOKEN_PROCEDURE); }
+PUBLIC {SQL_NEW_KEYWORD(SQL_TOKEN_PUBLIC); }
+
+QUARTER {SQL_NEW_KEYWORD(SQL_TOKEN_QUARTER); }
+
+RADIANS {SQL_NEW_KEYWORD(SQL_TOKEN_RADIANS); }
+RAND {SQL_NEW_KEYWORD(SQL_TOKEN_RAND); }
+RANGE {SQL_NEW_KEYWORD(SQL_TOKEN_RANGE); }
+RANK {SQL_NEW_KEYWORD(SQL_TOKEN_RANK); }
+REAL {SQL_NEW_KEYWORD(SQL_TOKEN_REAL); }
+REFERENCES {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCES); }
+REFERENCING {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCING); }
+REPEAT {SQL_NEW_KEYWORD(SQL_TOKEN_REPEAT); }
+REPLACE {SQL_NEW_KEYWORD(SQL_TOKEN_REPLACE); }
+RESPECT {SQL_NEW_KEYWORD(SQL_TOKEN_RESPECT); }
+ROLLBACK {SQL_NEW_KEYWORD(SQL_TOKEN_ROLLBACK); }
+ROUND {SQL_NEW_KEYWORD(SQL_TOKEN_ROUND); }
+ROUNDMAGIC {SQL_NEW_KEYWORD(SQL_TOKEN_ROUNDMAGIC); }
+ROW {SQL_NEW_KEYWORD(SQL_TOKEN_ROW); }
+ROWS {SQL_NEW_KEYWORD(SQL_TOKEN_ROWS); }
+ROW_NUMBER {SQL_NEW_KEYWORD(SQL_TOKEN_ROW_NUMBER); }
+RIGHT {SQL_NEW_KEYWORD(SQL_TOKEN_RIGHT); }
+RTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_RTRIM); }
+
+SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_SCHEMA); }
+SECOND {SQL_NEW_KEYWORD(SQL_TOKEN_SECOND); }
+SELECT {SQL_NEW_KEYWORD(SQL_TOKEN_SELECT); }
+SET {SQL_NEW_KEYWORD(SQL_TOKEN_SET); }
+SIZE {SQL_NEW_KEYWORD(SQL_TOKEN_SIZE); }
+SIGN {SQL_NEW_KEYWORD(SQL_TOKEN_SIGN); }
+SIN {SQL_NEW_KEYWORD(SQL_TOKEN_SIN); }
+SMALLINT {SQL_NEW_KEYWORD(SQL_TOKEN_SMALLINT); }
+SOME {SQL_NEW_KEYWORD(SQL_TOKEN_SOME); }
+SOUNDEX {SQL_NEW_KEYWORD(SQL_TOKEN_SOUNDEX); }
+SPACE {SQL_NEW_KEYWORD(SQL_TOKEN_SPACE); }
+SQRT {SQL_NEW_KEYWORD(SQL_TOKEN_SQRT); }
+STDDEV_POP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_POP); }
+STDDEV_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_SAMP); }
+STATEMENT {SQL_NEW_KEYWORD(SQL_TOKEN_STATEMENT); }
+SUBSTRING {SQL_NEW_KEYWORD(SQL_TOKEN_SUBSTRING); }
+SUM {SQL_NEW_KEYWORD(SQL_TOKEN_SUM); }
+SESSION_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SESSION_USER); }
+SYSTEM_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SYSTEM_USER); }
+
+TABLE {SQL_NEW_KEYWORD(SQL_TOKEN_TABLE); }
+TAN {SQL_NEW_KEYWORD(SQL_TOKEN_TAN); }
+THEN {SQL_NEW_KEYWORD(SQL_TOKEN_THEN); }
+TIES {SQL_NEW_KEYWORD(SQL_TOKEN_TIES); }
+TIME {SQL_NEW_KEYWORD(SQL_TOKEN_TIME); }
+TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMP); }
+TIMESTAMPADD {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPADD); }
+TIMESTAMPDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPDIFF); }
+TIMEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEVALUE); }
+TIMEZONE_HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_HOUR); }
+TIMEZONE_MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_MINUTE); }
+TO {SQL_NEW_KEYWORD(SQL_TOKEN_TO); }
+TRAILING {SQL_NEW_KEYWORD(SQL_TOKEN_TRAILING); }
+TRANSLATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRANSLATE); }
+TRIGGER {SQL_NEW_KEYWORD(SQL_TOKEN_TRIGGER); }
+TRIM {SQL_NEW_KEYWORD(SQL_TOKEN_TRIM); }
+TRUE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUE); }
+TRUNCATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUNCATE); }
+TS {SQL_NEW_KEYWORD(SQL_TOKEN_TS); }
+T {SQL_NEW_KEYWORD(SQL_TOKEN_T); }
+
+UCASE {SQL_NEW_KEYWORD(SQL_TOKEN_UCASE); }
+UNBOUNDED {SQL_NEW_KEYWORD(SQL_TOKEN_UNBOUNDED); }
+UNION {SQL_NEW_KEYWORD(SQL_TOKEN_UNION); }
+UNIQUE {SQL_NEW_KEYWORD(SQL_TOKEN_UNIQUE); }
+UNKNOWN {SQL_NEW_KEYWORD(SQL_TOKEN_UNKNOWN); }
+UPDATE {SQL_NEW_KEYWORD(SQL_TOKEN_UPDATE); }
+UPPER {SQL_NEW_KEYWORD(SQL_TOKEN_UPPER); }
+USAGE {SQL_NEW_KEYWORD(SQL_TOKEN_USAGE); }
+USER {SQL_NEW_KEYWORD(SQL_TOKEN_USER); }
+USING {SQL_NEW_KEYWORD(SQL_TOKEN_USING); }
+
+VARBINARY {SQL_NEW_KEYWORD(SQL_TOKEN_VARBINARY); }
+VARCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_VARCHAR); }
+VARYING {SQL_NEW_KEYWORD(SQL_TOKEN_VARYING); }
+VAR_POP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_POP); }
+VAR_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_SAMP); }
+VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_VALUE); }
+VALUES {SQL_NEW_KEYWORD(SQL_TOKEN_VALUES); }
+VIEW {SQL_NEW_KEYWORD(SQL_TOKEN_VIEW); }
+
+WEEK {SQL_NEW_KEYWORD(SQL_TOKEN_WEEK); }
+WEEKDAY {SQL_NEW_KEYWORD(SQL_TOKEN_WEEKDAY); }
+WHEN {SQL_NEW_KEYWORD(SQL_TOKEN_WHEN); }
+WHERE {SQL_NEW_KEYWORD(SQL_TOKEN_WHERE); }
+WITH {SQL_NEW_KEYWORD(SQL_TOKEN_WITH); }
+WITHIN {SQL_NEW_KEYWORD(SQL_TOKEN_WITHIN); }
+WITHOUT {SQL_NEW_KEYWORD(SQL_TOKEN_WITHOUT); }
+WORK {SQL_NEW_KEYWORD(SQL_TOKEN_WORK); }
+
+YEAR {SQL_NEW_KEYWORD(SQL_TOKEN_YEAR); }
+YEARDAY {SQL_NEW_KEYWORD(SQL_TOKEN_YEARDAY); }
+
+ZONE {SQL_NEW_KEYWORD(SQL_TOKEN_ZONE); }
+
+"<" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Less);return SQL_LESS;}
+">" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Great);return SQL_GREAT;}
+"=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Equal);return SQL_EQUAL;}
+"<=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::LessEq);return SQL_LESSEQ;}
+">=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::GreatEq);return SQL_GREATEQ;}
+"<>" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;}
+"!=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;}
+"||" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Concat);return SQL_CONCAT;}
+
+
+[-+*/:(),.;?{}] { return SQLyytext[0]; }
+
+
+<SQL>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375_0-9]* {return gatherName( SQLyytext);}
+
+<SQL>([0-9]+) {SQL_NEW_INTNUM; }
+
+<SQL>("."[0-9]*) |
+<SQL>([0-9]+"."[0-9]*) |
+<SQL>[0-9]+[eE][+-]?[0-9]+ |
+<SQL>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
+<SQL>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z0-9_%.,*?\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375]* {return gatherNamePre(SQLyytext);}
+
+<PREDICATE_GER,PREDICATE_ENG>([0-9]+) {SQL_NEW_INTNUM; }
+<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+) {SQL_NEW_INTNUM; }
+<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+) {SQL_NEW_INTNUM; }
+
+<PREDICATE_ENG>([0-9]+"."[0-9]+) |
+<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+"."[0-9]+) |
+<PREDICATE_ENG>("."[0-9]+) {SQL_NEW_APPROXNUM; }
+<PREDICATE_ENG>[0-9]+[eE][+-]?[0-9]+ |
+<PREDICATE_ENG>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ |
+<PREDICATE_ENG>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER>([0-9]+","[0-9]+) |
+<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+","[0-9]+) |
+<PREDICATE_GER>(","[0-9]+) {SQL_NEW_APPROXNUM; }
+<PREDICATE_GER>[0-9]+[eE][+-]?[0-9]+ |
+<PREDICATE_GER>[0-9]+","[0-9]*[eE][+-]?[0-9]+ |
+<PREDICATE_GER>","[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; }
+
+<PREDICATE_GER,PREDICATE_ENG>[0-9.,][A-Za-z0-9_.,%]* {return gatherNamePre(SQLyytext);}
+
+<SQL>\" { return gatherString('\"',0); }
+<SQL>` { return gatherString('`' ,0); }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE,SQL>"[" { return gatherString(']' ,0);}
+
+\' { return gatherString('\'',1); }
+
+<PREDICATE_GER,PREDICATE_ENG,DATE># { return gatherString('#' ,2); }
+
+<DATE>[0-9]{1,4}[^ ]*[0-9] |
+<DATE>[0-9]{1,4}[^ ]*[0-9][ ][0-9]{1,4}[^ ]*[0-9] { SQL_NEW_DATE; }
+
+<STRING>["-""+""*""/"":""("")"",""."";""?""{""}"] { return SQLyytext[0]; } /* */
+<STRING>"[" { return gatherString(']' ,0); }
+<STRING>[^ ':["?"]* { return gatherNamePre(SQLyytext); }
+
+\n {}
+
+[ \t\r]+ {}
+
+"--".*$ {}
+
+. {YY_FATAL_ERROR("Invalid symbol"); return SQL_TOKEN_INVALIDSYMBOL;}
+
+%%
+
+// Kludge around a bug (well, Posix incompatibility) in flex 2.5.x
+// http://bugs.debian.org/cgi-bin/bugreport.cgi?archive=no&bug=189332
+#if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5
+
+ #ifndef YY_FLUSH_BUFFER
+ #define YY_FLUSH_BUFFER SQLyy_flush_buffer(YY_CURRENT_BUFFER )
+ #endif
+
+ #ifndef yytext_ptr
+ #define yytext_ptr SQLyytext
+ #endif
+
+#endif
+
+// Versions of flex apparently differ in whether input() resp. yyinput() returns
+// zero or EOF upon end of file:
+inline bool checkeof(int c) { return c == 0 || c == EOF; }
+
+/*
+ * Read SQL string literal
+ * Valid strings:
+ * '' 'a string' 'quote '' within string'
+ * "" "a string" "quote "" within string"
+ * nTyp == 0 -> SQLNodeType::Name
+ * nTyp == 1 -> SQLNodeType::String
+ * nTyp == 2 -> SQLNodeType::AccessDate
+ */
+sal_Int32 gatherString(int delim, sal_Int32 nTyp)
+{
+ int ch;
+ OStringBuffer sBuffer(256);
+
+ assert(nTyp == 0 || nTyp == 1 || nTyp == 2);
+
+ while (!checkeof(ch = yyinput()))
+ {
+ if (ch == delim)
+ {
+ if ((ch = yyinput()) != delim)
+ {
+ if (!checkeof(ch))
+ unput(ch);
+
+ switch(nTyp)
+ {
+ case 0:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ return SQL_TOKEN_NAME;
+ case 1:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::String);
+ return SQL_TOKEN_STRING;
+ case 2:
+ SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate);
+ return SQL_TOKEN_ACCESS_DATE;
+ }
+ }
+ else
+ {
+ sBuffer.append(static_cast<char>(ch));
+ }
+
+ }
+ else if (nTyp == 2 && (ch == '\r' || ch == '\n') )
+ break;
+ else
+ {
+ sBuffer.append(static_cast<char>(ch));
+ }
+ }
+ YY_FATAL_ERROR("Unterminated name string");
+ return SQL_TOKEN_INVALIDSYMBOL;
+}
+
+sal_Int32 mapEnumToToken(IParseContext::InternationalKeyCode _eKeyCode )
+{
+ sal_Int32 nTokenID = 0;
+ switch( _eKeyCode )
+ {
+ case IParseContext::InternationalKeyCode::Like: nTokenID = SQL_TOKEN_LIKE; break;
+ case IParseContext::InternationalKeyCode::Not: nTokenID = SQL_TOKEN_NOT; break;
+ case IParseContext::InternationalKeyCode::Null: nTokenID = SQL_TOKEN_NULL; break;
+ case IParseContext::InternationalKeyCode::True: nTokenID = SQL_TOKEN_TRUE; break;
+ case IParseContext::InternationalKeyCode::False: nTokenID = SQL_TOKEN_FALSE; break;
+ case IParseContext::InternationalKeyCode::Is: nTokenID = SQL_TOKEN_IS; break;
+ case IParseContext::InternationalKeyCode::Between: nTokenID = SQL_TOKEN_BETWEEN; break;
+ case IParseContext::InternationalKeyCode::Or: nTokenID = SQL_TOKEN_OR; break;
+ case IParseContext::InternationalKeyCode::And: nTokenID = SQL_TOKEN_AND; break;
+ case IParseContext::InternationalKeyCode::Avg: nTokenID = SQL_TOKEN_AVG; break;
+ case IParseContext::InternationalKeyCode::Count: nTokenID = SQL_TOKEN_COUNT; break;
+ case IParseContext::InternationalKeyCode::Max: nTokenID = SQL_TOKEN_MAX; break;
+ case IParseContext::InternationalKeyCode::Min: nTokenID = SQL_TOKEN_MIN; break;
+ case IParseContext::InternationalKeyCode::Sum: nTokenID = SQL_TOKEN_SUM; break;
+ case IParseContext::InternationalKeyCode::Every: nTokenID = SQL_TOKEN_EVERY; break;
+ case IParseContext::InternationalKeyCode::Any: nTokenID = SQL_TOKEN_ANY; break;
+ case IParseContext::InternationalKeyCode::Some: nTokenID = SQL_TOKEN_SOME; break;
+ case IParseContext::InternationalKeyCode::StdDevPop: nTokenID = SQL_TOKEN_STDDEV_POP; break;
+ case IParseContext::InternationalKeyCode::StdDevSamp: nTokenID = SQL_TOKEN_STDDEV_SAMP; break;
+ case IParseContext::InternationalKeyCode::VarSamp: nTokenID = SQL_TOKEN_VAR_SAMP; break;
+ case IParseContext::InternationalKeyCode::VarPop: nTokenID = SQL_TOKEN_VAR_POP; break;
+ case IParseContext::InternationalKeyCode::Collect: nTokenID = SQL_TOKEN_COLLECT; break;
+ case IParseContext::InternationalKeyCode::Fusion: nTokenID = SQL_TOKEN_FUSION; break;
+ case IParseContext::InternationalKeyCode::Intersection: nTokenID = SQL_TOKEN_INTERSECTION; break;
+ default:
+ OSL_FAIL( "mapEnumToToken: unsupported key!" );
+ }
+ return nTokenID;
+}
+/*
+ * Read SQL Name literal
+ * Valid Names or international keywords:
+ * As we have international keywords, we test first on them
+ */
+sal_Int32 gatherName(const char* text)
+{
+ sal_Int32 nToken;
+ OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!");
+ IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text);
+ switch (eKeyCode)
+ {
+ case IParseContext::InternationalKeyCode::Like:
+ case IParseContext::InternationalKeyCode::Not:
+ case IParseContext::InternationalKeyCode::Null:
+ case IParseContext::InternationalKeyCode::True:
+ case IParseContext::InternationalKeyCode::False:
+ case IParseContext::InternationalKeyCode::Is:
+ case IParseContext::InternationalKeyCode::Between:
+ case IParseContext::InternationalKeyCode::Or:
+ case IParseContext::InternationalKeyCode::And:
+ case IParseContext::InternationalKeyCode::Count:
+ case IParseContext::InternationalKeyCode::Avg:
+ case IParseContext::InternationalKeyCode::Max:
+ case IParseContext::InternationalKeyCode::Min:
+ case IParseContext::InternationalKeyCode::Sum:
+ case IParseContext::InternationalKeyCode::Every:
+ case IParseContext::InternationalKeyCode::Any:
+ case IParseContext::InternationalKeyCode::Some:
+ case IParseContext::InternationalKeyCode::StdDevPop:
+ case IParseContext::InternationalKeyCode::StdDevSamp:
+ case IParseContext::InternationalKeyCode::VarSamp:
+ case IParseContext::InternationalKeyCode::VarPop:
+ case IParseContext::InternationalKeyCode::Collect:
+ case IParseContext::InternationalKeyCode::Fusion:
+ case IParseContext::InternationalKeyCode::Intersection:
+ nToken = mapEnumToToken(eKeyCode);
+ SQL_NEW_KEYWORD(nToken);
+ break;
+ default:
+ SQL_NEW_NODE(OUString(text,strlen(text),RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ return SQL_TOKEN_NAME;
+ }
+}
+/**
+ Read SQL Name literal for predicate check
+ Valid Names or international keywords:
+ As we have international keywords, we test first on them
+*/
+sal_Int32 gatherNamePre(const char* text)
+{
+ sal_Int32 nToken;
+ OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!");
+ IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text);
+ switch (eKeyCode)
+ {
+ case IParseContext::InternationalKeyCode::Like:
+ case IParseContext::InternationalKeyCode::Not:
+ case IParseContext::InternationalKeyCode::Null:
+ case IParseContext::InternationalKeyCode::True:
+ case IParseContext::InternationalKeyCode::False:
+ case IParseContext::InternationalKeyCode::Is:
+ case IParseContext::InternationalKeyCode::Between:
+ case IParseContext::InternationalKeyCode::Or:
+ case IParseContext::InternationalKeyCode::And:
+ case IParseContext::InternationalKeyCode::Count:
+ case IParseContext::InternationalKeyCode::Avg:
+ case IParseContext::InternationalKeyCode::Max:
+ case IParseContext::InternationalKeyCode::Min:
+ case IParseContext::InternationalKeyCode::Sum:
+ case IParseContext::InternationalKeyCode::Every:
+ case IParseContext::InternationalKeyCode::Any:
+ case IParseContext::InternationalKeyCode::Some:
+ case IParseContext::InternationalKeyCode::StdDevPop:
+ case IParseContext::InternationalKeyCode::StdDevSamp:
+ case IParseContext::InternationalKeyCode::VarSamp:
+ case IParseContext::InternationalKeyCode::VarPop:
+ case IParseContext::InternationalKeyCode::Collect:
+ case IParseContext::InternationalKeyCode::Fusion:
+ case IParseContext::InternationalKeyCode::Intersection:
+ nToken = mapEnumToToken(eKeyCode);
+ SQL_NEW_KEYWORD(nToken);
+ break;
+ default:
+ // we need a special handling for parameter
+ {
+ OString sStmt = xxx_pGLOBAL_SQLSCAN->getStatement();
+ sal_Int32 nLength = strlen(text);
+ sal_Int32 nPos = xxx_pGLOBAL_SQLSCAN->GetCurrentPos() - nLength - 2;
+ if (sStmt.getStr()[nPos] == ':')
+ {
+ SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::Name);
+ nToken = SQL_TOKEN_NAME;
+ }
+ else
+ {
+ SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::String);
+ nToken = SQL_TOKEN_STRING;
+ }
+ }
+ }
+ return nToken;
+}
+
+using namespace connectivity;
+
+static bool IN_SQLyyerror;
+//------------------------------------------------------------------------------
+OSQLScanner::OSQLScanner()
+ : m_pContext(nullptr)
+ , m_nCurrentPos(0)
+ , m_bInternational(false)
+ , m_nRule(0) // 0 is INITIAL
+{
+ IN_SQLyyerror = false;
+}
+
+//------------------------------------------------------------------------------
+OSQLScanner::~OSQLScanner()
+{
+}
+//------------------------------------------------------------------------------
+void OSQLScanner::SQLyyerror(char const *fmt)
+{
+
+ if(IN_SQLyyerror)
+ return;
+ IN_SQLyyerror = true;
+
+ OSL_ENSURE(m_pContext, "OSQLScanner::SQLyyerror: No Context set");
+ m_sErrorMessage = OUString(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8);
+ if (m_nCurrentPos < m_sStatement.getLength())
+ {
+ m_sErrorMessage += ": ";
+
+ OUString aError;
+ OUStringBuffer Buffer(256);
+
+ int ch = SQLyytext ? (SQLyytext[0] == 0 ? ' ' : SQLyytext[0]): ' ';
+ Buffer.append((sal_Unicode)ch);
+ while (!checkeof(ch = yyinput()))
+ {
+ if (ch == ' ')
+ {
+ if ((ch = yyinput()) != ' ')
+ {
+ if (!checkeof(ch))
+ unput(ch);
+ }
+ aError = Buffer.makeStringAndClear();
+ break;
+ }
+ else
+ {
+ Buffer.append((sal_Unicode)ch);
+ }
+ }
+ m_sErrorMessage += aError;
+ }
+ IN_SQLyyerror = false;
+ YY_FLUSH_BUFFER;
+}
+
+//------------------------------------------------------------------------------
+void OSQLScanner::prepareScan(const OUString & rNewStatement, const IParseContext* pContext, bool bInternational)
+{
+ YY_FLUSH_BUFFER;
+ BEGIN(m_nRule);
+
+ m_sErrorMessage = OUString();
+ m_sStatement = OUStringToOString(rNewStatement, RTL_TEXTENCODING_UTF8);
+ m_nCurrentPos = 0;
+ m_bInternational = bInternational;
+ m_pContext = pContext;
+}
+
+//------------------------------------------------------------------------------
+sal_Int32 OSQLScanner::SQLyygetc(void)
+{
+ sal_Int32 nPos = (m_nCurrentPos >= m_sStatement.getLength()) ? EOF : m_sStatement.getStr()[m_nCurrentPos];
+ m_nCurrentPos++;
+ return nPos;
+}
+
+//------------------------------------------------------------------------------
+IParseContext::InternationalKeyCode OSQLScanner::getInternationalTokenID(const char* sToken) const
+{
+ OSL_ENSURE(m_pContext, "OSQLScanner::getInternationalTokenID: No Context set");
+ return (m_bInternational) ? m_pContext->getIntlKeyCode(OString(sToken) ) : IParseContext::InternationalKeyCode::None;
+}
+sal_Int32 OSQLScanner::GetGERRule() { return PREDICATE_GER; }
+sal_Int32 OSQLScanner::GetENGRule() { return PREDICATE_ENG; }
+sal_Int32 OSQLScanner::GetSQLRule() { return SQL; }
+sal_Int32 OSQLScanner::GetDATERule() { return DATE; }
+sal_Int32 OSQLScanner::GetSTRINGRule() { return STRING; }
+void OSQLScanner::setScanner(bool _bNull)
+{
+ xxx_pGLOBAL_SQLSCAN = _bNull ? nullptr : this;
+}
+sal_Int32 OSQLScanner::SQLlex()
+{
+ return SQLyylex();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/connectivity/source/parse/sqliterator.cxx b/connectivity/source/parse/sqliterator.cxx
new file mode 100644
index 000000000..fcebd2879
--- /dev/null
+++ b/connectivity/source/parse/sqliterator.cxx
@@ -0,0 +1,2117 @@
+/* -*- 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 <connectivity/sqliterator.hxx>
+#include <connectivity/sdbcx/VTable.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <sqlbison.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#ifdef SQL_TEST_PARSETREEITERATOR
+#include <iostream>
+#endif
+#include <connectivity/PColumn.hxx>
+#include <tools/diagnose_ex.h>
+#include <TConnection.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+
+#include <iterator>
+#include <memory>
+
+using namespace ::comphelper;
+using namespace ::connectivity;
+using namespace ::connectivity::sdbcx;
+using namespace ::dbtools;
+using namespace ::connectivity::parse;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+
+namespace connectivity
+{
+ struct OSQLParseTreeIteratorImpl
+ {
+ std::vector< TNodePair > m_aJoinConditions;
+ Reference< XConnection > m_xConnection;
+ Reference< XDatabaseMetaData > m_xDatabaseMetaData;
+ Reference< XNameAccess > m_xTableContainer;
+ Reference< XNameAccess > m_xQueryContainer;
+
+ std::shared_ptr< OSQLTables > m_pTables; // all tables which participate in the SQL statement
+ std::shared_ptr< OSQLTables > m_pSubTables; // all tables from sub queries not the tables from the select tables
+ std::shared_ptr< QueryNameSet > m_pForbiddenQueryNames;
+
+ TraversalParts m_nIncludeMask;
+
+ bool m_bIsCaseSensitive;
+
+ OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables )
+ :m_xConnection( _rxConnection )
+ ,m_nIncludeMask( TraversalParts::All )
+ ,m_bIsCaseSensitive( true )
+ {
+ OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" );
+ m_xDatabaseMetaData = m_xConnection->getMetaData();
+
+ m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers();
+ m_pTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
+ m_pSubTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive );
+
+ m_xTableContainer = _rxTables;
+
+ DatabaseMetaData aMetaData( m_xConnection );
+ if ( aMetaData.supportsSubqueriesInFrom() )
+ {
+ // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection
+ // service
+ Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY );
+ if ( xSuppQueries.is() )
+ m_xQueryContainer = xSuppQueries->getQueries();
+ }
+ }
+
+ public:
+ bool isQueryAllowed( const OUString& _rQueryName )
+ {
+ if ( !m_pForbiddenQueryNames )
+ return true;
+ if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() )
+ return true;
+ return false;
+ }
+ };
+
+ namespace {
+
+ /** helper class for temporarily adding a query name to a list of forbidden query names
+ */
+ class ForbidQueryName
+ {
+ std::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames;
+ OUString m_sForbiddenQueryName;
+
+ public:
+ ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, const OUString& _rForbiddenQueryName )
+ :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames )
+ ,m_sForbiddenQueryName( _rForbiddenQueryName )
+ {
+ if ( !m_rpAllForbiddenNames )
+ m_rpAllForbiddenNames = std::make_shared<QueryNameSet>();
+ m_rpAllForbiddenNames->insert( m_sForbiddenQueryName );
+ }
+
+ ~ForbidQueryName()
+ {
+ m_rpAllForbiddenNames->erase( m_sForbiddenQueryName );
+ }
+ };
+
+ }
+}
+
+OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference< XConnection >& _rxConnection,
+ const Reference< XNameAccess >& _rxTables,
+ const OSQLParser& _rParser )
+ :m_rParser( _rParser )
+ ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection, _rxTables ) )
+{
+ setParseTree(nullptr);
+}
+
+
+OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator& _rParentIterator, const OSQLParser& _rParser, const OSQLParseNode* pRoot )
+ :m_rParser( _rParser )
+ ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator.m_pImpl->m_xConnection, _rParentIterator.m_pImpl->m_xTableContainer ) )
+{
+ m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames;
+ setParseTree( pRoot );
+}
+
+
+OSQLParseTreeIterator::~OSQLParseTreeIterator()
+{
+ dispose();
+}
+
+
+const OSQLTables& OSQLParseTreeIterator::getTables() const
+{
+ return *m_pImpl->m_pTables;
+}
+
+
+bool OSQLParseTreeIterator::isCaseSensitive() const
+{
+ return m_pImpl->m_bIsCaseSensitive;
+}
+
+
+void OSQLParseTreeIterator::dispose()
+{
+ m_aSelectColumns = nullptr;
+ m_aGroupColumns = nullptr;
+ m_aOrderColumns = nullptr;
+ m_aParameters = nullptr;
+ m_pImpl->m_xTableContainer = nullptr;
+ m_pImpl->m_xDatabaseMetaData = nullptr;
+ m_aCreateColumns = nullptr;
+ m_pImpl->m_pTables->clear();
+ m_pImpl->m_pSubTables->clear();
+}
+
+void OSQLParseTreeIterator::setParseTree(const OSQLParseNode * pNewParseTree)
+{
+ m_pImpl->m_pTables->clear();
+ m_pImpl->m_pSubTables->clear();
+
+ m_aSelectColumns = new OSQLColumns();
+ m_aGroupColumns = new OSQLColumns();
+ m_aOrderColumns = new OSQLColumns();
+ m_aParameters = new OSQLColumns();
+ m_aCreateColumns = new OSQLColumns();
+
+ m_pParseTree = pNewParseTree;
+ if (!m_pParseTree)
+ {
+ m_eStatementType = OSQLStatementType::Unknown;
+ return;
+ }
+
+ // If m_pParseTree, but no connection then return
+ if ( !m_pImpl->m_xTableContainer.is() )
+ return;
+
+ m_xErrors.reset();
+
+
+ // Determine statement type ...
+ if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) )
+ {
+ m_eStatementType = OSQLStatementType::Select;
+ }
+ else if (SQL_ISRULE(m_pParseTree,insert_statement))
+ {
+ m_eStatementType = OSQLStatementType::Insert;
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
+ {
+ m_eStatementType = OSQLStatementType::Update;
+ }
+ else if (SQL_ISRULE(m_pParseTree,delete_statement_searched))
+ {
+ m_eStatementType = OSQLStatementType::Delete;
+ }
+ else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec))
+ {
+ m_eStatementType = OSQLStatementType::OdbcCall;
+ }
+ else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def))
+ {
+ m_eStatementType = OSQLStatementType::CreateTable;
+ m_pParseTree = m_pParseTree->getChild(0);
+ }
+ else
+ {
+ m_eStatementType = OSQLStatementType::Unknown;
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+}
+
+
+namespace
+{
+
+ void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, OUString& _out_rString )
+ {
+ _out_rString = _rxRow->getString( _nColumnIndex );
+ if ( _rxRow->wasNull() )
+ _out_rString.clear();
+ }
+
+
+ OUString lcl_findTableInMetaData(
+ const Reference< XDatabaseMetaData >& _rxDBMeta, const OUString& _rCatalog,
+ const OUString& _rSchema, const OUString& _rTableName )
+ {
+ OUString sComposedName;
+
+ static constexpr OUStringLiteral s_sWildcard = u"%" ;
+
+ // we want all catalogues, all schemas, all tables
+ Sequence< OUString > sTableTypes { "VIEW", "TABLE", s_sWildcard }; // this last one just to be sure to include anything else...
+
+ if ( _rxDBMeta.is() )
+ {
+ sComposedName.clear();
+
+ Reference< XResultSet> xRes = _rxDBMeta->getTables(
+ !_rCatalog.isEmpty() ? Any( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _rSchema : s_sWildcard, _rTableName, sTableTypes );
+
+ Reference< XRow > xCurrentRow( xRes, UNO_QUERY );
+ if ( xCurrentRow.is() && xRes->next() )
+ {
+ OUString sCatalog, sSchema, sName;
+
+ impl_getRowString( xCurrentRow, 1, sCatalog );
+ impl_getRowString( xCurrentRow, 2, sSchema );
+ impl_getRowString( xCurrentRow, 3, sName );
+
+ sComposedName = ::dbtools::composeTableName(
+ _rxDBMeta,
+ sCatalog,
+ sSchema,
+ sName,
+ false,
+ ::dbtools::EComposeRule::InDataManipulation
+ );
+ }
+ }
+ return sComposedName;
+ }
+}
+
+
+void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable& _rQuery )
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
+ // parameters not to be included in the traversal
+ return;
+
+ ::rtl::Reference pSubQueryParameterColumns( new OSQLColumns() );
+
+ // get the command and the EscapeProcessing properties from the sub query
+ OUString sSubQueryCommand;
+ bool bEscapeProcessing = false;
+ try
+ {
+ Reference< XPropertySet > xQueryProperties( _rQuery, UNO_QUERY_THROW );
+ OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sSubQueryCommand );
+ OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+
+ // parse the sub query
+ do {
+
+ if ( !bEscapeProcessing || ( sSubQueryCommand.isEmpty() ) )
+ break;
+
+ OUString sError;
+ std::unique_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand ) );
+ if (!pSubQueryNode)
+ break;
+
+ OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() );
+ aSubQueryIterator.impl_traverse( TraversalParts::Parameters | TraversalParts::SelectColumns );
+ // SelectColumns might also contain parameters #i77635#
+ pSubQueryParameterColumns = aSubQueryIterator.getParameters();
+ aSubQueryIterator.dispose();
+
+ } while ( false );
+
+ // copy the parameters of the sub query to our own parameter array
+ m_aParameters->insert( m_aParameters->end(), pSubQueryParameterColumns->begin(), pSubQueryParameterColumns->end() );
+}
+
+
+OSQLTable OSQLParseTreeIterator::impl_locateRecordSource( const OUString& _rComposedName )
+{
+ if ( _rComposedName.isEmpty() )
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" );
+ return OSQLTable();
+ }
+
+ OSQLTable aReturn;
+ OUString sComposedName( _rComposedName );
+
+ try
+ {
+ OUString sCatalog, sSchema, sName;
+ qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
+
+ // check whether there is a query with the given name
+ bool bQueryDoesExist = m_pImpl->m_xQueryContainer.is() && m_pImpl->m_xQueryContainer->hasByName( sComposedName );
+
+ // check whether the table container contains an object with the given name
+ if ( !bQueryDoesExist && !m_pImpl->m_xTableContainer->hasByName( sComposedName ) )
+ sComposedName = lcl_findTableInMetaData( m_pImpl->m_xDatabaseMetaData, sCatalog, sSchema, sName );
+ bool bTableDoesExist = m_pImpl->m_xTableContainer->hasByName( sComposedName );
+
+ // now obtain the object
+
+ // if we're creating a table, and there already is a table or query with the same name,
+ // this is worth an error
+ if ( OSQLStatementType::CreateTable == m_eStatementType )
+ {
+ if ( bQueryDoesExist )
+ impl_appendError( IParseContext::ErrorCode::InvalidQueryExist, &sName );
+ else if ( bTableDoesExist )
+ impl_appendError( IParseContext::ErrorCode::InvalidTableExist, &sName );
+ else
+ aReturn = impl_createTableObject( sName, sCatalog, sSchema );
+ }
+ else
+ {
+ // queries win over tables, so if there's a query with this name, take this, no matter if
+ // there's a table, too
+ if ( bQueryDoesExist )
+ {
+ if ( !m_pImpl->isQueryAllowed( sComposedName ) )
+ {
+ impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, nullptr ) );
+ return nullptr;
+ }
+
+ m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn;
+
+ // collect the parameters from the sub query
+ ForbidQueryName aForbidName( *m_pImpl, sComposedName );
+ impl_getQueryParameterColumns( aReturn );
+ }
+ else if ( bTableDoesExist )
+ m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn;
+ else
+ {
+ if ( m_pImpl->m_xQueryContainer.is() )
+ // the connection on which we're working supports sub queries in from (else
+ // m_xQueryContainer would not have been set), so emit a better error message
+ impl_appendError( IParseContext::ErrorCode::InvalidTableOrQuery, &sName );
+ else
+ impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sName );
+ }
+ }
+ }
+ catch(Exception&)
+ {
+ impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sComposedName );
+ }
+
+ return aReturn;
+}
+
+
+void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const OUString & rTableRange )
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::TableNames ) )
+ // tables should not be included in the traversal
+ return;
+
+ OSL_ENSURE(pTableName != nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL");
+
+ Any aCatalog;
+ OUString aSchema,aTableName,aComposedName;
+ OUString aTableRange(rTableRange);
+
+ // Get table name
+ OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData);
+
+ // create the composed name like DOMAIN.USER.TABLE1
+ aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData,
+ aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : OUString(),
+ aSchema,
+ aTableName,
+ false,
+ ::dbtools::EComposeRule::InDataManipulation);
+
+ // if there is no alias for the table name assign the original name to it
+ if ( aTableRange.isEmpty() )
+ aTableRange = aComposedName;
+
+ // get the object representing this table/query
+ OSQLTable aTable = impl_locateRecordSource( aComposedName );
+ if ( aTable.is() )
+ _rTables[ aTableRange ] = aTable;
+}
+
+void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode* i_pJoinCondition)
+{
+ if (i_pJoinCondition->count() == 3 && // Expression with brackets
+ SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")"))
+ {
+ impl_fillJoinConditions(i_pJoinCondition->getChild(1));
+ }
+ else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR logic operation:
+ i_pJoinCondition->count() == 3)
+ {
+ // Only allow AND logic operation
+ if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) )
+ {
+ impl_fillJoinConditions(i_pJoinCondition->getChild(0));
+ impl_fillJoinConditions(i_pJoinCondition->getChild(1));
+ }
+ }
+ else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate))
+ {
+ // only the comparison of columns is allowed
+ OSL_ENSURE(i_pJoinCondition->count() == 3,"OQueryDesignView::InsertJoinConnection: error in the parse tree");
+ if (SQL_ISRULE(i_pJoinCondition->getChild(0),column_ref) &&
+ SQL_ISRULE(i_pJoinCondition->getChild(2),column_ref) &&
+ i_pJoinCondition->getChild(1)->getNodeType() == SQLNodeType::Equal)
+ {
+ m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) );
+ }
+ }
+}
+
+std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const
+{
+ return m_pImpl->m_aJoinConditions;
+}
+
+void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, OUString& aTableRange )
+{
+ OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) ,
+ "OSQLParseTreeIterator::getQualified_join: illegal node!" );
+
+ aTableRange.clear();
+
+ const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange);
+ if ( isTableNode( pNode ) )
+ traverseOneTableName( _rTables, pNode, aTableRange );
+
+ sal_uInt32 nPos = 4;
+ if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL)
+ {
+ nPos = 3;
+ // join_condition,named_columns_join
+ if ( SQL_ISRULE( pTableRef, qualified_join ) )
+ {
+ const OSQLParseNode* pJoin_spec = pTableRef->getChild(4);
+ if ( SQL_ISRULE( pJoin_spec, join_condition ) )
+ {
+ impl_fillJoinConditions(pJoin_spec->getChild(1));
+ }
+ else
+ {
+ const OSQLParseNode* pColumnCommalist = pJoin_spec->getChild(2);
+ // All columns in the column_commalist ...
+ for (size_t i = 0; i < pColumnCommalist->count(); i++)
+ {
+ const OSQLParseNode * pCol = pColumnCommalist->getChild(i);
+ // add twice because the column must exists in both tables
+ m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) );
+ }
+ }
+ }
+ }
+
+ pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange);
+ if ( isTableNode( pNode ) )
+ traverseOneTableName( _rTables, pNode, aTableRange );
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,OUString& rTableRange )
+{
+ OSL_PRECOND( SQL_ISRULE( pTableRef, table_ref ) || SQL_ISRULE( pTableRef, joined_table )
+ || SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ),
+ "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" );
+
+ const OSQLParseNode* pTableNameNode = nullptr;
+
+ if ( SQL_ISRULE( pTableRef, joined_table ) )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
+ }
+ if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) )
+ {
+ getQualified_join( _rTables, pTableRef, rTableRange );
+ }
+ else
+ {
+ rTableRange = OSQLParseNode::getTableRange(pTableRef);
+ if ( ( pTableRef->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}'
+ || ( pTableRef->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist
+ )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange );
+ }
+ else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')'
+ {
+ const OSQLParseNode* pSubQuery = pTableRef->getChild(0);
+ if ( pSubQuery->isToken() )
+ {
+ getQualified_join( _rTables, pTableRef->getChild(1), rTableRange );
+ }
+ else
+ {
+ OSL_ENSURE( pSubQuery->count() == 3, "sub queries should have 3 children!" );
+ const OSQLParseNode* pQueryExpression = pSubQuery->getChild(1);
+ if ( SQL_ISRULE( pQueryExpression, select_statement ) )
+ {
+ getSelect_statement( *m_pImpl->m_pSubTables, pQueryExpression );
+ // TODO: now, we need to setup an OSQLTable from pQueryExpression in some way
+ // and stick it in _rTables[rTableRange]. Probably fake it by
+ // setting up a full OSQLParseTreeIterator on pQueryExpression
+ // and using its m_aSelectColumns
+ // This is necessary in stuff like "SELECT * FROM tbl1 INNER JOIN (SELECT foo, bar FROM tbl2) AS tbl3"
+ // so that setSelectColumnName() can expand the "*" correctly.
+ // See e.g. R_UserAndLastSubscription query of https://bugs.libreoffice.org/attachment.cgi?id=71871
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" );
+ }
+ }
+ }
+ else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column
+ {
+ pTableNameNode = pTableRef->getChild(0);
+ }
+ else
+ SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" );
+ }
+
+ return pTableNameNode;
+}
+
+void OSQLParseTreeIterator::getSelect_statement(OSQLTables& _rTables,const OSQLParseNode* pSelect)
+{
+ if(SQL_ISRULE(pSelect,union_statement))
+ {
+ getSelect_statement(_rTables,pSelect->getChild(0));
+ //getSelect_statement(pSelect->getChild(3));
+ return;
+ }
+ OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1);
+
+ OSL_ENSURE(pTableRefCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!");
+
+ const OSQLParseNode* pTableName = nullptr;
+ OUString aTableRange;
+ for (size_t i = 0; i < pTableRefCommalist->count(); i++)
+ { // Process FROM clause
+ aTableRange.clear();
+
+ const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i);
+ if ( isTableNode( pTableListElement ) )
+ {
+ traverseOneTableName( _rTables, pTableListElement, aTableRange );
+ }
+ else if ( SQL_ISRULE( pTableListElement, table_ref ) )
+ {
+ // Table references can be made up of table names, table names (+),'('joined_table')'(+)
+ pTableName = pTableListElement->getChild(0);
+ if( isTableNode( pTableName ) )
+ { // Found table names
+ aTableRange = OSQLParseNode::getTableRange(pTableListElement);
+ traverseOneTableName( _rTables, pTableName, aTableRange );
+ }
+ else if(SQL_ISPUNCTUATION(pTableName,"{"))
+ { // '{' SQL_TOKEN_OJ joined_table '}'
+ getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange );
+ }
+ else
+ { // '(' joined_table ')' range_variable op_column_commalist
+ getTableNode( _rTables, pTableListElement, aTableRange );
+ }
+ }
+ else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) )
+ {
+ getQualified_join( _rTables, pTableListElement, aTableRange );
+ }
+ else if ( SQL_ISRULE( pTableListElement, joined_table ) )
+ {
+ getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange );
+ }
+
+ // if (! aIteratorStatus.IsSuccessful()) break;
+ }
+}
+
+bool OSQLParseTreeIterator::traverseTableNames(OSQLTables& _rTables)
+{
+ if ( m_pParseTree == nullptr )
+ return false;
+
+ OSQLParseNode* pTableName = nullptr;
+
+ switch ( m_eStatementType )
+ {
+ case OSQLStatementType::Select:
+ getSelect_statement( _rTables, m_pParseTree );
+ break;
+
+ case OSQLStatementType::CreateTable:
+ case OSQLStatementType::Insert:
+ case OSQLStatementType::Delete:
+ pTableName = m_pParseTree->getChild(2);
+ break;
+
+ case OSQLStatementType::Update:
+ pTableName = m_pParseTree->getChild(1);
+ break;
+ default:
+ break;
+ }
+
+ if ( pTableName )
+ {
+ traverseOneTableName( _rTables, pTableName, OUString() );
+ }
+
+ return !hasErrors();
+}
+
+OUString OSQLParseTreeIterator::getColumnAlias(const OSQLParseNode* _pDerivedColumn)
+{
+ OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!");
+ OUString sColumnAlias;
+ if(_pDerivedColumn->getChild(1)->count() == 2)
+ sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue();
+ else if(!_pDerivedColumn->getChild(1)->isRule())
+ sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue();
+ return sColumnAlias;
+}
+
+
+namespace
+{
+ void lcl_getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection,
+ OUString& _out_rColumnName, OUString& _out_rTableRange,
+ const OSQLColumns* _pSelectColumns, OUString& _out_rColumnAliasIfPresent )
+ {
+ _out_rColumnName.clear();
+ _out_rTableRange.clear();
+ _out_rColumnAliasIfPresent.clear();
+ if ( SQL_ISRULE( _pColumnRef, column_ref ) )
+ {
+ if( _pColumnRef->count() > 1 )
+ {
+ for ( sal_Int32 i=0; i<static_cast<sal_Int32>(_pColumnRef->count())-2; ++i )
+ _pColumnRef->getChild(i)->parseNodeToStr( _out_rTableRange, _rxConnection, nullptr, false, false );
+ _out_rColumnName = _pColumnRef->getChild( _pColumnRef->count()-1 )->getChild(0)->getTokenValue();
+ }
+ else
+ _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue();
+
+ // look up the column in the select column, to find a possible alias
+ if ( _pSelectColumns )
+ {
+ for (const Reference< XPropertySet >& xColumn : *_pSelectColumns)
+ {
+ try
+ {
+ OUString sName, sTableName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) >>= sName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName;
+ if ( sName == _out_rColumnName && ( _out_rTableRange.isEmpty() || sTableName == _out_rTableRange ) )
+ {
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent;
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ }
+ }
+ }
+ else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec))
+ { // Function
+ _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection );
+ }
+ else if(_pColumnRef->getNodeType() == SQLNodeType::Name)
+ _out_rColumnName = _pColumnRef->getTokenValue();
+ }
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ OUString& _rColumnName,
+ OUString& _rTableRange) const
+{
+ OUString sDummy;
+ lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, nullptr, sDummy );
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ OUString& _rColumnName,
+ OUString& _rTableRange,
+ OUString& _out_rColumnAliasIfPresent ) const
+{
+ lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent );
+}
+
+
+void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef,
+ const Reference< XConnection >& _rxConnection, OUString& _out_rColumnName, OUString& _out_rTableRange )
+{
+ OUString sDummy;
+ lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, nullptr, sDummy );
+}
+
+
+void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode* pSelectNode)
+{
+ // aIteratorStatus.Clear();
+
+ if (!pSelectNode || m_eStatementType != OSQLStatementType::CreateTable || m_pImpl->m_pTables->empty())
+ {
+ impl_appendError( IParseContext::ErrorCode::General );
+ return;
+ }
+ if (!SQL_ISRULE(pSelectNode,base_table_element_commalist))
+ return ;
+
+ for (size_t i = 0; i < pSelectNode->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelectNode->getChild(i);
+
+ if (SQL_ISRULE(pColumnRef,column_def))
+ {
+ OUString aColumnName;
+ OUString aTypeName;
+ sal_Int32 nType = DataType::VARCHAR;
+ aColumnName = pColumnRef->getChild(0)->getTokenValue();
+
+ OSQLParseNode *pDatatype = pColumnRef->getChild(1);
+ if (pDatatype && SQL_ISRULE(pDatatype,character_string_type))
+ {
+ const OSQLParseNode *pType = pDatatype->getChild(0);
+ aTypeName = pType->getTokenValue();
+ if (pDatatype->count() == 2 && (pType->getTokenID() == SQL_TOKEN_CHAR || pType->getTokenID() == SQL_TOKEN_CHARACTER ))
+ nType = DataType::CHAR;
+ }
+ else if(pDatatype && pDatatype->getNodeType() == SQLNodeType::Keyword)
+ {
+ aTypeName = "VARCHAR";
+ }
+
+ if (!aTypeName.isEmpty())
+ {
+ //TODO:Create a new class for create statement to handle field length
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aColumnName,aTypeName,OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(false);
+ pColumn->setRealName(aColumnName);
+
+ m_aCreateColumns->push_back(pColumn);
+ }
+ }
+
+ }
+}
+
+bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode* pSelectNode)
+{
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::SelectColumns ) )
+ return true;
+
+ if (!pSelectNode || m_eStatementType != OSQLStatementType::Select || m_pImpl->m_pTables->empty())
+ {
+ impl_appendError( IParseContext::ErrorCode::General );
+ return false;
+ }
+
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ return traverseSelectColumnNames( pSelectNode->getChild( 0 ) )
+ /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/;
+ }
+
+ // nyi: more checks for correct structure!
+ if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*"))
+ {
+ // SELECT * ...
+ setSelectColumnName("*", "", "");
+ }
+ else if (SQL_ISRULE(pSelectNode->getChild(2),scalar_exp_commalist))
+ {
+ // SELECT column[,column] or SELECT COUNT(*) ...
+ OSQLParseNode * pSelection = pSelectNode->getChild(2);
+
+ for (size_t i = 0; i < pSelection->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelection->getChild(i);
+
+ //if (SQL_ISRULE(pColumnRef,select_sublist))
+ if (SQL_ISRULE(pColumnRef,derived_column) &&
+ SQL_ISRULE(pColumnRef->getChild(0),column_ref) &&
+ pColumnRef->getChild(0)->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0)->getChild(2),"*"))
+ {
+ // All the table's columns
+ OUString aTableRange;
+ pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, nullptr, false, false );
+ setSelectColumnName("*", "", aTableRange);
+ continue;
+ }
+ else if (SQL_ISRULE(pColumnRef,derived_column))
+ {
+ OUString aColumnAlias(getColumnAlias(pColumnRef)); // can be empty
+ OUString sColumnName;
+ OUString aTableRange;
+ sal_Int32 nType = DataType::VARCHAR;
+ bool bFkt(false);
+ pColumnRef = pColumnRef->getChild(0);
+ while (
+ pColumnRef->getKnownRuleID() != OSQLParseNode::subquery &&
+ pColumnRef->count() == 3 &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pColumnRef->getChild(2),")")
+ )
+ pColumnRef = pColumnRef->getChild(1);
+
+ if (SQL_ISRULE(pColumnRef,column_ref))
+ {
+ getColumnRange(pColumnRef,sColumnName,aTableRange);
+ OSL_ENSURE(!sColumnName.isEmpty(),"Column name must not be empty!");
+ }
+ else /*if (SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec) ||
+ SQL_ISRULE(pColumnRef,position_exp) || SQL_ISRULE(pColumnRef,extract_exp) ||
+ SQL_ISRULE(pColumnRef,length_exp) || SQL_ISRULE(pColumnRef,char_value_fct)||
+ SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term))*/
+ {
+ // Function call present
+ pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection );
+ // check if the column is also a parameter
+ traverseSearchCondition(pColumnRef); // num_value_exp
+
+ if ( pColumnRef->isRule() )
+ {
+ // FIXME: the if condition is not quite right
+ // many expressions are rules, e.g. "5+3"
+ // or even: "colName + 1"
+ bFkt = true;
+ nType = getFunctionReturnType(pColumnRef);
+ }
+ }
+ /*
+ else
+ {
+ aIteratorStatus.setStatementTooComplex();
+ return;
+ }
+ */
+ if(aColumnAlias.isEmpty())
+ aColumnAlias = sColumnName;
+ setSelectColumnName(sColumnName,aColumnAlias,aTableRange,bFkt,nType,SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec));
+ }
+ }
+ }
+
+ return !hasErrors();
+}
+
+
+bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode* pSelectNode)
+{
+ traverseByColumnNames( pSelectNode, true );
+ return !hasErrors();
+}
+
+void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode* pSelectNode, bool _bOrder)
+{
+ // aIteratorStatus.Clear();
+
+ if (pSelectNode == nullptr)
+ {
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+
+ if (m_eStatementType != OSQLStatementType::Select)
+ {
+ //aIteratorStatus.setInvalidStatement();
+ return;
+ }
+
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ traverseByColumnNames(pSelectNode->getChild(0),_bOrder);
+ return;
+ }
+
+ OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pTableExp = pSelectNode->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator:table_exp error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ sal_uInt32 nPos = ( _bOrder ? ORDER_BY_CHILD_POS : 2 );
+
+ OSQLParseNode * pOptByClause = pTableExp->getChild(nPos);
+ OSL_ENSURE(pOptByClause != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ if ( pOptByClause->count() == 0 )
+ return;
+
+ OSL_ENSURE(pOptByClause->count() == 3,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pOrderingSpecCommalist = pOptByClause->getChild(2);
+ OSL_ENSURE(pOrderingSpecCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(!_bOrder || SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OSQLParseTreeIterator:ordering_spec_commalist error in parse tree!");
+ OSL_ENSURE(pOrderingSpecCommalist->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
+
+ OUString sColumnName;
+ OUString aTableRange;
+ sal_uInt32 nCount = pOrderingSpecCommalist->count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ OSQLParseNode* pColumnRef = pOrderingSpecCommalist->getChild(i);
+ OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ if ( _bOrder )
+ {
+ OSL_ENSURE(SQL_ISRULE(pColumnRef,ordering_spec),"OSQLParseTreeIterator:ordering_spec error in parse tree!");
+ OSL_ENSURE(pColumnRef->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+
+ pColumnRef = pColumnRef->getChild(0);
+ }
+ OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ aTableRange.clear();
+ sColumnName.clear();
+ if ( SQL_ISRULE(pColumnRef,column_ref) )
+ {
+ // Column name (and TableRange):
+ getColumnRange(pColumnRef,sColumnName,aTableRange);
+ }
+ else
+ { // here I found a predicate
+ pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ }
+ OSL_ENSURE(!sColumnName.isEmpty(),"sColumnName must not be empty!");
+ if ( _bOrder )
+ {
+ // Ascending/Descending
+ OSQLParseNode * pOptAscDesc = pColumnRef->getParent()->getChild(1);
+ OSL_ENSURE(pOptAscDesc != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+ bool bAscending = ! (pOptAscDesc && SQL_ISTOKEN(pOptAscDesc,DESC));
+ setOrderByColumnName(sColumnName, aTableRange,bAscending);
+ }
+ else
+ setGroupByColumnName(sColumnName, aTableRange);
+ }
+}
+
+bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode* pSelectNode)
+{
+ traverseByColumnNames( pSelectNode, false );
+ return !hasErrors();
+}
+
+
+namespace
+{
+ OUString lcl_generateParameterName( const OSQLParseNode& _rParentNode, const OSQLParseNode& _rParamNode )
+ {
+ OUString sColumnName( "param" );
+ const sal_Int32 nCount = static_cast<sal_Int32>(_rParentNode.count());
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ if ( _rParentNode.getChild(i) == &_rParamNode )
+ {
+ sColumnName += OUString::number( i+1 );
+ break;
+ }
+ }
+ return sColumnName;
+ }
+}
+
+
+void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode* _pNode)
+{
+ if ( _pNode == nullptr )
+ return;
+
+ OUString sColumnName, sTableRange, aColumnAlias;
+ const OSQLParseNode* pParent = _pNode->getParent();
+ if ( pParent != nullptr )
+ {
+ if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
+ {
+ sal_uInt32 nPos = 0;
+ if ( pParent->getChild(nPos) == _pNode )
+ nPos = 2;
+ const OSQLParseNode* pOther = pParent->getChild(nPos);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ } // if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X
+ else if ( SQL_ISRULE(pParent,other_like_predicate_part_2) )
+ {
+ const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ }
+ else if ( SQL_ISRULE(pParent,between_predicate_part_2) )
+ {
+ const OSQLParseNode* pOther = pParent->getParent()->getChild(0);
+ if ( SQL_ISRULE( pOther, column_ref ) )
+ getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias);
+ else
+ {
+ pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false );
+ lcl_generateParameterName( *pParent, *_pNode );
+ }
+ }
+ else if ( pParent->getNodeType() == SQLNodeType::CommaListRule )
+ {
+ lcl_generateParameterName( *pParent, *_pNode );
+ }
+ }
+ traverseParameter( _pNode, pParent, sColumnName, sTableRange, aColumnAlias );
+ const sal_uInt32 nCount = _pNode->count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ const OSQLParseNode* pChild = _pNode->getChild(i);
+ traverseParameters( pChild );
+ }
+}
+
+bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode* pSelectNode)
+{
+ if ( pSelectNode == nullptr )
+ return false;
+
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to WHERE clause:
+ OSQLParseNode * pWhereClause = nullptr;
+
+ if (m_eStatementType == OSQLStatementType::Select)
+ {
+ if(SQL_ISRULE(pSelectNode,union_statement))
+ {
+ return traverseSelectionCriteria( pSelectNode->getChild( 0 ) )
+ && traverseSelectionCriteria( pSelectNode->getChild( 3 ) );
+ }
+ OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pTableExp = pSelectNode->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pWhereClause = pTableExp->getChild(1);
+ } else if (SQL_ISRULE(pSelectNode,update_statement_searched)) {
+ OSL_ENSURE(pSelectNode->count() == 5,"OSQLParseTreeIterator: error in parse tree!");
+ pWhereClause = pSelectNode->getChild(4);
+ } else if (SQL_ISRULE(pSelectNode,delete_statement_searched)) {
+ OSL_ENSURE(pSelectNode->count() == 4,"OSQLParseTreeIterator: error in parse tree!");
+ pWhereClause = pSelectNode->getChild(3);
+ } else if (SQL_ISRULE(pSelectNode,delete_statement_positioned)) {
+ // nyi
+ SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi");
+ } else {
+ // Other statement, no selection criteria
+ return false;
+ }
+
+ if (!pWhereClause || !SQL_ISRULE(pWhereClause,where_clause))
+ {
+ // The WHERE clause is optional most of the time; which means it could be a "optional_where_clause".
+ OSL_ENSURE(pWhereClause && SQL_ISRULE(pWhereClause,opt_where_clause),"OSQLParseTreeIterator: error in parse tree!");
+ return false;
+ }
+
+ // But if it's a where_clause, then it must not be empty
+ OSL_ENSURE(pWhereClause->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+
+ OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
+ OSL_ENSURE(pComparisonPredicate != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+
+ // Process the comparison criteria now
+
+
+ traverseSearchCondition(pComparisonPredicate);
+
+ return !hasErrors();
+}
+
+
+void OSQLParseTreeIterator::traverseSearchCondition(OSQLParseNode const * pSearchCondition)
+{
+ if (
+ SQL_ISRULE(pSearchCondition,boolean_primary) &&
+ pSearchCondition->count() == 3 &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")")
+ )
+ {
+ // Round brackets
+ traverseSearchCondition(pSearchCondition->getChild(1));
+ }
+ // The first element is an OR logical operation
+ else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 )
+ {
+ // if this assert fails, the SQL grammar has changed!
+ assert(SQL_ISTOKEN(pSearchCondition->getChild(1),OR));
+ // Then process recursively (use the same row) ...
+ traverseSearchCondition(pSearchCondition->getChild(0));
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+
+ // Continue with the right child
+ traverseSearchCondition(pSearchCondition->getChild(2));
+ }
+ // The first element is an AND logical operation (again)
+ else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 )
+ {
+ // Then process recursively (use the same row)
+ traverseSearchCondition(pSearchCondition->getChild(0));
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+
+ // Continue with the right child
+ traverseSearchCondition(pSearchCondition->getChild(2));
+ }
+ // Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.)
+ else if (SQL_ISRULE(pSearchCondition,comparison_predicate) )
+ {
+ OUString aValue;
+ pSearchCondition->getChild(2)->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
+ traverseOnePredicate(pSearchCondition->getChild(0),aValue,pSearchCondition->getChild(2));
+ impl_fillJoinConditions(pSearchCondition);
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,like_predicate) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+
+ sal_Int32 nCurentPos = pPart2->count()-2;
+
+ OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurentPos);
+ OSQLParseNode * pOptEscape = pPart2->getChild(nCurentPos+1);
+
+ OSL_ENSURE(pNum_value_exp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pOptEscape != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+
+ if (pOptEscape->count() != 0)
+ {
+ // aIteratorStatus.setStatementTooComplex();
+ return;
+ }
+
+ OUString aValue;
+ OSQLParseNode * pParam = nullptr;
+ if (SQL_ISRULE(pNum_value_exp,parameter))
+ pParam = pNum_value_exp;
+ else if(pNum_value_exp->isToken())
+ // Normal value
+ aValue = pNum_value_exp->getTokenValue();
+ else
+ {
+ pNum_value_exp->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false );
+ pParam = pNum_value_exp;
+ }
+
+ traverseOnePredicate(pSearchCondition->getChild(0),aValue,pParam);
+// if (! aIteratorStatus.IsSuccessful())
+// return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,in_predicate))
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+
+ traverseSearchCondition(pSearchCondition->getChild(0));
+ // if (! aIteratorStatus.IsSuccessful()) return;
+
+ OSQLParseNode* pChild = pPart2->getChild(2);
+ if ( SQL_ISRULE(pChild->getChild(0),subquery) )
+ {
+ traverseTableNames( *m_pImpl->m_pSubTables );
+ traverseSelectionCriteria(pChild->getChild(0)->getChild(1));
+ }
+ else
+ { // '(' value_exp_commalist ')'
+ pChild = pChild->getChild(1);
+ sal_Int32 nCount = pChild->count();
+ for (sal_Int32 i=0; i < nCount; ++i)
+ {
+ traverseSearchCondition(pChild->getChild(i));
+ }
+ }
+ }
+ else if (SQL_ISRULE(pSearchCondition,test_for_null) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/)
+ {
+ OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!");
+ const OSQLParseNode* pPart2 = pSearchCondition->getChild(1);
+ OSL_ENSURE(SQL_ISTOKEN(pPart2->getChild(0),IS),"OSQLParseTreeIterator: error in parse tree!");
+
+ OUString aString;
+ traverseOnePredicate(pSearchCondition->getChild(0),aString,nullptr);
+ // if (! aIteratorStatus.IsSuccessful()) return;
+ }
+ else if (SQL_ISRULE(pSearchCondition,num_value_exp) || SQL_ISRULE(pSearchCondition,term))
+ {
+ OUString aString;
+ traverseOnePredicate(pSearchCondition->getChild(0),aString,pSearchCondition->getChild(0));
+ traverseOnePredicate(pSearchCondition->getChild(2),aString,pSearchCondition->getChild(2));
+ }
+ // Just pass on the error
+}
+
+void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode* _pParseNode
+ ,const OSQLParseNode* _pParentNode
+ ,const OUString& _aColumnName
+ ,OUString& _aTableRange
+ ,const OUString& _rColumnAlias)
+{
+ if ( !SQL_ISRULE( _pParseNode, parameter ) )
+ return;
+
+ if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) )
+ // parameters not to be included in the traversal
+ return;
+
+ OSL_ENSURE(_pParseNode->count() > 0,"OSQLParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pMark = _pParseNode->getChild(0);
+ OUString sParameterName;
+
+ if (SQL_ISPUNCTUATION(pMark,"?"))
+ {
+ sParameterName = !_rColumnAlias.isEmpty()
+ ? _rColumnAlias
+ : !_aColumnName.isEmpty()
+ ? _aColumnName
+ : OUString("?");
+ }
+ else if (SQL_ISPUNCTUATION(pMark,":"))
+ {
+ sParameterName = _pParseNode->getChild(1)->getTokenValue();
+ }
+ else if (SQL_ISPUNCTUATION(pMark,"["))
+ {
+ sParameterName = _pParseNode->getChild(1)->getTokenValue();
+ }
+ else
+ {
+ SAL_WARN( "connectivity.parse","OSQLParseTreeIterator: error in parse tree!");
+ }
+
+ // found a parameter
+ if ( _pParentNode && (SQL_ISRULE(_pParentNode,general_set_fct) || SQL_ISRULE(_pParentNode,set_fct_spec)) )
+ {// found a function as column_ref
+ OUString sFunctionName;
+ _pParentNode->getChild(0)->parseNodeToStr( sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+ const sal_uInt32 nCount = _pParentNode->count();
+ sal_uInt32 i = 0;
+ for(; i < nCount;++i)
+ {
+ if ( _pParentNode->getChild(i) == _pParseNode )
+ break;
+ }
+ sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode->getChild(0)->getTokenID(), i-1);
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn( sParameterName,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(true);
+ pColumn->setRealName(sFunctionName);
+ m_aParameters->push_back(pColumn);
+ }
+ else
+ {
+ bool bNotFound = true;
+ OSQLColumns::const_iterator aIter = ::connectivity::find(
+ m_aSelectColumns->begin(),
+ m_aSelectColumns->end(),
+ _aColumnName,::comphelper::UStringMixEqual( isCaseSensitive() )
+ );
+ if(aIter != m_aSelectColumns->end())
+ {
+ rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(*aIter,isCaseSensitive());
+ pNewColumn->setName(sParameterName);
+ pNewColumn->setRealName(_aColumnName);
+ m_aParameters->push_back(pNewColumn);
+ bNotFound = false;
+ }
+ else if(!_aColumnName.isEmpty())// search in the tables for the right one
+ {
+
+ Reference<XPropertySet> xColumn = findColumn( _aColumnName, _aTableRange, true );
+
+ if ( xColumn.is() )
+ {
+ rtl::Reference<OParseColumn> pNewColumn = new OParseColumn(xColumn,isCaseSensitive());
+ pNewColumn->setName(sParameterName);
+ pNewColumn->setRealName(_aColumnName);
+ m_aParameters->push_back(pNewColumn);
+ bNotFound = false;
+ }
+ }
+ if ( bNotFound )
+ {
+ sal_Int32 nType = DataType::VARCHAR;
+ OSQLParseNode* pParent = _pParentNode ? _pParentNode->getParent() : nullptr;
+ if ( pParent && (SQL_ISRULE(pParent,general_set_fct) || SQL_ISRULE(pParent,set_fct_spec)) )
+ {
+ const sal_uInt32 nCount = _pParentNode->count();
+ sal_uInt32 i = 0;
+ for(; i < nCount;++i)
+ {
+ if ( _pParentNode->getChild(i) == _pParseNode )
+ break;
+ }
+ nType = ::connectivity::OSQLParser::getFunctionParameterType( pParent->getChild(0)->getTokenID(), i+1);
+ }
+
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), sParameterName));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,
+ OUString(),
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString());
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(sParameterName);
+ m_aParameters->push_back(pColumn);
+ }
+ }
+}
+
+void OSQLParseTreeIterator::traverseOnePredicate(
+ OSQLParseNode const * pColumnRef,
+ OUString& rValue,
+ OSQLParseNode const * pParseNode)
+{
+ if ( !pParseNode )
+ return;
+
+ // Column name (and TableRange):
+ OUString aColumnName, aTableRange, sColumnAlias;
+ getColumnRange( pColumnRef, aColumnName, aTableRange, sColumnAlias);
+
+ OUString aName;
+
+ /*if (SQL_ISRULE(pParseNode,parameter))
+ traverseParameter( pParseNode, pColumnRef, aColumnName, aTableRange, sColumnAlias );
+ else */if (SQL_ISRULE(pParseNode,column_ref))// Column-Name (and TableRange):
+ getColumnRange(pParseNode,aName,rValue);
+ else
+ {
+ traverseSearchCondition(pParseNode);
+ // if (! aIteratorStatus.IsSuccessful()) return;
+ }
+}
+
+
+void OSQLParseTreeIterator::traverseAll()
+{
+ impl_traverse( TraversalParts::All );
+}
+
+
+void OSQLParseTreeIterator::impl_traverse( TraversalParts _nIncludeMask )
+{
+ // resets our errors
+ m_xErrors.reset();
+
+ m_pImpl->m_nIncludeMask = _nIncludeMask;
+
+ if ( !traverseTableNames( *m_pImpl->m_pTables ) )
+ return;
+
+ switch ( m_eStatementType )
+ {
+ case OSQLStatementType::Select:
+ {
+ const OSQLParseNode* pSelectNode = m_pParseTree;
+ traverseParameters( pSelectNode );
+ if ( !traverseSelectColumnNames( pSelectNode )
+ || !traverseOrderByColumnNames( pSelectNode )
+ || !traverseGroupByColumnNames( pSelectNode )
+ || !traverseSelectionCriteria( pSelectNode )
+ )
+ return;
+ }
+ break;
+ case OSQLStatementType::CreateTable:
+ {
+ //0 | 1 | 2 |3| 4 |5
+ //create table sc.foo ( a char(20), b char )
+ const OSQLParseNode* pCreateNode = m_pParseTree->getChild(4);
+ traverseCreateColumns(pCreateNode);
+ }
+ break;
+ case OSQLStatementType::Insert:
+ break;
+ default:
+ break;
+ }
+}
+
+// Dummy implementations
+
+
+OSQLTable OSQLParseTreeIterator::impl_createTableObject( const OUString& rTableName,
+ const OUString& rCatalogName, const OUString& rSchemaName )
+{
+ OSL_PRECOND( m_eStatementType == OSQLStatementType::CreateTable,
+ "OSQLParseTreeIterator::impl_createTableObject: only to be called for CREATE TABLE statements!" );
+ // (in all other cases, m_pTables is to contain the table objects as obtained from the tables
+ // container of the connection (m_xTablesContainer)
+
+ OSQLTable aReturnTable = new OTable(
+ nullptr,
+ false,
+ rTableName,
+ "Table",
+ "New Created Table",
+ rSchemaName,
+ rCatalogName
+ );
+ return aReturnTable;
+}
+
+void OSQLParseTreeIterator::appendColumns(const OUString& _rTableAlias, const OSQLTable& _rTable)
+{
+ if (!_rTable.is())
+ return;
+
+ Reference<XNameAccess> xColumns = _rTable->getColumns();
+ if ( !xColumns.is() )
+ return;
+
+ Sequence< OUString > aColNames = xColumns->getElementNames();
+ const OUString* pBegin = aColNames.getConstArray();
+ const OUString* pEnd = pBegin + aColNames.getLength();
+
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+ std::vector<OUString> aSelectColumnNames = getSelectColumnNames();
+
+ for(;pBegin != pEnd;++pBegin)
+ {
+ OUString aName(getUniqueColumnName(aSelectColumnNames, *pBegin));
+ Reference< XPropertySet > xColumn;
+ if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is())
+ {
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aName
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))
+ , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))
+ , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)))
+ , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))
+ , isCaseSensitive()
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME)))
+ , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))));
+
+ pColumn->setTableName(_rTableAlias);
+ pColumn->setRealName(*pBegin);
+ m_aSelectColumns->push_back(pColumn);
+ // update aSelectColumnNames with newly insert aName
+ aSelectColumnNames.insert(std::upper_bound(aSelectColumnNames.begin(), aSelectColumnNames.end(), aName, aCompare), aName);
+ }
+ else
+ impl_appendError( IParseContext::ErrorCode::InvalidColumn, pBegin, &_rTableAlias );
+ }
+}
+
+void OSQLParseTreeIterator::setSelectColumnName(const OUString & rColumnName,const OUString & rColumnAlias, const OUString & rTableRange, bool bFkt, sal_Int32 _nType, bool bAggFkt)
+{
+ if(rColumnName.toChar() == '*' && rTableRange.isEmpty())
+ { // SELECT * ...
+ for (auto const& table : *m_pImpl->m_pTables)
+ appendColumns(table.first, table.second);
+ }
+ else if( rColumnName.toChar() == '*' && !rTableRange.isEmpty() )
+ { // SELECT <table>.*
+ OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
+
+ if(aFind != m_pImpl->m_pTables->end())
+ appendColumns(rTableRange, aFind->second);
+ }
+ else if ( rTableRange.isEmpty() )
+ { // SELECT <something> ...
+ // without table specified
+ if ( !bFkt )
+ {
+ Reference< XPropertySet> xNewColumn;
+
+ for (auto const& table : *m_pImpl->m_pTables)
+ {
+ if ( !table.second.is() )
+ continue;
+
+ Reference<XNameAccess> xColumns = table.second->getColumns();
+ Reference< XPropertySet > xColumn;
+ if ( !xColumns->hasByName( rColumnName )
+ || !( xColumns->getByName( rColumnName ) >>= xColumn )
+ )
+ continue;
+
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
+ xNewColumn = pColumn;
+ pColumn->setTableName(table.first);
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(rColumnName);
+
+ break;
+ }
+
+ if ( !xNewColumn.is() )
+ {
+ // no function (due to the above !bFkt), no existing column
+ // => assume an expression
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+ // did not find a column with this name in any of the tables
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(
+ aNewColName,
+ "VARCHAR",
+ // TODO: does this match with _nType?
+ // Or should be fill this from the getTypeInfo of the connection?
+ OUString(),
+ OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,
+ 0,
+ 0,
+ _nType,
+ false,
+ false,
+ isCaseSensitive(),
+ OUString(),
+ OUString(),
+ OUString()
+ );
+
+ xNewColumn = pColumn;
+ pColumn->setRealName( rColumnName );
+ }
+
+ m_aSelectColumns->push_back( xNewColumn );
+ }
+ else
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+ pColumn->setRealName(rColumnName);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ }
+ else // ColumnName and TableName exist
+ {
+ OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange);
+
+ bool bError = false;
+ if (aFind != m_pImpl->m_pTables->end() && aFind->second.is())
+ {
+ if (bFkt)
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+ pColumn->setRealName(rColumnName);
+ SAL_WARN("connectivity.parse", "Trying to construct a column with Function==true and a TableName; this makes no sense.");
+ assert(false);
+ pColumn->setTableName(aFind->first);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ else
+ {
+ Reference< XPropertySet > xColumn;
+ if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn))
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(xColumn,isCaseSensitive());
+ pColumn->setName(aNewColName);
+ pColumn->setRealName(rColumnName);
+ pColumn->setTableName(aFind->first);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ else
+ bError = true;
+ }
+ }
+ else
+ bError = true;
+
+ // Table does not exist or lacking field
+ if (bError)
+ {
+ OUString aNewColName(getUniqueColumnName(getSelectColumnNames(), rColumnAlias));
+
+ rtl::Reference<OParseColumn> pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(),
+ ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,false,false,isCaseSensitive(),
+ OUString(),OUString(),OUString());
+ pColumn->setFunction(true);
+ pColumn->setAggregateFunction(bAggFkt);
+
+ m_aSelectColumns->push_back(pColumn);
+ }
+ }
+}
+
+std::vector<OUString> OSQLParseTreeIterator::getSelectColumnNames() const
+{
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+
+ std::vector<OUString> aColumnNames;
+ OUString sPropertyName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ for (const auto& col : *m_aSelectColumns)
+ aColumnNames.push_back(getString(col->getPropertyValue(sPropertyName)));
+ std::sort(aColumnNames.begin(), aColumnNames.end(), aCompare);
+
+ return aColumnNames;
+}
+
+OUString OSQLParseTreeIterator::getUniqueColumnName(const std::vector<OUString>& rColumnNames, const OUString& rColumnName) const
+{
+ ::comphelper::UStringMixLess aCompare(isCaseSensitive());
+ if (!std::binary_search(rColumnNames.begin(), rColumnNames.end(), rColumnName, aCompare))
+ return rColumnName;
+
+ OUString aAlias;
+ sal_Int32 i=1;
+ do
+ {
+ aAlias = rColumnName + OUString::number(i++);
+ }
+ while (std::binary_search(rColumnNames.begin(), rColumnNames.end(), aAlias, aCompare));
+ return aAlias;
+}
+
+void OSQLParseTreeIterator::setOrderByColumnName(const OUString & rColumnName, OUString & rTableRange, bool bAscending)
+{
+ Reference<XPropertySet> xColumn = findSelectColumn( rColumnName );
+ if ( !xColumn.is() )
+ xColumn = findColumn ( rColumnName, rTableRange, false );
+ if ( xColumn.is() )
+ m_aOrderColumns->push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) );
+ else
+ {
+ sal_Int32 nId = rColumnName.toInt32();
+ if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
+ m_aOrderColumns->push_back( new OOrderColumn( (*m_aSelectColumns)[nId-1], isCaseSensitive(), bAscending ) );
+ }
+
+#ifdef SQL_TEST_PARSETREEITERATOR
+ cout << "OSQLParseTreeIterator::setOrderByColumnName: "
+ << (const char *) rColumnName << ", "
+ << (const char *) rTableRange << ", "
+ << (bAscending ? "true" : "false")
+ << "\n";
+#endif
+}
+
+void OSQLParseTreeIterator::setGroupByColumnName(const OUString & rColumnName, OUString & rTableRange)
+{
+ Reference<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false );
+ if ( xColumn.is() )
+ m_aGroupColumns->push_back(new OParseColumn(xColumn,isCaseSensitive()));
+ else
+ {
+ sal_Int32 nId = rColumnName.toInt32();
+ if ( nId > 0 && o3tl::make_unsigned(nId) < m_aSelectColumns->size() )
+ m_aGroupColumns->push_back(new OParseColumn((*m_aSelectColumns)[nId-1],isCaseSensitive()));
+ }
+
+#ifdef SQL_TEST_PARSETREEITERATOR
+ cout << "OSQLParseTreeIterator::setGroupByColumnName: "
+ << (const char *) rColumnName << ", "
+ << (const char *) rTableRange << ", "
+ << (bAscending ? "true" : "false")
+ << "\n";
+#endif
+}
+
+
+const OSQLParseNode* OSQLParseTreeIterator::getWhereTree() const
+{
+ if (!m_pParseTree)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to WHERE clause:
+ OSQLParseNode * pWhereClause = nullptr;
+ if(getStatementType() == OSQLStatementType::Select)
+ {
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pWhereClause = pTableExp->getChild(1);
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched) ||
+ SQL_ISRULE(m_pParseTree,delete_statement_searched))
+ {
+ pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1);
+ }
+ if(pWhereClause && pWhereClause->count() != 2)
+ pWhereClause = nullptr;
+ return pWhereClause;
+}
+
+
+const OSQLParseNode* OSQLParseTreeIterator::getOrderTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+
+ assert(SQL_ISRULE(m_pParseTree, select_statement) || SQL_ISRULE(m_pParseTree, union_statement));
+
+ auto pParseTree = m_pParseTree;
+ if(SQL_ISRULE(m_pParseTree, union_statement))
+ {
+ assert(m_pParseTree->count() == 4);
+ pParseTree = pParseTree->getChild(3);
+ // since UNION is left-associative (at least in our grammar),
+ // possibly the left-hand (m_pParseTree->getChild(0)) is a union_statement,
+ // but the right hand cannot.
+ assert(SQL_ISRULE(pParseTree, select_statement));
+ }
+
+ OSQLParseNode * pOrderClause = nullptr;
+ OSL_ENSURE(pParseTree->count() == 4, "OSQLParseTreeIterator::getOrderTree: expected a SELECT, and a SELECT must have exactly four children");
+ OSQLParseNode * pTableExp = pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr, "OSQLParseTreeIterator::getOrderTree: got NULL table_exp");
+ OSL_ENSURE(SQL_ISRULE(pTableExp, table_exp), "OSQLParseTreeIterator::getOrderTree: expected table_exp but got something else");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator::getOrderTree: table_exp doesn't have the expected number of children");
+ // tdf#141115 upgrade the above to an assert;
+ // this cannot go well if there are too few children
+ assert(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT);
+
+ pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
+ // If it is an order_by, it must not be empty
+ if(pOrderClause->count() != 3)
+ pOrderClause = nullptr;
+ return pOrderClause;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getGroupByTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+ OSQLParseNode * pGroupClause = nullptr;
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pGroupClause = pTableExp->getChild(2);
+ // If it is an order_by, it must not be empty
+ if(pGroupClause->count() != 3)
+ pGroupClause = nullptr;
+ return pGroupClause;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const
+{
+ if (!m_pParseTree || getStatementType() != OSQLStatementType::Select)
+ return nullptr;
+
+ // Analyse parse tree (depending on statement type)
+ // and set pointer to ORDER clause:
+ OSQLParseNode * pHavingClause = nullptr;
+ OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!");
+ OSQLParseNode * pTableExp = m_pParseTree->getChild(3);
+ OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!");
+ OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!");
+
+ pHavingClause = pTableExp->getChild(3);
+ // If it is an order_by, then it must not be empty
+ if(pHavingClause->count() < 1)
+ pHavingClause = nullptr;
+ return pHavingClause;
+}
+
+bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode* _pTableNode)
+{
+ return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) ||
+ SQL_ISRULE(_pTableNode,schema_name) ||
+ SQL_ISRULE(_pTableNode,table_name));
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleWhereTree() const
+{
+ const OSQLParseNode* pNode = getWhereTree();
+ return pNode ? pNode->getChild(1) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleOrderTree() const
+{
+ const OSQLParseNode* pNode = getOrderTree();
+ return pNode ? pNode->getChild(2) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleGroupByTree() const
+{
+ const OSQLParseNode* pNode = getGroupByTree();
+ return pNode ? pNode->getChild(2) : nullptr;
+}
+
+const OSQLParseNode* OSQLParseTreeIterator::getSimpleHavingTree() const
+{
+ const OSQLParseNode* pNode = getHavingTree();
+ return pNode ? pNode->getChild(1) : nullptr;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findSelectColumn( std::u16string_view rColumnName )
+{
+ for (auto const& lookupColumn : *m_aSelectColumns)
+ {
+ Reference< XPropertySet > xColumn( lookupColumn );
+ try
+ {
+ OUString sName;
+ xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sName;
+ if ( sName == rColumnName )
+ return xColumn;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("connectivity.parse");
+ }
+ }
+ return nullptr;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const OUString & rColumnName, OUString & rTableRange, bool _bLookInSubTables )
+{
+ Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange );
+ if ( !xColumn.is() && _bLookInSubTables )
+ xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange );
+ return xColumn;
+}
+
+
+Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables, const OUString & rColumnName, OUString & rTableRange)
+{
+ Reference< XPropertySet > xColumn;
+ if ( !rTableRange.isEmpty() )
+ {
+ OSQLTables::const_iterator aFind = _rTables.find(rTableRange);
+
+ if ( aFind != _rTables.end()
+ && aFind->second.is()
+ && aFind->second->getColumns().is()
+ && aFind->second->getColumns()->hasByName(rColumnName) )
+ aFind->second->getColumns()->getByName(rColumnName) >>= xColumn;
+ }
+ if ( !xColumn.is() )
+ {
+ for (auto const& table : _rTables)
+ {
+ if ( table.second.is() )
+ {
+ Reference<XNameAccess> xColumns = table.second->getColumns();
+ if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) )
+ {
+ OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!");
+ // Cannot take "rTableRange = table.first" because that is the fully composed name
+ // that is, catalogName.schemaName.tableName
+ rTableRange = getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)));
+ break; // This column must only exits once
+ }
+ }
+ }
+ }
+ return xColumn;
+}
+
+
+void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const OUString* _pReplaceToken1, const OUString* _pReplaceToken2 )
+{
+ OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError );
+ if ( _pReplaceToken1 )
+ {
+ bool bTwoTokens = ( _pReplaceToken2 != nullptr );
+ const char* pPlaceHolder1 = bTwoTokens ? "#1" : "#";
+ const OUString sPlaceHolder1 = OUString::createFromAscii( pPlaceHolder1 );
+
+ sErrorMessage = sErrorMessage.replaceFirst( sPlaceHolder1, *_pReplaceToken1 );
+ if ( _pReplaceToken2 )
+ sErrorMessage = sErrorMessage.replaceFirst( "#2" , *_pReplaceToken2 );
+ }
+
+ impl_appendError( SQLException(
+ sErrorMessage, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() ) );
+}
+
+
+void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError )
+{
+ SAL_WARN("connectivity.parse", "Adding error " << exceptionToString(Any(_rError)));
+ if ( m_xErrors )
+ {
+ SQLException* pErrorChain = &*m_xErrors;
+ while ( pErrorChain->NextException.hasValue() )
+ pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData );
+ pErrorChain->NextException <<= _rError;
+ }
+ else
+ m_xErrors = _rError;
+}
+
+sal_Int32 OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode* _pNode )
+{
+ sal_Int32 nType = DataType::OTHER;
+ OUString sFunctionName;
+ if ( SQL_ISRULE(_pNode,length_exp) )
+ {
+ _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+ nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
+ }
+ else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) )
+ {
+ nType = DataType::DOUBLE;
+ }
+ else
+ {
+ _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false );
+
+ // MIN and MAX have another return type, we have to check the expression itself.
+ // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566
+ if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) ))
+ {
+ const OSQLParseNode* pValueExp = _pNode->getChild(3);
+ if (SQL_ISRULE(pValueExp,column_ref))
+ {
+ OUString sColumnName;
+ OUString aTableRange;
+ getColumnRange(pValueExp,sColumnName,aTableRange);
+ OSL_ENSURE(!sColumnName.isEmpty(),"Columnname must not be empty!");
+ Reference<XPropertySet> xColumn = findColumn( sColumnName, aTableRange, true );
+
+ if ( xColumn.is() )
+ {
+ xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType;
+ }
+ }
+ else
+ {
+ if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) )
+ {
+ nType = DataType::DOUBLE;
+ }
+ else if ( SQL_ISRULE(pValueExp,datetime_primary) )
+ {
+ switch(pValueExp->getChild(0)->getTokenID() )
+ {
+ case SQL_TOKEN_CURRENT_DATE:
+ nType = DataType::DATE;
+ break;
+ case SQL_TOKEN_CURRENT_TIME:
+ nType = DataType::TIME;
+ break;
+ case SQL_TOKEN_CURRENT_TIMESTAMP:
+ nType = DataType::TIMESTAMP;
+ break;
+ }
+ }
+ else if ( SQL_ISRULE(pValueExp,value_exp_primary) )
+ {
+ nType = getFunctionReturnType(pValueExp->getChild(1));
+ }
+ else if ( SQL_ISRULE(pValueExp,concatenation)
+ || SQL_ISRULE(pValueExp,char_factor)
+ || SQL_ISRULE(pValueExp,bit_value_fct)
+ || SQL_ISRULE(pValueExp,char_value_fct)
+ || SQL_ISRULE(pValueExp,char_substring_fct)
+ || SQL_ISRULE(pValueExp,fold)
+ || SQL_ISTOKEN(pValueExp,STRING) )
+ {
+ nType = DataType::VARCHAR;
+ }
+ }
+ if ( nType == DataType::OTHER )
+ nType = DataType::DOUBLE;
+ }
+ else
+ nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() );
+ }
+
+ return nType;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/parse/sqlnode.cxx b/connectivity/source/parse/sqlnode.cxx
new file mode 100644
index 000000000..75acac48f
--- /dev/null
+++ b/connectivity/source/parse/sqlnode.cxx
@@ -0,0 +1,2789 @@
+/* -*- 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 <string_view>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.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(std::u16string_view rValue, const OUString& rQuot, std::u16string_view rQuotToReplace)
+ {
+ OUString rNewValue = rQuot + 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())
+ 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,
+ const 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(_sPredicateTableAlias)
+ ,m_rContext( _pContext ? *_pContext : OSQLParser::s_aDefaultContext )
+ ,sDecSep(_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, OUString("."), false );
+}
+
+
+void OSQLParseNode::parseNodeToPredicateStr(OUString& rString,
+ const Reference< XConnection >& _rxConnection,
+ const Reference< XNumberFormatter > & xFormatter,
+ const css::lang::Locale& rIntl,
+ OUString _sDec,
+ 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, _sDec, 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,
+ OUString _sDec,
+ 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, _sDec, 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,
+ OUString _sDecSep,
+ 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, _sDecSep, _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, OUString("."), 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();
+ delete 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),
+ OUStringConcatenation(" 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);
+ }
+ 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 )
+ 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;
+ }
+ 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, "\'", 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 )
+ {
+ 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, u"");
+ 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;
+}
+
+
+std::unique_ptr<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();
+ m_pParseTree.release(); // because the garbage collector deleted it
+ 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(const css::uno::Reference< css::uno::XComponentContext >& rxContext, const IParseContext* _pContext)
+ :m_pContext(_pContext)
+ ,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 = 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();
+}
+
+
+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().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);
+ 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& ) { }
+ 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(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::none_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewNode; }),
+ "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],"{"))
+ return false;
+
+ 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) ))
+ return false;
+
+ 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;
+}
+
+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;
+}
+
+static 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;
+}
+
+static 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
+ OSQLParseNode* pOldRight = pSearchCondition->removeAt(2);
+ assert(pOldRight == pRight);
+
+ pNewRight = MakeANDNode(pOr->removeAt(2), pOldRight);
+ pNewLeft = MakeANDNode(pOr->removeAt(sal_uInt32(0)), new OSQLParseNode(*pOldRight));
+ 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
+ OSQLParseNode* pOldLeft = pSearchCondition->removeAt(sal_uInt32(0));
+ assert(pOldLeft == pLeft);
+
+ pNewRight = MakeANDNode(pOldLeft, pOr->removeAt(2));
+ pNewLeft = MakeANDNode(new OSQLParseNode(*pOldLeft), 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),")")))))
+ return;
+
+ 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)))
+ return;
+
+ 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::any_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pOldSubNode; }),
+ "OSQLParseNode::Replace() Node not element of parent");
+ OSL_ENSURE(std::none_of(m_aChildren.begin(), m_aChildren.end(),
+ [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewSubNode; }),
+ "OSQLParseNode::Replace() Node already element of parent");
+
+ pOldSubNode->setParent( nullptr );
+ pNewSubNode->setParent( this );
+ auto it = std::find_if(m_aChildren.begin(), m_aChildren.end(),
+ [&pOldSubNode](const std::unique_ptr<OSQLParseNode>& rxChild) { return rxChild.get() == pOldSubNode; });
+ if (it != m_aChildren.end())
+ {
+ it->release();
+ it->reset(pNewSubNode);
+ }
+ 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, "\'", u"\'\'"));
+ 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;
+ static constexpr OUStringLiteral strPoint(u".");
+ if (rParam.bInternational && rParam.bPredicate && rParam.sDecSep != strPoint)
+ aTmp = aTmp.replaceAll(strPoint, rParam.sDecSep);
+
+ 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;
+ }
+ [[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(std::u16string_view _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: */