summaryrefslogtreecommitdiff
path: root/src/database/postgresql_statement.hpp
blob: 571c8f142019f0ec7319bd1af564133df8b90e3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#pragma once

#include <database/statement.hpp>

#include <logger/logger.hpp>

#include <libpq-fe.h>

class PostgresqlStatement: public Statement
{
 public:
  PostgresqlStatement(std::string body, PGconn*const conn):
      body(std::move(body)),
      conn(conn)
  {}
  ~PostgresqlStatement()
  {
    PQclear(this->result);
    this->result = nullptr;
  }
  PostgresqlStatement(const PostgresqlStatement&) = delete;
  PostgresqlStatement& operator=(const PostgresqlStatement&) = delete;
  PostgresqlStatement(PostgresqlStatement&& other) = delete;
  PostgresqlStatement& operator=(PostgresqlStatement&& other) = delete;

  StepResult step() override final
  {
    if (!this->executed)
      {
        this->current_tuple = 0;
        this->executed = true;
        if (!this->execute())
          return StepResult::Error;
      }
    else
      {
        this->current_tuple++;
      }
    if (this->current_tuple < PQntuples(this->result))
      return StepResult::Row;
    return StepResult::Done;
  }

  int64_t get_column_int64(const int col) override
  {
    const char* result = PQgetvalue(this->result, this->current_tuple, col);
    std::istringstream iss;
    iss.str(result);
    int64_t res;
    iss >> res;
    return res;
  }
  std::string get_column_text(const int col) override
  {
    const char* result = PQgetvalue(this->result, this->current_tuple, col);
    return result;
  }
  int get_column_int(const int col) override
  {
    const char* result = PQgetvalue(this->result, this->current_tuple, col);
    std::istringstream iss;
    iss.str(result);
    int res;
    iss >> res;
    return res;
  }

  void bind(std::vector<std::string> params) override
  {

    this->params = std::move(params);
  }

  bool bind_text(const int, const std::string& data) override
  {
    this->params.push_back(data);
    return true;
  }
  bool bind_int64(const int, const std::int64_t value) override
  {
    this->params.push_back(std::to_string(value));
    return true;
  }
  bool bind_null(const int) override
  {
    this->params.push_back("NULL");
    return true;
  }

 private:

private:
  bool execute()
  {
    std::vector<const char*> params;
    params.reserve(this->params.size());

    for (const auto& param: this->params)
      params.push_back(param.data());
    const int param_size = static_cast<int>(this->params.size());
    this->result = PQexecParams(this->conn, this->body.data(),
                                param_size,
                                nullptr,
                                params.data(),
                                nullptr,
                                nullptr,
                                0);
    const auto status = PQresultStatus(this->result);
    if (status != PGRES_TUPLES_OK && status != PGRES_COMMAND_OK)
      {
        log_error("Failed to execute command: ", PQresultErrorMessage(this->result));
        return false;
      }
    return true;
  }

  bool executed{false};
  std::string body;
  PGconn*const conn;
  std::vector<std::string> params;
  PGresult* result{nullptr};
  int current_tuple{0};
};