5 #ifndef HAVE_BOOST_REGEX
8 #include <boost/regex.hpp>
11 using boost::regex_match;
16 static regex e_timeout(
"ERROR: canceling statement due to statement timeout(\n|.)*");
17 static regex e_syntax(
"ERROR: syntax error at or near(\n|.)*");
24 cerr <<
"unknown type: " << rvalue->name << endl;
38 if (name ==
"anyarray") {
39 return t->typelem_ != InvalidOid;
40 }
else if (name ==
"anynonarray") {
41 return t->typelem_ == InvalidOid;
42 }
else if(name ==
"anyenum") {
43 return t->typtype_ ==
'e';
44 }
else if (name ==
"any") {
46 }
else if (name ==
"anyelement") {
47 return t->typelem_ == InvalidOid;
48 }
else if (name ==
"anyrange") {
49 return t->typtype_ ==
'r';
50 }
else if (name ==
"record") {
51 return t->typtype_ ==
'c';
52 }
else if (name ==
"cstring") {
59 throw std::logic_error(
"unknown typtype");
63 dut_pqxx::dut_pqxx(std::string conninfo)
66 c.set_variable(
"statement_timeout",
"'1s'");
67 c.set_variable(
"client_min_messages",
"'ERROR'");
68 c.set_variable(
"application_name",
"'" PACKAGE
"::dut'");
71 void dut_pqxx::test(
const std::string &stmt)
80 }
catch (
const pqxx::failure &e) {
81 if ((
dynamic_cast<const pqxx::broken_connection *
>(&e))) {
86 if (regex_match(e.what(), e_timeout))
88 else if (regex_match(e.what(), e_syntax))
96 schema_pqxx::schema_pqxx(std::string &conninfo,
bool no_catalog) : c(conninfo)
98 c.set_variable(
"application_name",
"'" PACKAGE
"::schema'");
101 pqxx::result r = w.exec(
"select version()");
102 version = r[0][0].as<
string>();
104 r = w.exec(
"SHOW server_version_num");
105 version_num = r[0][0].as<
int>();
108 string procedure_is_aggregate = version_num < 110000 ?
"proisagg" :
"prokind = 'a'";
109 string procedure_is_window = version_num < 110000 ?
"proiswindow" :
"prokind = 'w'";
111 cerr <<
"Loading types...";
113 r = w.exec(
"select quote_ident(typname), oid, typdelim, typrelid, typelem, typarray, typtype "
116 for (
auto row = r.begin(); row != r.end(); ++row) {
117 string name(row[0].as<string>());
118 OID oid(row[1].as<OID>());
119 string typdelim(row[2].as<string>());
120 OID typrelid(row[3].as<OID>());
121 OID typelem(row[4].as<OID>());
122 OID typarray(row[5].as<OID>());
123 string typtype(row[6].as<string>());
129 pg_type *t =
new pg_type(name,oid,typdelim[0],typrelid, typelem, typarray, typtype[0]);
135 booltype = name2type[
"bool"];
136 inttype = name2type[
"int4"];
138 internaltype = name2type[
"internal"];
139 arraytype = name2type[
"anyarray"];
141 cerr <<
"done." << endl;
143 cerr <<
"Loading tables...";
144 r = w.exec(
"select table_name, "
146 "is_insertable_into, "
148 "from information_schema.tables");
150 for (
auto row = r.begin(); row != r.end(); ++row) {
151 string schema(row[1].as<string>());
152 string insertable(row[2].as<string>());
153 string table_type(row[3].as<string>());
155 if (no_catalog && ((
schema ==
"pg_catalog") || (
schema ==
"information_schema")))
158 tables.push_back(
table(row[0].as<string>(),
160 ((insertable ==
"YES") ?
true :
false),
161 ((table_type ==
"BASE TABLE") ?
true :
false)));
164 cerr <<
"done." << endl;
166 cerr <<
"Loading columns and constraints...";
168 for (
auto t = tables.begin(); t != tables.end(); ++t) {
169 string q(
"select attname, "
171 "from pg_attribute join pg_class c on( c.oid = attrelid ) "
172 "join pg_namespace n on n.oid = relnamespace "
173 "where not attisdropped "
174 "and attname not in "
175 "('xmin', 'xmax', 'ctid', 'cmin', 'cmax', 'tableoid', 'oid') ");
176 q +=
" and relname = " + w.quote(t->name);
177 q +=
" and nspname = " + w.quote(t->schema);
181 column c(row[0].as<string>(), oid2type[row[1].as<OID>()]);
182 t->columns().push_back(c);
185 q =
"select conname from pg_class t "
186 "join pg_constraint c on (t.oid = c.conrelid) "
187 "where contype in ('f', 'u', 'p') ";
188 q +=
" and relnamespace = " " (select oid from pg_namespace where nspname = " + w.quote(t->schema) +
")";
189 q +=
" and relname = " + w.quote(t->name);
191 for (
auto row : w.exec(q)) {
192 t->constraints.push_back(row[0].as<string>());
196 cerr <<
"done." << endl;
198 cerr <<
"Loading operators...";
200 r = w.exec(
"select oprname, oprleft,"
201 "oprright, oprresult "
202 "from pg_catalog.pg_operator "
203 "where 0 not in (oprresult, oprright, oprleft) ");
205 op o(row[0].as<string>(),
206 oid2type[row[1].as<OID>()],
207 oid2type[row[2].as<OID>()],
208 oid2type[row[3].as<OID>()]);
209 register_operator(o);
212 cerr <<
"done." << endl;
214 cerr <<
"Loading routines...";
215 r = w.exec(
"select (select nspname from pg_namespace where oid = pronamespace), oid, prorettype, proname "
217 "where prorettype::regtype::text not in ('event_trigger', 'trigger', 'opaque', 'internal') "
218 "and proname <> 'pg_event_trigger_table_rewrite_reason' "
219 "and proname <> 'pg_event_trigger_table_rewrite_oid' "
220 "and proname !~ '^ri_fkey_' "
221 "and not (proretset or " + procedure_is_aggregate +
" or " + procedure_is_window +
") ");
224 routine proc(row[0].as<string>(),
226 oid2type[row[2].as<long>()],
227 row[3].as<string>());
228 register_routine(proc);
231 cerr <<
"done." << endl;
233 cerr <<
"Loading routine parameters...";
235 for (
auto &proc : routines) {
236 string q(
"select unnest(proargtypes) "
238 q +=
" where oid = " + w.quote(proc.specific_name);
242 sqltype *t = oid2type[row[0].as<OID>()];
244 proc.argtypes.push_back(t);
247 cerr <<
"done." << endl;
249 cerr <<
"Loading aggregates...";
250 r = w.exec(
"select (select nspname from pg_namespace where oid = pronamespace), oid, prorettype, proname "
252 "where prorettype::regtype::text not in ('event_trigger', 'trigger', 'opaque', 'internal') "
253 "and proname not in ('pg_event_trigger_table_rewrite_reason') "
254 "and proname not in ('percentile_cont', 'dense_rank', 'cume_dist', "
255 "'rank', 'test_rank', 'percent_rank', 'percentile_disc', 'mode', 'test_percentile_disc') "
256 "and proname !~ '^ri_fkey_' "
257 "and not (proretset or " + procedure_is_window +
") "
258 "and " + procedure_is_aggregate);
261 routine proc(row[0].as<string>(),
263 oid2type[row[2].as<OID>()],
264 row[3].as<string>());
265 register_aggregate(proc);
268 cerr <<
"done." << endl;
270 cerr <<
"Loading aggregate parameters...";
272 for (
auto &proc : aggregates) {
273 string q(
"select unnest(proargtypes) "
275 q +=
" where oid = " + w.quote(proc.specific_name);
279 sqltype *t = oid2type[row[0].as<OID>()];
281 proc.argtypes.push_back(t);
284 cerr <<
"done." << endl;
290 void dut_libpq_notice_rx(
void *arg,
const PGresult *res);
293 void dut_libpq_notice_rx(
void *arg,
const PGresult *res)
299 void dut_libpq::connect(std::string &conninfo)
304 conn = PQconnectdb(conninfo.c_str());
305 if (PQstatus(conn) != CONNECTION_OK)
307 char *errmsg = PQerrorMessage(conn);
312 command(
"set statement_timeout to '1s'");
313 command(
"set client_min_messages to 'ERROR';");
314 command(
"set application_name to '" PACKAGE
"::dut';");
316 PQsetNoticeReceiver(conn, dut_libpq_notice_rx, (
void *) 0);
319 dut_libpq::dut_libpq(std::string conninfo)
320 : conninfo_(conninfo)
325 void dut_libpq::command(
const std::string &stmt)
329 PGresult *res = PQexec(conn, stmt.c_str());
331 switch (PQresultStatus(res)) {
333 case PGRES_FATAL_ERROR:
336 const char *errmsg = PQresultErrorMessage(res);
337 if (!errmsg || !strlen(errmsg))
338 errmsg = PQerrorMessage(conn);
340 const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
341 if (!sqlstate || !strlen(sqlstate))
342 sqlstate = (CONNECTION_OK != PQstatus(conn)) ?
"08000" :
"?????";
344 std::string error_string(errmsg);
345 std::string sqlstate_string(sqlstate);
348 if (CONNECTION_OK != PQstatus(conn)) {
351 throw dut::broken(error_string.c_str(), sqlstate_string.c_str());
353 if (sqlstate_string ==
"42601")
354 throw dut::syntax(error_string.c_str(), sqlstate_string.c_str());
356 throw dut::failure(error_string.c_str(), sqlstate_string.c_str());
359 case PGRES_NONFATAL_ERROR:
360 case PGRES_TUPLES_OK:
361 case PGRES_SINGLE_TUPLE:
362 case PGRES_COMMAND_OK:
368 void dut_libpq::test(
const std::string &stmt)
370 command(
"ROLLBACK;");
372 command(stmt.c_str());
373 command(
"ROLLBACK;");
schema and dut classes for PostgreSQL
virtual bool consistent(struct sqltype *rvalue)
This function is used to model postgres-style pseudotypes.