Skip to content

Commit d3f5eac

Browse files
committed
Move Lua code for setting up tables into their own file
1 parent c42e200 commit d3f5eac

File tree

5 files changed

+320
-270
lines changed

5 files changed

+320
-270
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ if (WITH_LUA)
5252
flex-table-column.cpp
5353
flex-lua-geom.cpp
5454
flex-lua-index.cpp
55+
flex-lua-table.cpp
5556
flex-write.cpp
5657
geom-transform.cpp
5758
lua-utils.cpp

src/flex-lua-table.cpp

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
/**
2+
* SPDX-License-Identifier: GPL-2.0-or-later
3+
*
4+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
5+
*
6+
* Copyright (C) 2006-2023 by the osm2pgsql developer community.
7+
* For a full list of authors see the git log.
8+
*/
9+
10+
#include "flex-lua-index.hpp"
11+
#include "flex-lua-table.hpp"
12+
#include "lua-utils.hpp"
13+
#include "flex-table.hpp"
14+
#include "pgsql-capabilities.hpp"
15+
16+
#include <lua.hpp>
17+
18+
static void check_tablespace(std::string const &tablespace)
19+
{
20+
if (!has_tablespace(tablespace)) {
21+
throw fmt_error(
22+
"Tablespace '{0}' not available."
23+
" Use 'CREATE TABLESPACE \"{0}\" ...;' to create it.",
24+
tablespace);
25+
}
26+
}
27+
28+
static flex_table_t &create_flex_table(lua_State *lua_state,
29+
std::vector<flex_table_t> *tables)
30+
{
31+
std::string const table_name =
32+
luaX_get_table_string(lua_state, "name", -1, "The table");
33+
34+
check_identifier(table_name, "table names");
35+
36+
if (util::find_by_name(*tables, table_name)) {
37+
throw fmt_error("Table with name '{}' already exists.", table_name);
38+
}
39+
40+
auto &new_table = tables->emplace_back(table_name);
41+
42+
lua_pop(lua_state, 1); // "name"
43+
44+
// optional "schema" field
45+
lua_getfield(lua_state, -1, "schema");
46+
if (lua_isstring(lua_state, -1)) {
47+
std::string const schema = lua_tostring(lua_state, -1);
48+
check_identifier(schema, "schema field");
49+
if (!has_schema(schema)) {
50+
throw fmt_error("Schema '{0}' not available."
51+
" Use 'CREATE SCHEMA \"{0}\";' to create it.",
52+
schema);
53+
}
54+
new_table.set_schema(schema);
55+
}
56+
lua_pop(lua_state, 1);
57+
58+
// optional "cluster" field
59+
lua_getfield(lua_state, -1, "cluster");
60+
int const cluster_type = lua_type(lua_state, -1);
61+
if (cluster_type == LUA_TSTRING) {
62+
std::string const cluster = lua_tostring(lua_state, -1);
63+
if (cluster == "auto") {
64+
new_table.set_cluster_by_geom(true);
65+
} else if (cluster == "no") {
66+
new_table.set_cluster_by_geom(false);
67+
} else {
68+
throw fmt_error("Unknown value '{}' for 'cluster' table option"
69+
" (use 'auto' or 'no').",
70+
cluster);
71+
}
72+
} else if (cluster_type == LUA_TNIL) {
73+
// ignore
74+
} else {
75+
throw std::runtime_error{
76+
"Unknown value for 'cluster' table option: Must be string."};
77+
}
78+
lua_pop(lua_state, 1);
79+
80+
// optional "data_tablespace" field
81+
lua_getfield(lua_state, -1, "data_tablespace");
82+
if (lua_isstring(lua_state, -1)) {
83+
std::string const tablespace = lua_tostring(lua_state, -1);
84+
check_identifier(tablespace, "data_tablespace field");
85+
check_tablespace(tablespace);
86+
new_table.set_data_tablespace(tablespace);
87+
}
88+
lua_pop(lua_state, 1);
89+
90+
// optional "index_tablespace" field
91+
lua_getfield(lua_state, -1, "index_tablespace");
92+
if (lua_isstring(lua_state, -1)) {
93+
std::string const tablespace = lua_tostring(lua_state, -1);
94+
check_identifier(tablespace, "index_tablespace field");
95+
check_tablespace(tablespace);
96+
new_table.set_index_tablespace(tablespace);
97+
}
98+
lua_pop(lua_state, 1);
99+
100+
return new_table;
101+
}
102+
103+
static void setup_flex_table_id_columns(lua_State *lua_state,
104+
flex_table_t *table)
105+
{
106+
assert(lua_state);
107+
assert(table);
108+
109+
lua_getfield(lua_state, -1, "ids");
110+
if (lua_type(lua_state, -1) != LUA_TTABLE) {
111+
log_warn("Table '{}' doesn't have an id column. Two-stage"
112+
" processing, updates and expire will not work!",
113+
table->name());
114+
lua_pop(lua_state, 1); // ids
115+
return;
116+
}
117+
118+
std::string const type{
119+
luaX_get_table_string(lua_state, "type", -1, "The ids field")};
120+
lua_pop(lua_state, 1); // "type"
121+
122+
if (type == "node") {
123+
table->set_id_type(osmium::item_type::node);
124+
} else if (type == "way") {
125+
table->set_id_type(osmium::item_type::way);
126+
} else if (type == "relation") {
127+
table->set_id_type(osmium::item_type::relation);
128+
} else if (type == "area") {
129+
table->set_id_type(osmium::item_type::area);
130+
} else if (type == "any") {
131+
table->set_id_type(osmium::item_type::undefined);
132+
lua_getfield(lua_state, -1, "type_column");
133+
if (lua_isstring(lua_state, -1)) {
134+
std::string const column_name =
135+
lua_tolstring(lua_state, -1, nullptr);
136+
check_identifier(column_name, "column names");
137+
auto &column = table->add_column(column_name, "id_type", "");
138+
column.set_not_null();
139+
} else if (!lua_isnil(lua_state, -1)) {
140+
throw std::runtime_error{"type_column must be a string or nil."};
141+
}
142+
lua_pop(lua_state, 1); // "type_column"
143+
} else {
144+
throw fmt_error("Unknown ids type: {}.", type);
145+
}
146+
147+
std::string const name =
148+
luaX_get_table_string(lua_state, "id_column", -1, "The ids field");
149+
lua_pop(lua_state, 1); // "id_column"
150+
check_identifier(name, "column names");
151+
152+
std::string const create_index = luaX_get_table_string(
153+
lua_state, "create_index", -1, "The ids field", "auto");
154+
lua_pop(lua_state, 1); // "create_index"
155+
if (create_index == "always") {
156+
table->set_always_build_id_index();
157+
} else if (create_index != "auto") {
158+
throw fmt_error("Unknown value '{}' for 'create_index' field of ids",
159+
create_index);
160+
}
161+
162+
auto &column = table->add_column(name, "id_num", "");
163+
column.set_not_null();
164+
lua_pop(lua_state, 1); // "ids"
165+
}
166+
167+
static void setup_flex_table_columns(lua_State *lua_state, flex_table_t *table)
168+
{
169+
assert(lua_state);
170+
assert(table);
171+
172+
lua_getfield(lua_state, -1, "columns");
173+
if (lua_type(lua_state, -1) != LUA_TTABLE) {
174+
throw fmt_error("No 'columns' field (or not an array) in table '{}'.",
175+
table->name());
176+
}
177+
178+
if (!luaX_is_array(lua_state)) {
179+
throw std::runtime_error{"The 'columns' field must contain an array."};
180+
}
181+
std::size_t num_columns = 0;
182+
luaX_for_each(lua_state, [&]() {
183+
if (!lua_istable(lua_state, -1)) {
184+
throw std::runtime_error{
185+
"The entries in the 'columns' array must be tables."};
186+
}
187+
188+
char const *const type = luaX_get_table_string(lua_state, "type", -1,
189+
"Column entry", "text");
190+
char const *const name =
191+
luaX_get_table_string(lua_state, "column", -2, "Column entry");
192+
check_identifier(name, "column names");
193+
char const *const sql_type = luaX_get_table_string(
194+
lua_state, "sql_type", -3, "Column entry", "");
195+
196+
auto &column = table->add_column(name, type, sql_type);
197+
lua_pop(lua_state, 3); // "type", "column", "sql_type"
198+
199+
column.set_not_null(luaX_get_table_bool(lua_state, "not_null", -1,
200+
"Entry 'not_null'", false));
201+
lua_pop(lua_state, 1); // "not_null"
202+
203+
column.set_create_only(luaX_get_table_bool(
204+
lua_state, "create_only", -1, "Entry 'create_only'", false));
205+
lua_pop(lua_state, 1); // "create_only"
206+
207+
lua_getfield(lua_state, -1, "projection");
208+
if (!lua_isnil(lua_state, -1)) {
209+
if (column.is_geometry_column() ||
210+
column.type() == table_column_type::area) {
211+
column.set_projection(lua_tostring(lua_state, -1));
212+
} else {
213+
throw std::runtime_error{"Projection can only be set on "
214+
"geometry and area columns."};
215+
}
216+
}
217+
lua_pop(lua_state, 1); // "projection"
218+
219+
++num_columns;
220+
});
221+
222+
if (num_columns == 0 && !table->has_id_column()) {
223+
throw fmt_error("No columns defined for table '{}'.", table->name());
224+
}
225+
226+
lua_pop(lua_state, 1); // "columns"
227+
}
228+
229+
static void setup_flex_table_indexes(lua_State *lua_state, flex_table_t *table,
230+
bool updatable)
231+
{
232+
assert(lua_state);
233+
assert(table);
234+
235+
lua_getfield(lua_state, -1, "indexes");
236+
if (lua_type(lua_state, -1) == LUA_TNIL) {
237+
if (table->has_geom_column()) {
238+
auto &index = table->add_index("gist");
239+
index.set_columns(table->geom_column().name());
240+
241+
if (!updatable) {
242+
// If database can not be updated, use fillfactor 100.
243+
index.set_fillfactor(100);
244+
}
245+
index.set_tablespace(table->index_tablespace());
246+
}
247+
lua_pop(lua_state, 1); // "indexes"
248+
return;
249+
}
250+
251+
if (lua_type(lua_state, -1) != LUA_TTABLE) {
252+
throw fmt_error("The 'indexes' field in definition of"
253+
" table '{}' is not an array.",
254+
table->name());
255+
}
256+
257+
if (!luaX_is_array(lua_state)) {
258+
throw std::runtime_error{"The 'indexes' field must contain an array."};
259+
}
260+
261+
luaX_for_each(lua_state, [&]() {
262+
if (!lua_istable(lua_state, -1)) {
263+
throw std::runtime_error{
264+
"The entries in the 'indexes' array must be Lua tables."};
265+
}
266+
267+
flex_lua_setup_index(lua_state, table);
268+
});
269+
270+
lua_pop(lua_state, 1); // "indexes"
271+
}
272+
273+
int setup_flex_table(lua_State *lua_state, std::vector<flex_table_t> *tables,
274+
bool updatable)
275+
{
276+
if (lua_type(lua_state, 1) != LUA_TTABLE) {
277+
throw std::runtime_error{
278+
"Argument #1 to 'define_table' must be a table."};
279+
}
280+
281+
auto &new_table = create_flex_table(lua_state, tables);
282+
setup_flex_table_id_columns(lua_state, &new_table);
283+
setup_flex_table_columns(lua_state, &new_table);
284+
setup_flex_table_indexes(lua_state, &new_table, updatable);
285+
286+
void *ptr = lua_newuserdata(lua_state, sizeof(std::size_t));
287+
auto *num = new (ptr) std::size_t{};
288+
*num = tables->size() - 1;
289+
luaL_getmetatable(lua_state, osm2pgsql_table_name);
290+
lua_setmetatable(lua_state, -2);
291+
292+
return 1;
293+
}

src/flex-lua-table.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef OSM2PGSQL_FLEX_LUA_TABLE_HPP
2+
#define OSM2PGSQL_FLEX_LUA_TABLE_HPP
3+
4+
/**
5+
* SPDX-License-Identifier: GPL-2.0-or-later
6+
*
7+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
8+
*
9+
* Copyright (C) 2006-2023 by the osm2pgsql developer community.
10+
* For a full list of authors see the git log.
11+
*/
12+
13+
#include <vector>
14+
15+
class flex_table_t;
16+
struct lua_State;
17+
18+
static char const *const osm2pgsql_table_name = "osm2pgsql.Table";
19+
20+
int setup_flex_table(lua_State *lua_state, std::vector<flex_table_t> *tables,
21+
bool updatable);
22+
23+
#endif // OSM2PGSQL_FLEX_LUA_TABLE_HPP

0 commit comments

Comments
 (0)