nss: upgrade to release 3.73
[LibreOffice.git] / dbaccess / source / filter / hsqldb / createparser.cxx
blobad1c95f89966432a68a34e99a59f51514b9c11e0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <comphelper/string.hxx>
21 #include <sal/log.hxx>
22 #include "createparser.hxx"
23 #include "utils.hxx"
24 #include <com/sun/star/sdbc/DataType.hpp>
26 using namespace ::comphelper;
27 using namespace css::sdbc;
29 namespace
31 /// Returns substring of sSql from the first occurrence of '(' until the
32 /// last occurrence of ')' (excluding the parenthesis)
33 OUString lcl_getColumnPart(const OUString& sSql)
35 sal_Int32 nBeginIndex = sSql.indexOf("(") + 1;
36 if (nBeginIndex < 0)
38 SAL_WARN("dbaccess", "No column definitions found");
39 return OUString();
41 sal_Int32 nCount = sSql.lastIndexOf(")") - nBeginIndex;
42 return sSql.copy(nBeginIndex, nCount);
45 /// Constructs a vector of strings that represents the definitions of each
46 /// column or constraint.
47 ///
48 /// @param sColumnPart part of the create statement inside the parenthesis
49 /// containing the column definitions
50 std::vector<OUString> lcl_splitColumnPart(const OUString& sColumnPart)
52 std::vector<OUString> sParts = string::split(sColumnPart, sal_Unicode(u','));
53 std::vector<OUString> sReturn;
55 OUStringBuffer current(128);
56 for (auto const& part : sParts)
58 current.append(part);
59 if (current.lastIndexOf("(") > current.lastIndexOf(")"))
60 current.append(","); // it was false split
61 else
63 sReturn.push_back(current.toString());
64 current.setLength(0);
67 return sReturn;
70 sal_Int32 lcl_getAutoIncrementDefault(const OUString& sColumnDef)
72 // TODO what if there are more spaces?
73 if (sColumnDef.indexOf("GENERATED BY DEFAULT AS IDENTITY") > 0)
75 // TODO parse starting sequence stated by "START WITH"
76 return 0;
78 return -1;
81 OUString lcl_getDefaultValue(const OUString& sColumnDef)
83 constexpr char DEFAULT_KW[] = "DEFAULT";
84 auto nDefPos = sColumnDef.indexOf(DEFAULT_KW);
85 if (nDefPos > 0 && lcl_getAutoIncrementDefault(sColumnDef) < 0)
87 const OUString& fromDefault = sColumnDef.copy(nDefPos + sizeof(DEFAULT_KW)).trim();
89 // next word is the value
90 auto nNextSpace = fromDefault.indexOf(" ");
91 return nNextSpace > 0 ? fromDefault.copy(0, fromDefault.indexOf(" ")) : fromDefault;
93 return OUString{};
96 bool lcl_isNullable(const OUString& sColumnDef) { return sColumnDef.indexOf("NOT NULL") < 0; }
98 bool lcl_isPrimaryKey(const OUString& sColumnDef) { return sColumnDef.indexOf("PRIMARY KEY") >= 0; }
100 sal_Int32 lcl_getDataTypeFromHsql(const OUString& sTypeName)
102 if (sTypeName == "CHAR")
103 return DataType::CHAR;
104 else if (sTypeName == "VARCHAR" || sTypeName == "VARCHAR_IGNORECASE")
105 return DataType::VARCHAR;
106 else if (sTypeName == "TINYINT")
107 return DataType::TINYINT;
108 else if (sTypeName == "SMALLINT")
109 return DataType::SMALLINT;
110 else if (sTypeName == "INTEGER")
111 return DataType::INTEGER;
112 else if (sTypeName == "BIGINT")
113 return DataType::BIGINT;
114 else if (sTypeName == "NUMERIC")
115 return DataType::NUMERIC;
116 else if (sTypeName == "DECIMAL")
117 return DataType::DECIMAL;
118 else if (sTypeName == "BOOLEAN")
119 return DataType::BOOLEAN;
120 else if (sTypeName == "LONGVARCHAR")
121 return DataType::LONGVARCHAR;
122 else if (sTypeName == "LONGVARBINARY")
123 return DataType::LONGVARBINARY;
124 else if (sTypeName == "CLOB")
125 return DataType::CLOB;
126 else if (sTypeName == "BLOB")
127 return DataType::BLOB;
128 else if (sTypeName == "BINARY")
129 return DataType::BINARY;
130 else if (sTypeName == "VARBINARY")
131 return DataType::VARBINARY;
132 else if (sTypeName == "DATE")
133 return DataType::DATE;
134 else if (sTypeName == "TIME")
135 return DataType::TIME;
136 else if (sTypeName == "TIMESTAMP")
137 return DataType::TIMESTAMP;
138 else if (sTypeName == "DOUBLE")
139 return DataType::DOUBLE;
140 else if (sTypeName == "REAL")
141 return DataType::REAL;
142 else if (sTypeName == "FLOAT")
143 return DataType::FLOAT;
145 assert(false);
146 return -1;
149 void lcl_addDefaultParameters(std::vector<sal_Int32>& aParams, sal_Int32 eType)
151 if (eType == DataType::CHAR || eType == DataType::BINARY || eType == DataType::VARBINARY
152 || eType == DataType::VARCHAR)
153 aParams.push_back(8000); // from SQL standard
156 struct ColumnTypeParts
158 OUString typeName;
159 std::vector<sal_Int32> params;
163 * Separates full type descriptions (e.g. NUMERIC(5,4)) to type name (NUMERIC) and
164 * parameters (5,4)
166 ColumnTypeParts lcl_getColumnTypeParts(const OUString& sFullTypeName)
168 ColumnTypeParts parts;
169 auto nParenPos = sFullTypeName.indexOf("(");
170 if (nParenPos > 0)
172 parts.typeName = sFullTypeName.copy(0, nParenPos).trim();
173 OUString sParamStr
174 = sFullTypeName.copy(nParenPos + 1, sFullTypeName.indexOf(")") - nParenPos - 1);
175 auto sParams = string::split(sParamStr, sal_Unicode(u','));
176 for (const auto& sParam : sParams)
178 parts.params.push_back(sParam.toInt32());
181 else
183 parts.typeName = sFullTypeName.trim();
184 lcl_addDefaultParameters(parts.params, lcl_getDataTypeFromHsql(parts.typeName));
186 return parts;
189 } // unnamed namespace
191 namespace dbahsql
193 CreateStmtParser::CreateStmtParser() {}
195 void CreateStmtParser::parsePrimaryKeys(const OUString& sPrimaryPart)
197 sal_Int32 nParenPos = sPrimaryPart.indexOf("(");
198 if (nParenPos > 0)
200 OUString sParamStr
201 = sPrimaryPart.copy(nParenPos + 1, sPrimaryPart.lastIndexOf(")") - nParenPos - 1);
202 auto sParams = string::split(sParamStr, sal_Unicode(u','));
203 for (const auto& sParam : sParams)
205 m_PrimaryKeys.push_back(sParam);
210 void CreateStmtParser::parseColumnPart(const OUString& sColumnPart)
212 auto sColumns = lcl_splitColumnPart(sColumnPart);
213 for (const OUString& sColumn : sColumns)
215 if (sColumn.startsWithIgnoreAsciiCase("PRIMARY KEY"))
217 parsePrimaryKeys(sColumn);
218 continue;
221 if (sColumn.startsWithIgnoreAsciiCase("CONSTRAINT"))
223 m_aForeignParts.push_back(sColumn);
224 continue;
227 bool bIsQuoteUsedForColumnName(sColumn[0] == '\"');
229 // find next quote after the initial quote
230 // or next space if quote isn't used as delimiter
231 auto nEndColumnName
232 = bIsQuoteUsedForColumnName ? sColumn.indexOf("\"", 1) + 1 : sColumn.indexOf(" ");
233 OUString rColumnName = sColumn.copy(0, nEndColumnName);
235 const OUString& sFromTypeName = sColumn.copy(nEndColumnName).trim();
237 // Now let's manage the column type
238 // search next space to get the whole type name
239 // eg: INTEGER, VARCHAR(10), DECIMAL(6,3)
240 auto nNextSpace = sFromTypeName.indexOf(" ");
241 OUString sFullTypeName;
242 if (nNextSpace > 0)
243 sFullTypeName = sFromTypeName.copy(0, nNextSpace);
244 // perhaps column type corresponds to the last info here
245 else
246 sFullTypeName = sFromTypeName;
248 ColumnTypeParts typeParts = lcl_getColumnTypeParts(sFullTypeName);
250 bool bCaseInsensitive = typeParts.typeName.indexOf("IGNORECASE") >= 0;
251 bool isPrimaryKey = lcl_isPrimaryKey(sColumn);
253 if (isPrimaryKey)
254 m_PrimaryKeys.push_back(rColumnName);
256 const OUString sColumnWithoutName = sColumn.copy(sColumn.indexOf(typeParts.typeName));
258 ColumnDefinition aColDef(rColumnName, lcl_getDataTypeFromHsql(typeParts.typeName),
259 typeParts.params, isPrimaryKey,
260 lcl_getAutoIncrementDefault(sColumnWithoutName),
261 lcl_isNullable(sColumnWithoutName), bCaseInsensitive,
262 lcl_getDefaultValue(sColumnWithoutName));
264 m_aColumns.push_back(aColDef);
268 void CreateStmtParser::parse(const OUString& sSql)
270 // TODO Foreign keys
271 if (!sSql.startsWith("CREATE"))
273 SAL_WARN("dbaccess", "Not a create statement");
274 return;
277 m_sTableName = utils::getTableNameFromStmt(sSql);
278 OUString sColumnPart = lcl_getColumnPart(sSql);
279 parseColumnPart(sColumnPart);
282 } // namespace dbahsql
284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */