blob: 9634fa36309d1853ce43d46c2379b438299363dc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cursor.h"
#include "ignite/protocol/writer.h"
#include "ignite/protocol/sql/column_meta.h"
#include <Python.h>
class node_connection;
/**
* SQL parameter.
*/
struct sql_parameter {
bool nullable;
ignite::ignite_type data_type;
std::int32_t scale;
std::int32_t precision;
};
/**
* Python parameter list set.
*/
class py_parameter_set final {
public:
/**
* Constructor for the case of a single parameter row.
*
* @param row_size Number of params in a single row.
* @param params Python parameter sequence list.
*/
py_parameter_set(Py_ssize_t row_size, PyObject *params)
: m_size(0)
, m_row_size(row_size)
, m_params(params) {}
/**
* Constructor for the case of multiple parameter rows.
*
* @param size Size number of rows to insert.
* @param row_size Number of params in a single row.
* @param params Python parameter sequence list.
*/
py_parameter_set(Py_ssize_t size, Py_ssize_t row_size, PyObject *params)
: m_size(size)
, m_row_size(row_size)
, m_params(params) {}
/**
* Write only the first row of the param set using a provided writer.
*
* @param writer Writer.
*/
void write(ignite::protocol::writer &writer) const;
/**
* Check if is the batch query.
*
* @return @c true if is the batch query.
*/
[[nodiscard]] bool is_batch_query() const {
return m_size > 0;
}
private:
/**
* Write rows of the param set in the interval [begin, end) using the provided writer.
*
* @param writer Writer.
* @param begin Beginning of the interval.
* @param end End of the interval.
* @param last Last page flag.
*/
void write(ignite::protocol::writer &writer, std::size_t begin, std::size_t end, bool last) const;
/** Rows number. */
Py_ssize_t m_size{0};
/** Row size. */
Py_ssize_t m_row_size{0};
/** Python sequence of parameters. */
PyObject *m_params{nullptr};
};
/**
* A result set cursor.
*/
class statement final {
public:
/**
* Constructor.
*
* @param connection Connection.
*/
explicit statement(node_connection &connection)
: m_connection(connection) { }
/**
* Destructor.
*/
~statement() {
close();
}
/**
* Close the statement.
*/
void close() noexcept;
/**
* Execute the statement.
* @param query SQL Query.
* @param params Parameters.
*/
void execute(const char *query, py_parameter_set &params);
/**
* Get the number of rows affected by the statement.
*
* @return Number of rows affected by the statement.
*/
[[nodiscard]] std::int64_t get_affected_rows() const { return m_rows_affected; }
/**
* Check if data is available.
*
* @return True if data is available.
*/
[[nodiscard]] bool is_data_available() const { return m_has_more_pages || (m_cursor && m_cursor->has_data()); }
/**
* Check if the query is executed.
*
* @return @c true if executed and @c false, otherwise.
*/
[[nodiscard]] bool is_executed() const { return m_executed; }
/**
* Get the current row.
*
* @return Row.
*/
[[nodiscard]] const std::vector<ignite::primitive> &get_current_row() const { return m_cursor->get_row(); }
/**
* Get column metadata.
*
* @return Column metadata.
*/
[[nodiscard]] const ignite::protocol::column_meta_vector *get_meta() {
if (!m_result_meta_available) {
update_meta();
if (!m_result_meta_available)
return nullptr;
}
return &m_result_meta;
}
/**
* Fetch next result row to application buffers.
*
* @return @c true if there was another row and @c false if there is no more data.
*/
bool fetch_next_row();
private:
/**
* Process affected keys array received from the server.
*
* @param affected_rows Affected keys.
* @param params Parameters.
*/
void process_affected_rows(const std::vector<std::int64_t> &affected_rows, py_parameter_set &params);
/**
* Set metadata for the result set.
*
* @param value Metadata.
*/
void set_resultset_meta(ignite::protocol::column_meta_vector value);
/**
* Make result set metadata request.
*
* @return Result.
*/
void update_meta();
/**
* Set metadata for params.
*
* @param value Metadata.
*/
void set_params_meta(std::vector<sql_parameter> value);
/** Connection associated with the statement. */
node_connection &m_connection;
/** SQL query. */
std::string m_query;
/** Parameter types. */
std::vector<sql_parameter> m_params_meta{};
/** Indicating if the query was executed. */
bool m_executed{false};
/** Parameter metadata is available. */
volatile bool m_params_meta_available{false};
/** Result set metadata is available */
volatile bool m_result_meta_available{false};
/** A result set metadata. */
ignite::protocol::column_meta_vector m_result_meta;
/** Query ID, nullopt when closed on server. */
std::optional<std::int64_t> m_query_id;
/** Indicate whether a result set is available. */
bool m_has_rowset{false};
/** Indicate whether there are more pages available on the server side. */
bool m_has_more_pages{false};
/** Indicate whether the query was applied. */
bool m_was_applied{false};
/** Number of rows affected. */
std::int64_t m_rows_affected{-1};
/** Cursor. */
std::unique_ptr<cursor> m_cursor;
};