diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /dbaccess/source/filter/hsqldb/createparser.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dbaccess/source/filter/hsqldb/createparser.cxx')
-rw-r--r-- | dbaccess/source/filter/hsqldb/createparser.cxx | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/dbaccess/source/filter/hsqldb/createparser.cxx b/dbaccess/source/filter/hsqldb/createparser.cxx new file mode 100644 index 0000000000..360741ce0b --- /dev/null +++ b/dbaccess/source/filter/hsqldb/createparser.cxx @@ -0,0 +1,298 @@ +/* -*- 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 <comphelper/string.hxx> +#include <sal/log.hxx> +#include <o3tl/string_view.hxx> +#include "createparser.hxx" +#include "utils.hxx" +#include <com/sun/star/sdbc/DataType.hpp> + +using namespace ::comphelper; +using namespace css::sdbc; + +namespace +{ +/// Returns substring of sSql from the first occurrence of '(' until the +/// last occurrence of ')' (excluding the parenthesis) +std::u16string_view lcl_getColumnPart(std::u16string_view sSql) +{ + size_t nBeginIndex = sSql.find('('); + if (nBeginIndex == std::u16string_view::npos) + { + SAL_WARN("dbaccess", "No column definitions found"); + return std::u16string_view(); + } + sal_Int32 nCount = sSql.rfind(')') - nBeginIndex - 1; + auto sPart = sSql.substr(nBeginIndex + 1, nCount); + return sPart; +} + +/// Constructs a vector of strings that represents the definitions of each +/// column or constraint. +/// +/// @param sColumnPart part of the create statement inside the parenthesis +/// containing the column definitions +std::vector<OUString> lcl_splitColumnPart(std::u16string_view sColumnPart) +{ + std::vector<OUString> sParts = string::split(sColumnPart, sal_Unicode(u',')); + std::vector<OUString> sReturn; + + OUStringBuffer current(128); + for (auto const& part : sParts) + { + current.append(part); + if (current.lastIndexOf("(") > current.lastIndexOf(")")) + current.append(","); // it was false split + else + { + sReturn.push_back(current.toString()); + current.setLength(0); + } + } + return sReturn; +} + +sal_Int32 lcl_getAutoIncrementDefault(std::u16string_view sColumnDef) +{ + // TODO what if there are more spaces? + size_t nPos = sColumnDef.find(u"GENERATED BY DEFAULT AS IDENTITY"); + if (nPos != std::u16string_view::npos && nPos > 0) + { + // TODO parse starting sequence stated by "START WITH" + return 0; + } + return -1; +} + +std::u16string_view lcl_getDefaultValue(std::u16string_view sColumnDef) +{ + constexpr std::u16string_view DEFAULT_KW = u"DEFAULT"; + size_t nDefPos = sColumnDef.find(DEFAULT_KW); + if (nDefPos > 0 && nDefPos != std::u16string_view::npos + && lcl_getAutoIncrementDefault(sColumnDef) < 0) + { + std::u16string_view fromDefault + = o3tl::trim(sColumnDef.substr(nDefPos + DEFAULT_KW.size())); + + // next word is the value + size_t nNextSpace = fromDefault.find(' '); + return (nNextSpace > 0 && nNextSpace != std::u16string_view::npos) + ? fromDefault.substr(0, nNextSpace) + : fromDefault; + } + return std::u16string_view(); +} + +bool lcl_isNullable(std::u16string_view sColumnDef) +{ + return sColumnDef.find(u"NOT NULL") == std::u16string_view::npos; +} + +bool lcl_isPrimaryKey(std::u16string_view sColumnDef) +{ + return sColumnDef.find(u"PRIMARY KEY") != std::u16string_view::npos; +} + +sal_Int32 lcl_getDataTypeFromHsql(std::u16string_view sTypeName) +{ + if (sTypeName == u"CHAR") + return DataType::CHAR; + else if (sTypeName == u"VARCHAR" || sTypeName == u"VARCHAR_IGNORECASE") + return DataType::VARCHAR; + else if (sTypeName == u"TINYINT") + return DataType::TINYINT; + else if (sTypeName == u"SMALLINT") + return DataType::SMALLINT; + else if (sTypeName == u"INTEGER") + return DataType::INTEGER; + else if (sTypeName == u"BIGINT") + return DataType::BIGINT; + else if (sTypeName == u"NUMERIC") + return DataType::NUMERIC; + else if (sTypeName == u"DECIMAL") + return DataType::DECIMAL; + else if (sTypeName == u"BOOLEAN") + return DataType::BOOLEAN; + else if (sTypeName == u"LONGVARCHAR") + return DataType::LONGVARCHAR; + else if (sTypeName == u"LONGVARBINARY") + return DataType::LONGVARBINARY; + else if (sTypeName == u"CLOB") + return DataType::CLOB; + else if (sTypeName == u"BLOB") + return DataType::BLOB; + else if (sTypeName == u"BINARY") + return DataType::BINARY; + else if (sTypeName == u"VARBINARY") + return DataType::VARBINARY; + else if (sTypeName == u"DATE") + return DataType::DATE; + else if (sTypeName == u"TIME") + return DataType::TIME; + else if (sTypeName == u"TIMESTAMP") + return DataType::TIMESTAMP; + else if (sTypeName == u"DOUBLE") + return DataType::DOUBLE; + else if (sTypeName == u"REAL") + return DataType::REAL; + else if (sTypeName == u"FLOAT") + return DataType::FLOAT; + + assert(false); + return -1; +} + +void lcl_addDefaultParameters(std::vector<sal_Int32>& aParams, sal_Int32 eType) +{ + if (eType == DataType::CHAR || eType == DataType::BINARY || eType == DataType::VARBINARY + || eType == DataType::VARCHAR) + aParams.push_back(8000); // from SQL standard +} + +struct ColumnTypeParts +{ + OUString typeName; + std::vector<sal_Int32> params; +}; + +/** + * Separates full type descriptions (e.g. NUMERIC(5,4)) to type name (NUMERIC) and + * parameters (5,4) + */ +ColumnTypeParts lcl_getColumnTypeParts(std::u16string_view sFullTypeName) +{ + ColumnTypeParts parts; + auto nParenPos = sFullTypeName.find('('); + if (nParenPos > 0 && nParenPos != std::u16string_view::npos) + { + parts.typeName = o3tl::trim(sFullTypeName.substr(0, nParenPos)); + std::u16string_view sParamStr + = sFullTypeName.substr(nParenPos + 1, sFullTypeName.find(')') - nParenPos - 1); + auto sParams = string::split(sParamStr, sal_Unicode(u',')); + for (const auto& sParam : sParams) + { + parts.params.push_back(sParam.toInt32()); + } + } + else + { + parts.typeName = o3tl::trim(sFullTypeName); + lcl_addDefaultParameters(parts.params, lcl_getDataTypeFromHsql(parts.typeName)); + } + return parts; +} + +} // unnamed namespace + +namespace dbahsql +{ +CreateStmtParser::CreateStmtParser() {} + +void CreateStmtParser::parsePrimaryKeys(std::u16string_view sPrimaryPart) +{ + size_t nParenPos = sPrimaryPart.find('('); + if (nParenPos > 0 && nParenPos != std::u16string_view::npos) + { + std::u16string_view sParamStr + = sPrimaryPart.substr(nParenPos + 1, sPrimaryPart.rfind(')') - nParenPos - 1); + auto sParams = string::split(sParamStr, sal_Unicode(u',')); + for (const auto& sParam : sParams) + { + m_PrimaryKeys.push_back(sParam); + } + } +} + +void CreateStmtParser::parseColumnPart(std::u16string_view sColumnPart) +{ + auto sColumns = lcl_splitColumnPart(sColumnPart); + for (const OUString& sColumn : sColumns) + { + if (sColumn.startsWithIgnoreAsciiCase("PRIMARY KEY")) + { + parsePrimaryKeys(sColumn); + continue; + } + + if (sColumn.startsWithIgnoreAsciiCase("CONSTRAINT")) + { + m_aForeignParts.push_back(sColumn); + continue; + } + + bool bIsQuoteUsedForColumnName(sColumn[0] == '\"'); + + // find next quote after the initial quote + // or next space if quote isn't used as delimiter + auto nEndColumnName + = bIsQuoteUsedForColumnName ? sColumn.indexOf("\"", 1) + 1 : sColumn.indexOf(" "); + OUString rColumnName = sColumn.copy(0, nEndColumnName); + + const OUString sFromTypeName(o3tl::trim(sColumn.subView(nEndColumnName))); + + // Now let's manage the column type + // search next space to get the whole type name + // eg: INTEGER, VARCHAR(10), DECIMAL(6,3) + auto nNextSpace = sFromTypeName.indexOf(" "); + std::u16string_view sFullTypeName; + if (nNextSpace > 0) + sFullTypeName = sFromTypeName.subView(0, nNextSpace); + // perhaps column type corresponds to the last info here + else + sFullTypeName = sFromTypeName; + + ColumnTypeParts typeParts = lcl_getColumnTypeParts(sFullTypeName); + + bool bCaseInsensitive = typeParts.typeName.indexOf("IGNORECASE") >= 0; + bool isPrimaryKey = lcl_isPrimaryKey(sColumn); + + if (isPrimaryKey) + m_PrimaryKeys.push_back(rColumnName); + + const std::u16string_view sColumnWithoutName + = sColumn.subView(sColumn.indexOf(typeParts.typeName)); + + ColumnDefinition aColDef(rColumnName, lcl_getDataTypeFromHsql(typeParts.typeName), + std::move(typeParts.params), isPrimaryKey, + lcl_getAutoIncrementDefault(sColumnWithoutName), + lcl_isNullable(sColumnWithoutName), bCaseInsensitive, + OUString(lcl_getDefaultValue(sColumnWithoutName))); + + m_aColumns.push_back(aColDef); + } +} + +void CreateStmtParser::parse(std::u16string_view sSql) +{ + // TODO Foreign keys + if (!o3tl::starts_with(sSql, u"CREATE")) + { + SAL_WARN("dbaccess", "Not a create statement"); + return; + } + + m_sTableName = utils::getTableNameFromStmt(sSql); + std::u16string_view sColumnPart = lcl_getColumnPart(sSql); + parseColumnPart(sColumnPart); +} + +} // namespace dbahsql + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |