1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <sal/config.h>
21
22 #include <string_view>
23
24 #include "parseschema.hxx"
25 #include "fbcreateparser.hxx"
26 #include "fbalterparser.hxx"
27 #include "utils.hxx"
28
29 #include <com/sun/star/io/TextInputStream.hpp>
30 #include <com/sun/star/embed/XStorage.hpp>
31 #include <com/sun/star/embed/ElementModes.hpp>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/string.hxx>
34 #include <sal/log.hxx>
35 #include <connectivity/dbexception.hxx>
36
37 namespace
38 {
39 using namespace ::comphelper;
40
41 using IndexVector = std::vector<sal_Int32>;
42
43 class IndexStmtParser
44 {
45 private:
46 OUString m_sql;
47
48 public:
IndexStmtParser(const OUString & sSql)49 IndexStmtParser(const OUString& sSql)
50 : m_sql(sSql)
51 {
52 }
53
isIndexStatement() const54 bool isIndexStatement() const
55 {
56 return m_sql.startsWith("SET TABLE") && m_sql.indexOf("INDEX") >= 0;
57 }
58
getIndexes() const59 IndexVector getIndexes() const
60 {
61 assert(isIndexStatement());
62
63 OUString sIndexPart = m_sql.copy(m_sql.indexOf("INDEX") + 5);
64 sal_Int32 nQuotePos = sIndexPart.indexOf("'") + 1;
65 OUString sIndexNums = sIndexPart.copy(nQuotePos, sIndexPart.lastIndexOf("'") - nQuotePos);
66
67 std::vector<OUString> sIndexes = string::split(sIndexNums, u' ');
68 IndexVector indexes;
69 for (const auto& sIndex : sIndexes)
70 indexes.push_back(sIndex.toInt32());
71
72 // ignore last element
73 // TODO this is an identity peek, which indicates the value of the next
74 // identity. At the current state all migrated identities start with 0.
75 indexes.pop_back();
76
77 return indexes;
78 }
79
getTableName() const80 OUString getTableName() const
81 {
82 // SET TABLE <tableName> or SET TABLE "<multi word table name>"
83 OUString sName = string::split(m_sql, u' ')[2];
84 if (sName.indexOf('"') >= 0)
85 {
86 // Table name with string delimiter
87 sName = "\"" + string::split(m_sql, u'"')[1] + "\"";
88 }
89 return sName;
90 }
91 };
92
lcl_createAlterForeign(std::u16string_view sForeignPart,std::u16string_view sTableName)93 OUString lcl_createAlterForeign(std::u16string_view sForeignPart, std::u16string_view sTableName)
94 {
95 return OUString::Concat("ALTER TABLE ") + sTableName + " ADD " + sForeignPart;
96 }
97
98 } // anonymous namespace
99
100 namespace dbahsql
101 {
102 using namespace css::io;
103 using namespace css::uno;
104 using namespace css::embed;
105
SchemaParser(Reference<XStorage> & rStorage)106 SchemaParser::SchemaParser(Reference<XStorage>& rStorage)
107 : m_rStorage(rStorage)
108 {
109 }
110
parseSchema()111 void SchemaParser::parseSchema()
112 {
113 assert(m_rStorage);
114
115 static constexpr OUStringLiteral SCHEMA_FILENAME = u"script";
116 if (!m_rStorage->hasByName(SCHEMA_FILENAME))
117 {
118 SAL_WARN("dbaccess", "script file does not exist in storage during hsqldb import");
119 return;
120 }
121
122 Reference<XStream> xStream(m_rStorage->openStreamElement(SCHEMA_FILENAME, ElementModes::READ));
123
124 Reference<XComponentContext> rContext = comphelper::getProcessComponentContext();
125 Reference<XTextInputStream2> xTextInput = TextInputStream::create(rContext);
126 xTextInput->setEncoding("UTF-8");
127 xTextInput->setInputStream(xStream->getInputStream());
128
129 while (!xTextInput->isEOF())
130 {
131 // every line contains exactly one DDL statement
132 OUString sSql = utils::convertToUTF8(
133 OUStringToOString(xTextInput->readLine(), RTL_TEXTENCODING_UTF8));
134
135 IndexStmtParser indexParser{ sSql };
136 if (indexParser.isIndexStatement())
137 {
138 m_Indexes[indexParser.getTableName()] = indexParser.getIndexes();
139 }
140 else if (sSql.startsWith("SET") || sSql.startsWith("CREATE USER")
141 || sSql.startsWith("CREATE SCHEMA") || sSql.startsWith("GRANT"))
142 continue;
143 else if (sSql.startsWith("CREATE CACHED TABLE") || sSql.startsWith("CREATE TABLE"))
144 {
145 FbCreateStmtParser aCreateParser;
146 aCreateParser.parse(sSql);
147
148 for (const auto& foreignParts : aCreateParser.getForeignParts())
149 {
150 m_sAlterStatements.push_back(
151 lcl_createAlterForeign(foreignParts, aCreateParser.getTableName()));
152 }
153
154 sSql = aCreateParser.compose();
155
156 // save column definitions
157 m_ColumnTypes[aCreateParser.getTableName()] = aCreateParser.getColumnDef();
158
159 m_sCreateStatements.push_back(sSql);
160 }
161 else if (sSql.startsWith("ALTER"))
162 {
163 FbAlterStmtParser aAlterParser;
164 aAlterParser.parse(sSql);
165 OUString parsedStmt = aAlterParser.compose();
166
167 if (!parsedStmt.isEmpty())
168 m_sAlterStatements.push_back(parsedStmt);
169 }
170 else if (sSql.startsWith("CREATE VIEW"))
171 m_sCreateStatements.push_back(sSql);
172 }
173 }
174
getTableColumnTypes(const OUString & sTableName) const175 std::vector<ColumnDefinition> SchemaParser::getTableColumnTypes(const OUString& sTableName) const
176 {
177 if (m_ColumnTypes.count(sTableName) < 1)
178 {
179 static constexpr OUStringLiteral NOT_EXIST
180 = u"Internal error while getting column information of table";
181 SAL_WARN("dbaccess", NOT_EXIST << ". Table name is: " << sTableName);
182 dbtools::throwGenericSQLException(NOT_EXIST, ::comphelper::getProcessComponentContext());
183 }
184 return m_ColumnTypes.at(sTableName);
185 }
186
getTableIndexes() const187 const std::map<OUString, std::vector<sal_Int32>>& SchemaParser::getTableIndexes() const
188 {
189 return m_Indexes;
190 }
191
getPrimaryKeys() const192 const std::map<OUString, std::vector<OUString>>& SchemaParser::getPrimaryKeys() const
193 {
194 return m_PrimaryKeys;
195 }
196
197 } // namespace dbahsql
198
199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
200