Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to choose C++ type for Postgres built-in types? #290

Open
croja opened this issue Mar 1, 2021 · 5 comments
Open

How to choose C++ type for Postgres built-in types? #290

croja opened this issue Mar 1, 2021 · 5 comments
Assignees
Labels
feature feature request

Comments

@croja
Copy link

croja commented Mar 1, 2021

Which C++ type should I use if I want to read column of type "inet"? Is it as simple as using std::string for "text"?
Which actions must be performed to be able to read column value into variable of type boost::asio::ip::network_v4?

@thed636 thed636 self-assigned this Mar 2, 2021
@croja
Copy link
Author

croja commented Mar 3, 2021

#pragma once

#include <ozo/pg/definitions.h>
#include <ozo/io/send.h>
#include <ozo/io/recv.h>

#include <boost/asio.hpp>

namespace ozo {

// NOT TESTED!!!
template <>
struct send_impl<boost::asio::ip::network_v4> {
    template <typename OidMap>
    static ostream& apply(ostream& out, const OidMap&, const boost::asio::ip::network_v4& in) {
        std::uint8_t size_of_mask = sizeof(std::uint16_t);
        std::uint16_t mask = in.netmask().to_uint();
        write(out, size_of_mask);
        write(out, htons(mask));

        std::uint8_t size_of_address = sizeof(std::uint32_t);
        std::uint32_t address = in.address().to_uint();
        write(out, size_of_address);
        return write(out, address);
    }
};

template <>
struct recv_impl<boost::asio::ip::network_v4> {
    template <typename OidMap>
    static istream& apply(istream& in, size_type, const OidMap&, boost::asio::ip::network_v4& out) {
        std::uint8_t size_of_mask = 0;
        read(in, size_of_mask);
        assert(size_of_mask == sizeof(std::uint16_t));

        std::uint16_t mask = 0;
        read(in, mask);
        mask = ntohs(mask);

        std::uint8_t size_of_address = 0;
        read(in, size_of_address);
        assert(size_of_address == sizeof(std::uint32_t));

        std::uint32_t address = 0;
        read(in, address);

        out = boost::asio::ip::network_v4(boost::asio::ip::address_v4(address), mask);

        return in;
    }
};

}

OZO_PG_BIND_TYPE(boost::asio::ip::network_v4, "inet")

Found some examples in source code and tried to implement support for "inet". recv_impl seems to work (binary representation explored experimentally, not sure where I can find it's description)

Unfortunately I don't know how to test send_impl, failed to write INSERT query using boost::asio::ip::network_v4 variable.

@thed636
Copy link
Contributor

thed636 commented Mar 3, 2021

Hi!

Thanks for trying to implement the IO. Yes, this is very close to the proper implementation. A good description for the binary representation may be found here. Since the type has a dynamic size of the binary representation, the ozo::size_of_impl specialization is needed too. The ozo::size_of should return a size of binary representation for the type. So this is the reason for send failure.

I spent some time last night implementing a more general solution. So feel free to use your solution for a while until the out-of-the-box solution is on the way.

@croja
Copy link
Author

croja commented Mar 3, 2021

Thank you very much! It is great.

p.s. About send - I meant I don't know how to construct INSERT query passing network_v4 variables. All INSERT queries I found in sources contain hardcoded values. Maybe you can provide example how to construct insert query using variables?

I tried concatenate variable (analogous to SELECT example from documentation), but this doesn't compile:

using namespace boost::asio;
const ip::network_v4 net(ip::make_address_v4("127.0.0.0"), 8);
const auto query_insert = "INSERT INTO tbl (network) VALUES ('"_SQL  + net + "') RETURNING network"_SQL;

Maybe there other ways to trigger send_impl::apply() execution?

@thed636
Copy link
Contributor

thed636 commented Mar 3, 2021

Could you please share the compilation error?

Also, in the case of inet type of the network column, you do not need to quote variables, since they are transferred via the binary protocol, and all the type information being preserved.

@croja
Copy link
Author

croja commented Mar 3, 2021

Sorry! As you said, compilation error is related to missing ozo::size_of.
I had to check it again more carefully after your response.
Implemented size_of and error is gone.

p.s. Thank you for the library! I use boost::asio hard, and for me it is really enjoying to asynchronously access Postgres with little to no efforts, reusing io_context from my applications.

@thed636 thed636 added the feature feature request label Mar 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature feature request
Projects
None yet
Development

No branches or pull requests

2 participants