1#include "duckdb/parser/statement/pragma_statement.hpp"
2#include "duckdb/parser/transformer.hpp"
3#include "duckdb/parser/expression/constant_expression.hpp"
4#include "duckdb/parser/expression/comparison_expression.hpp"
5#include "duckdb/execution/expression_executor.hpp"
6#include "duckdb/parser/statement/set_statement.hpp"
7#include "duckdb/common/case_insensitive_map.hpp"
8#include "duckdb/parser/expression/columnref_expression.hpp"
9
10namespace duckdb {
11
12unique_ptr<SQLStatement> Transformer::TransformPragma(duckdb_libpgquery::PGPragmaStmt &stmt) {
13 auto result = make_uniq<PragmaStatement>();
14 auto &info = *result->info;
15
16 info.name = stmt.name;
17 // parse the arguments, if any
18 if (stmt.args) {
19 for (auto cell = stmt.args->head; cell != nullptr; cell = cell->next) {
20 auto node = PGPointerCast<duckdb_libpgquery::PGNode>(ptr: cell->data.ptr_value);
21 auto expr = TransformExpression(node);
22
23 if (expr->type == ExpressionType::COMPARE_EQUAL) {
24 auto &comp = expr->Cast<ComparisonExpression>();
25 if (comp.right->type != ExpressionType::VALUE_CONSTANT) {
26 throw ParserException("Named parameter requires a constant on the RHS");
27 }
28 if (comp.left->type != ExpressionType::COLUMN_REF) {
29 throw ParserException("Named parameter requires a column reference on the LHS");
30 }
31 auto &columnref = comp.left->Cast<ColumnRefExpression>();
32 auto &constant = comp.right->Cast<ConstantExpression>();
33 info.named_parameters[columnref.GetName()] = constant.value;
34 } else if (node->type == duckdb_libpgquery::T_PGAConst) {
35 auto constant = TransformConstant(c&: *PGPointerCast<duckdb_libpgquery::PGAConst>(ptr: node.get()));
36 info.parameters.push_back(x: (constant->Cast<ConstantExpression>()).value);
37 } else if (expr->type == ExpressionType::COLUMN_REF) {
38 auto &colref = expr->Cast<ColumnRefExpression>();
39 if (!colref.IsQualified()) {
40 info.parameters.emplace_back(args: colref.GetColumnName());
41 } else {
42 info.parameters.emplace_back(args: expr->ToString());
43 }
44 } else {
45 info.parameters.emplace_back(args: expr->ToString());
46 }
47 }
48 }
49 // now parse the pragma type
50 switch (stmt.kind) {
51 case duckdb_libpgquery::PG_PRAGMA_TYPE_NOTHING: {
52 if (!info.parameters.empty() || !info.named_parameters.empty()) {
53 throw InternalException("PRAGMA statement that is not a call or assignment cannot contain parameters");
54 }
55 break;
56 case duckdb_libpgquery::PG_PRAGMA_TYPE_ASSIGNMENT:
57 if (info.parameters.size() != 1) {
58 throw InternalException("PRAGMA statement with assignment should contain exactly one parameter");
59 }
60 if (!info.named_parameters.empty()) {
61 throw InternalException("PRAGMA statement with assignment cannot have named parameters");
62 }
63 // SQLite does not distinguish between:
64 // "PRAGMA table_info='integers'"
65 // "PRAGMA table_info('integers')"
66 // for compatibility, any pragmas that match the SQLite ones are parsed as calls
67 case_insensitive_set_t sqlite_compat_pragmas {"table_info"};
68 if (sqlite_compat_pragmas.find(x: info.name) != sqlite_compat_pragmas.end()) {
69 break;
70 }
71 auto set_statement = make_uniq<SetVariableStatement>(args&: info.name, args&: info.parameters[0], args: SetScope::AUTOMATIC);
72 return std::move(set_statement);
73 }
74 case duckdb_libpgquery::PG_PRAGMA_TYPE_CALL:
75 break;
76 default:
77 throw InternalException("Unknown pragma type");
78 }
79
80 return std::move(result);
81}
82
83} // namespace duckdb
84