LibreOffice Module dbaccess (master) 1
createparser.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 <comphelper/string.hxx>
21#include <sal/log.hxx>
22#include <o3tl/string_view.hxx>
23#include "createparser.hxx"
24#include "utils.hxx"
25#include <com/sun/star/sdbc/DataType.hpp>
26
27using namespace ::comphelper;
28using namespace css::sdbc;
29
30namespace
31{
34std::u16string_view lcl_getColumnPart(std::u16string_view sSql)
35{
36 size_t nBeginIndex = sSql.find('(');
37 if (nBeginIndex == std::u16string_view::npos)
38 {
39 SAL_WARN("dbaccess", "No column definitions found");
40 return std::u16string_view();
41 }
42 sal_Int32 nCount = sSql.rfind(')') - nBeginIndex - 1;
43 auto sPart = sSql.substr(nBeginIndex + 1, nCount);
44 return sPart;
45}
46
52std::vector<OUString> lcl_splitColumnPart(std::u16string_view sColumnPart)
53{
54 std::vector<OUString> sParts = string::split(sColumnPart, sal_Unicode(u','));
55 std::vector<OUString> sReturn;
56
57 OUStringBuffer current(128);
58 for (auto const& part : sParts)
59 {
60 current.append(part);
61 if (current.lastIndexOf("(") > current.lastIndexOf(")"))
62 current.append(","); // it was false split
63 else
64 {
65 sReturn.push_back(current.toString());
66 current.setLength(0);
67 }
68 }
69 return sReturn;
70}
71
72sal_Int32 lcl_getAutoIncrementDefault(std::u16string_view sColumnDef)
73{
74 // TODO what if there are more spaces?
75 size_t nPos = sColumnDef.find(u"GENERATED BY DEFAULT AS IDENTITY");
76 if (nPos != std::u16string_view::npos && nPos > 0)
77 {
78 // TODO parse starting sequence stated by "START WITH"
79 return 0;
80 }
81 return -1;
82}
83
84std::u16string_view lcl_getDefaultValue(std::u16string_view sColumnDef)
85{
86 constexpr std::u16string_view DEFAULT_KW = u"DEFAULT";
87 size_t nDefPos = sColumnDef.find(DEFAULT_KW);
88 if (nDefPos > 0 && nDefPos != std::u16string_view::npos
89 && lcl_getAutoIncrementDefault(sColumnDef) < 0)
90 {
91 std::u16string_view fromDefault
92 = o3tl::trim(sColumnDef.substr(nDefPos + DEFAULT_KW.size()));
93
94 // next word is the value
95 size_t nNextSpace = fromDefault.find(' ');
96 return (nNextSpace > 0 && nNextSpace != std::u16string_view::npos)
97 ? fromDefault.substr(0, nNextSpace)
98 : fromDefault;
99 }
100 return std::u16string_view();
101}
102
103bool lcl_isNullable(std::u16string_view sColumnDef)
104{
105 return sColumnDef.find(u"NOT NULL") == std::u16string_view::npos;
106}
107
108bool lcl_isPrimaryKey(std::u16string_view sColumnDef)
109{
110 return sColumnDef.find(u"PRIMARY KEY") != std::u16string_view::npos;
111}
112
113sal_Int32 lcl_getDataTypeFromHsql(std::u16string_view sTypeName)
114{
115 if (sTypeName == u"CHAR")
116 return DataType::CHAR;
117 else if (sTypeName == u"VARCHAR" || sTypeName == u"VARCHAR_IGNORECASE")
118 return DataType::VARCHAR;
119 else if (sTypeName == u"TINYINT")
120 return DataType::TINYINT;
121 else if (sTypeName == u"SMALLINT")
122 return DataType::SMALLINT;
123 else if (sTypeName == u"INTEGER")
124 return DataType::INTEGER;
125 else if (sTypeName == u"BIGINT")
126 return DataType::BIGINT;
127 else if (sTypeName == u"NUMERIC")
128 return DataType::NUMERIC;
129 else if (sTypeName == u"DECIMAL")
130 return DataType::DECIMAL;
131 else if (sTypeName == u"BOOLEAN")
132 return DataType::BOOLEAN;
133 else if (sTypeName == u"LONGVARCHAR")
134 return DataType::LONGVARCHAR;
135 else if (sTypeName == u"LONGVARBINARY")
136 return DataType::LONGVARBINARY;
137 else if (sTypeName == u"CLOB")
138 return DataType::CLOB;
139 else if (sTypeName == u"BLOB")
140 return DataType::BLOB;
141 else if (sTypeName == u"BINARY")
142 return DataType::BINARY;
143 else if (sTypeName == u"VARBINARY")
144 return DataType::VARBINARY;
145 else if (sTypeName == u"DATE")
146 return DataType::DATE;
147 else if (sTypeName == u"TIME")
148 return DataType::TIME;
149 else if (sTypeName == u"TIMESTAMP")
150 return DataType::TIMESTAMP;
151 else if (sTypeName == u"DOUBLE")
152 return DataType::DOUBLE;
153 else if (sTypeName == u"REAL")
154 return DataType::REAL;
155 else if (sTypeName == u"FLOAT")
156 return DataType::FLOAT;
157
158 assert(false);
159 return -1;
160}
161
162void lcl_addDefaultParameters(std::vector<sal_Int32>& aParams, sal_Int32 eType)
163{
164 if (eType == DataType::CHAR || eType == DataType::BINARY || eType == DataType::VARBINARY
165 || eType == DataType::VARCHAR)
166 aParams.push_back(8000); // from SQL standard
167}
168
169struct ColumnTypeParts
170{
171 OUString typeName;
172 std::vector<sal_Int32> params;
173};
174
179ColumnTypeParts lcl_getColumnTypeParts(std::u16string_view sFullTypeName)
180{
181 ColumnTypeParts parts;
182 auto nParenPos = sFullTypeName.find('(');
183 if (nParenPos > 0 && nParenPos != std::u16string_view::npos)
184 {
185 parts.typeName = o3tl::trim(sFullTypeName.substr(0, nParenPos));
186 std::u16string_view sParamStr
187 = sFullTypeName.substr(nParenPos + 1, sFullTypeName.find(')') - nParenPos - 1);
188 auto sParams = string::split(sParamStr, sal_Unicode(u','));
189 for (const auto& sParam : sParams)
190 {
191 parts.params.push_back(sParam.toInt32());
192 }
193 }
194 else
195 {
196 parts.typeName = o3tl::trim(sFullTypeName);
197 lcl_addDefaultParameters(parts.params, lcl_getDataTypeFromHsql(parts.typeName));
198 }
199 return parts;
200}
201
202} // unnamed namespace
203
204namespace dbahsql
205{
207
208void CreateStmtParser::parsePrimaryKeys(std::u16string_view sPrimaryPart)
209{
210 size_t nParenPos = sPrimaryPart.find('(');
211 if (nParenPos > 0 && nParenPos != std::u16string_view::npos)
212 {
213 std::u16string_view sParamStr
214 = sPrimaryPart.substr(nParenPos + 1, sPrimaryPart.rfind(')') - nParenPos - 1);
215 auto sParams = string::split(sParamStr, sal_Unicode(u','));
216 for (const auto& sParam : sParams)
217 {
218 m_PrimaryKeys.push_back(sParam);
219 }
220 }
221}
222
223void CreateStmtParser::parseColumnPart(std::u16string_view sColumnPart)
224{
225 auto sColumns = lcl_splitColumnPart(sColumnPart);
226 for (const OUString& sColumn : sColumns)
227 {
228 if (sColumn.startsWithIgnoreAsciiCase("PRIMARY KEY"))
229 {
230 parsePrimaryKeys(sColumn);
231 continue;
232 }
233
234 if (sColumn.startsWithIgnoreAsciiCase("CONSTRAINT"))
235 {
236 m_aForeignParts.push_back(sColumn);
237 continue;
238 }
239
240 bool bIsQuoteUsedForColumnName(sColumn[0] == '\"');
241
242 // find next quote after the initial quote
243 // or next space if quote isn't used as delimiter
244 auto nEndColumnName
245 = bIsQuoteUsedForColumnName ? sColumn.indexOf("\"", 1) + 1 : sColumn.indexOf(" ");
246 OUString rColumnName = sColumn.copy(0, nEndColumnName);
247
248 const OUString sFromTypeName(o3tl::trim(sColumn.subView(nEndColumnName)));
249
250 // Now let's manage the column type
251 // search next space to get the whole type name
252 // eg: INTEGER, VARCHAR(10), DECIMAL(6,3)
253 auto nNextSpace = sFromTypeName.indexOf(" ");
254 std::u16string_view sFullTypeName;
255 if (nNextSpace > 0)
256 sFullTypeName = sFromTypeName.subView(0, nNextSpace);
257 // perhaps column type corresponds to the last info here
258 else
259 sFullTypeName = sFromTypeName;
260
261 ColumnTypeParts typeParts = lcl_getColumnTypeParts(sFullTypeName);
262
263 bool bCaseInsensitive = typeParts.typeName.indexOf("IGNORECASE") >= 0;
264 bool isPrimaryKey = lcl_isPrimaryKey(sColumn);
265
266 if (isPrimaryKey)
267 m_PrimaryKeys.push_back(rColumnName);
268
269 const std::u16string_view sColumnWithoutName
270 = sColumn.subView(sColumn.indexOf(typeParts.typeName));
271
272 ColumnDefinition aColDef(rColumnName, lcl_getDataTypeFromHsql(typeParts.typeName),
273 std::move(typeParts.params), isPrimaryKey,
274 lcl_getAutoIncrementDefault(sColumnWithoutName),
275 lcl_isNullable(sColumnWithoutName), bCaseInsensitive,
276 OUString(lcl_getDefaultValue(sColumnWithoutName)));
277
278 m_aColumns.push_back(aColDef);
279 }
280}
281
282void CreateStmtParser::parse(std::u16string_view sSql)
283{
284 // TODO Foreign keys
285 if (!o3tl::starts_with(sSql, u"CREATE"))
286 {
287 SAL_WARN("dbaccess", "Not a create statement");
288 return;
289 }
290
292 std::u16string_view sColumnPart = lcl_getColumnPart(sSql);
293 parseColumnPart(sColumnPart);
294}
295
296} // namespace dbahsql
297
298/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
nAutoIncrement: column is auto incremented started with value nAutoIncrement
Definition: columndef.hxx:19
std::vector< OUString > m_PrimaryKeys
void parse(std::u16string_view sSql)
Parses a create statement.
void parseColumnPart(std::u16string_view sColumnPart)
void parsePrimaryKeys(std::u16string_view sPrimaryPart)
std::vector< ColumnDefinition > m_aColumns
std::vector< OUString > m_aForeignParts
int nCount
float u
OUString eType
Definition: generalpage.cxx:78
sal_uInt16 nPos
#define SAL_WARN(area, stream)
OUString getTableNameFromStmt(std::u16string_view sSql)
Definition: utils.cxx:91
std::basic_string_view< charT, traits > trim(std::basic_string_view< charT, traits > str)
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
OUString typeName
sal_uInt16 sal_Unicode