LibreOffice Module dbaccess (master) 1
hsqlimport.cxx
Go to the documentation of this file.
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 <com/sun/star/embed/XStorage.hpp>
21#include <com/sun/star/embed/ElementModes.hpp>
22#include <com/sun/star/io/XInputStream.hpp>
23#include <com/sun/star/io/WrongFormatException.hpp>
24#include <com/sun/star/util/Date.hpp>
25
26#include <com/sun/star/sdbc/XConnection.hpp>
27#include <com/sun/star/sdbc/XParameters.hpp>
28#include <com/sun/star/sdbc/DataType.hpp>
29#include <com/sun/star/sdbc/SQLException.hpp>
30
31#include <rtl/ustrbuf.hxx>
32#include <sal/log.hxx>
36
37#include <vcl/weld.hxx>
38
39#include "hsqlimport.hxx"
40#include "parseschema.hxx"
41#include "rowinputbinary.hxx"
42
43namespace
44{
45using namespace css::io;
46using namespace css::uno;
47using namespace css::sdbc;
48
49void lcl_setParams(const std::vector<Any>& row, Reference<XParameters> const& xParam,
50 const std::vector<dbahsql::ColumnDefinition>& rColTypes)
51{
52 assert(row.size() == rColTypes.size());
53 size_t nColIndex = 0;
54 for (size_t i = 0; i < rColTypes.size(); ++i)
55 {
56 if (!row.at(i).hasValue())
57 xParam->setNull(i + 1, rColTypes.at(i).getDataType());
58
59 switch (rColTypes.at(i).getDataType())
60 {
61 case DataType::CHAR:
62 case DataType::VARCHAR:
63 case DataType::LONGVARCHAR:
64 {
65 OUString sVal;
66 if (row.at(i) >>= sVal)
67 {
68 xParam->setString(nColIndex + 1, sVal);
69 }
70 }
71 break;
72 case DataType::TINYINT:
73 case DataType::SMALLINT:
74 {
75 sal_Int16 nVal;
76 if (row.at(i) >>= nVal)
77 {
78 xParam->setShort(nColIndex + 1, nVal);
79 }
80 }
81 break;
82 case DataType::INTEGER:
83 {
84 sal_Int32 nVal;
85 if (row.at(i) >>= nVal)
86 {
87 xParam->setInt(nColIndex + 1, nVal);
88 }
89 }
90 break;
91 case DataType::BIGINT:
92 {
93 sal_Int64 nVal;
94 if (row.at(i) >>= nVal)
95 {
96 xParam->setLong(nColIndex + 1, nVal);
97 }
98 }
99 break;
100 case DataType::REAL:
101 case DataType::FLOAT:
102 case DataType::DOUBLE:
103 {
104 double nVal;
105 if (row.at(i) >>= nVal)
106 {
107 xParam->setDouble(nColIndex + 1, nVal);
108 }
109 }
110 break;
111 case DataType::NUMERIC:
112 case DataType::DECIMAL:
113 {
114 Sequence<Any> aNumeric;
115 if (row.at(i) >>= aNumeric)
116 {
117 sal_Int32 nScale = 0;
118 if (aNumeric[1] >>= nScale)
119 xParam->setObjectWithInfo(nColIndex + 1, aNumeric[0],
120 rColTypes.at(i).getDataType(), nScale);
121 }
122 }
123 break;
124 case DataType::DATE:
125 {
126 css::util::Date date;
127 if (row.at(i) >>= date)
128 {
129 xParam->setDate(nColIndex + 1, date);
130 }
131 }
132 break;
133 case DataType::TIME:
134 {
135 css::util::Time time;
136 if (row.at(i) >>= time)
137 {
138 xParam->setTime(nColIndex + 1, time);
139 }
140 }
141 break;
142 case DataType::TIMESTAMP:
143 {
144 css::util::DateTime dateTime;
145 if (row.at(i) >>= dateTime)
146 {
147 xParam->setTimestamp(nColIndex + 1, dateTime);
148 }
149 }
150 break;
151 case DataType::BOOLEAN:
152 {
153 bool bVal = false;
154 if (row.at(i) >>= bVal)
155 xParam->setBoolean(nColIndex + 1, bVal);
156 }
157 break;
158 case DataType::OTHER:
159 // TODO
160 break;
161 case DataType::BINARY:
162 case DataType::VARBINARY:
163 case DataType::LONGVARBINARY:
164 {
165 Sequence<sal_Int8> nVal;
166 if (row.at(i) >>= nVal)
167 {
168 xParam->setBytes(nColIndex + 1, nVal);
169 }
170 break;
171 }
172 default:
173 throw WrongFormatException();
174 }
175 ++nColIndex;
176 }
177}
178
179OUString lcl_createInsertStatement(std::u16string_view sTableName,
180 const std::vector<dbahsql::ColumnDefinition>& rColTypes)
181{
182 assert(rColTypes.size() > 0);
183 OUStringBuffer sql(OUString::Concat("INSERT INTO ") + sTableName + " (");
184
185 // column names
186 for (size_t i = 0; i < rColTypes.size(); ++i)
187 {
188 sql.append(rColTypes.at(i).getName());
189 if (i < rColTypes.size() - 1)
190 sql.append(", ");
191 }
192 sql.append(") VALUES (");
193 for (size_t i = 0; i < rColTypes.size(); ++i)
194 {
195 sql.append("?");
196 if (i < rColTypes.size() - 1)
197 sql.append(", ");
198 }
199 sql.append(")");
200 return sql.makeStringAndClear();
201}
202
203} // unnamed namespace
204
205namespace dbahsql
206{
207using namespace css::embed;
208
209HsqlImporter::HsqlImporter(Reference<XConnection>& rConnection, const Reference<XStorage>& rStorage)
210 : m_rConnection(rConnection)
211{
212 m_xStorage.set(rStorage);
213}
214
215void HsqlImporter::insertRow(const std::vector<css::uno::Any>& xRows,
216 std::u16string_view sTableName,
217 const std::vector<ColumnDefinition>& rColTypes)
218{
219 OUString sStatement = lcl_createInsertStatement(sTableName, rColTypes);
220 Reference<XPreparedStatement> xStatement = m_rConnection->prepareStatement(sStatement);
221
222 Reference<XParameters> xParameter(xStatement, UNO_QUERY);
223 assert(xParameter.is());
224 xParameter->clearParameters();
225
226 lcl_setParams(xRows, xParameter, rColTypes);
227 xStatement->executeQuery();
228}
229
231 const std::vector<ColumnDefinition>& rColTypes,
232 const OUString& sTableName, sal_Int32 nIndexCount)
233{
234 rNode.readChildren(rStream);
235 sal_Int32 nNext = rNode.getLeft();
236 if (nNext > 0)
237 {
238 HsqlBinaryNode aLeft{ nNext };
239 processTree(aLeft, rStream, rColTypes, sTableName, nIndexCount);
240 }
241 std::vector<Any> row = rNode.readRow(rStream, rColTypes, nIndexCount);
242 insertRow(row, sTableName, rColTypes);
243
244 nNext = rNode.getRight();
245 if (nNext > 0)
246 {
247 HsqlBinaryNode aRight{ nNext };
248 processTree(aRight, rStream, rColTypes, sTableName, nIndexCount);
249 }
250}
251
262void HsqlImporter::parseTableRows(const std::vector<sal_Int32>& rIndexes,
263 const std::vector<ColumnDefinition>& rColTypes,
264 const OUString& sTableName)
265{
266 static constexpr OUStringLiteral BINARY_FILENAME = u"data";
267
268 if (!m_xStorage->hasByName(BINARY_FILENAME))
269 {
270 SAL_WARN("dbaccess", "data file does not exist in storage during hsqldb import");
271 assert(false); // TODO throw error
272 }
273
274 Reference<css::io::XStream> xStream(
275 m_xStorage->openStreamElement(BINARY_FILENAME, ElementModes::READ));
276
277 HsqlRowInputStream rowInput;
278 Reference<XInputStream> xInput = xStream->getInputStream();
279 rowInput.setInputStream(xInput);
280
281 if (!rIndexes.empty())
282 {
283 HsqlBinaryNode aPrimaryNode{ rIndexes.at(0) };
284 processTree(aPrimaryNode, rowInput, rColTypes, sTableName, rIndexes.size());
285 }
286
287 xInput->closeInput();
288}
289
291{
292 assert(m_xStorage);
293
295 std::unique_ptr<SQLException> pException;
296 try
297 {
298 parser.parseSchema();
299 }
300 catch (SQLException& ex)
301 {
302 pException.reset(new SQLException{ std::move(ex) });
303 }
304
305 auto statements = parser.getCreateStatements();
306
307 if (statements.empty() && !pException)
308 {
309 SAL_WARN("dbaccess", "dbashql: there is nothing to import");
310 return; // there is nothing to import
311 }
312
313 // schema
314 for (const auto& sSql : statements)
315 {
316 Reference<XStatement> statement = m_rConnection->createStatement();
317 try
318 {
319 statement->executeQuery(sSql);
320 }
321 catch (SQLException& ex)
322 {
323 // chain errors and keep going
324 if (pException)
325 ex.NextException <<= *pException;
326 pException.reset(new SQLException{ std::move(ex) });
327 }
328 }
329
330 // data
331 for (const auto& tableIndex : parser.getTableIndexes())
332 {
333 try
334 {
335 std::vector<ColumnDefinition> aColTypes = parser.getTableColumnTypes(tableIndex.first);
336 parseTableRows(tableIndex.second, aColTypes, tableIndex.first);
337 }
338 catch (const std::out_of_range& e)
339 {
340 std::unique_ptr<SQLException> ex(new SQLException);
341 const char* msg = e.what();
342 ex->SQLState = OUString(msg, strlen(msg), RTL_TEXTENCODING_ASCII_US);
343 // chain errors and keep going
344 if (pException)
345 ex->NextException <<= *pException;
346 pException = std::move(ex);
347 }
348 catch (SQLException& ex)
349 {
350 // chain errors and keep going
351 if (pException)
352 ex.NextException <<= *pException;
353 pException.reset(new SQLException{ std::move(ex) });
354 }
355 }
356
357 // alter stmts
358 for (const auto& sSql : parser.getAlterStatements())
359 {
360 Reference<XStatement> statement = m_rConnection->createStatement();
361 try
362 {
363 statement->executeQuery(sSql);
364 }
365 catch (SQLException& ex)
366 {
367 // chain errors and keep going
368 if (pException)
369 ex.NextException <<= *pException;
370 pException.reset(new SQLException{ std::move(ex) });
371 }
372 }
373
374 if (pException)
375 {
376 SAL_WARN("dbaccess", "Error during migration");
378 pParent ? pParent->GetXWindow() : nullptr,
379 ::comphelper::getProcessComponentContext());
380 }
381}
382}
383
384/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
void readChildren(HsqlRowInputStream const &rInput)
Read position of children from data file.
sal_Int32 getLeft() const
Get Position of left children.
std::vector< css::uno::Any > readRow(HsqlRowInputStream &rInput, const std::vector< ColumnDefinition > &aColTypes, sal_Int32 nIndexCount)
Read the row represented by this node.
sal_Int32 getRight() const
Get Position of right children.
css::uno::Reference< css::sdbc::XConnection > & m_rConnection
Definition: hsqlimport.hxx:29
HsqlImporter(css::uno::Reference< css::sdbc::XConnection > &rConnection, const css::uno::Reference< css::embed::XStorage > &rStorage)
Definition: hsqlimport.cxx:209
void insertRow(const std::vector< css::uno::Any > &xRows, std::u16string_view sTable, const std::vector< ColumnDefinition > &rColTypes)
Definition: hsqlimport.cxx:215
css::uno::Reference< css::embed::XStorage > m_xStorage
Definition: hsqlimport.hxx:30
void processTree(HsqlBinaryNode &rNode, HsqlRowInputStream &rStream, const std::vector< ColumnDefinition > &rColTypes, const OUString &sTableName, sal_Int32 nIndexCount)
Definition: hsqlimport.cxx:230
void parseTableRows(const std::vector< sal_Int32 > &rIndexes, const std::vector< ColumnDefinition > &rColTypes, const OUString &sTableName)
Format from the indexed file position is the following: <Node x20><Row> Where Node is a 20 byte data,...
Definition: hsqlimport.cxx:262
void importHsqlDatabase(weld::Window *pParent)
Migrate a HSQL database to another.
Definition: hsqlimport.cxx:290
void setInputStream(css::uno::Reference< css::io::XInputStream > const &rStream)
virtual css::uno::Reference< css::awt::XWindow > GetXWindow()=0
float u
#define SAL_WARN(area, stream)
void showError(const SQLExceptionInfo &_rInfo, const Reference< XWindow > &_xParent, const Reference< XComponentContext > &_rxContext)
int i
parser
const int nIndexCount