[v3][Dbo] How to read from a Set Returning Function (SRF) aka "table functions".

Added by Vincenzo Romano 6 months ago

I am in the process of replacing my own DB access library with Dbo.
I am on v3.3.12 with g++ (GCC) 8.2.1 20181127.
I have recompiled the whole Wt library myself with no errors.

I have a number of SRFs I need to read data from.
It seems I need to write code like this:

struct ConfigEntry {
  std::string k;
  std::string v;
  template<class Action> void persist( Action& a ) {
    Wt::Dbo::field( a,k,"k");
    Wt::Dbo::field( a,v,"v");
  }
};

...

Wt::Dbo::backend::Postgres dbBackEnd;
Wt::Dbo::Session dbSession;

...

void aFunction() {
  dbBackEnd.connect( std::string( dbconn ) );
  dbSession.setConnection( dbBackEnd );
  ...
  dbSession.mapClass<ConfigEntry>( "session_configuration()" );
  auto conf = dbSession.find<ConfigEntry>();
  ...
}

Is this correct? If not, what's the problem?

Anyway, this code fails at linkage time (I have -lwtdbo -lwtdbopostgres -lwt -lwthttp) with these messages:

/usr/bin/ld: /tmp/ccpHUsWJ.o: in function `setEntryPoints()':
init.cpp:(.text+0xfa): undefined reference to `void Wt::Dbo::Session::mapClass<ConfigEntry>(char const*)'
/usr/bin/ld: init.cpp:(.text+0x128): undefined reference to `Wt::Dbo::Query<Wt::Dbo::ptr<ConfigEntry>, Wt::Dbo::DynamicBinding> Wt::Dbo::Session::find<ConfigEntry, Wt::Dbo::DynamicBinding>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: init.cpp:(.text+0x143): undefined reference to `Wt::Dbo::Query<Wt::Dbo::ptr<ConfigEntry>, Wt::Dbo::DynamicBinding>::~Query()'

I am pretty sure this isn't a bug but something I am missing.

One thing that comes to my mind is that my compiler defaults to the "gnu++1" which should be the 2014 ISO C++ standard plus amendments plus the GNU enhancements.
In the error I read "__cxx11".
I have no way at the moment to test with a different compiler.

Any idea?


Replies (6)

RE: [v3][Dbo] How to read from a Set Returning Function (SRF) aka "table functions". - Added by lm at 6 months ago

I don't use Wt 3, but given the information you gave, I created the following example in Wt 4:

#include <iostream>
#include <Wt/Dbo/Dbo.h>
#include <Wt/Dbo/backend/Postgres.h>

struct ConfigEntry
{
    std::string k, v;
    template <class A>
    void persist (A& a)
    {
        Wt::Dbo::field(a,k,"k");
        Wt::Dbo::field(a,v,"v");
    }
};

Wt::Dbo::Session session;

int main()
{
    auto backend {std::make_unique<Wt::Dbo::backend::Postgres>()};
    backend->connect("dbcon");
    session.setConnection(std::move(backend));
    session.mapClass<ConfigEntry>("config()");
    auto conf = session.find<ConfigEntry>();
    return 0;
}
It's built using
g++ -I/usr/local/include/ src/main.cpp -L/usr/local/lib -lwtdbopostgres -lwtdbo
Let me know if you think there's something I can add that might recreate the linker problem.

RE: [v3][Dbo] How to read from a Set Returning Function (SRF) aka "table functions". - Added by Roel Standaert 6 months ago

lm at: wow, does that work?

I don't know if I can necessarily guarantee that this will always work:

session.mapClass<ConfigEntry>("config()");

Dbo treats what's between double quotes as the name of a table, so if it works then that's neat, I guess, but I think a view would probably work better. You can of course always turn a function call with no arguments or arguments that are known beforehand into a view.

Another thing you should probably do is disable the id and version field using dbo_traits, see the Wt::Dbo tutorial about customizing the mapping: https://www.webtoolkit.eu/wt/wt3/doc/tutorial/dbo.html#customizing

RE: [v3][Dbo] How to read from a Set Returning Function (SRF) aka "table functions". - Added by Vincenzo Romano 6 months ago

Thanks again lm.
Unluckily I need time to prepare a v4 environment to test which I don't have right now.
The point for me is that syntax is (seems to be) OK: I am always compiling with
-Wall@ so any type mismatch would pop up as a warning.
The SQL function session_configuration() returns a set of records, though, while your example would pull 1 or 0 records.
My minimal code is:

// Wt
#include <Wt/Dbo/backend/Postgres>
#include <Wt/Dbo/Session>
#include <Wt/Dbo/collection>

// C++
#include <cstdio>

// C

Wt::Dbo::backend::Postgres dbBackEnd;
Wt::Dbo::Session dbSession;

struct ConfigEntry {
  std::string k;
  std::string v;
  template<class Action> void persist( Action& a ) {
    Wt::Dbo::field( a,k,"k");
    Wt::Dbo::field( a,v,"v");
  }
};

int main() {
  const char* dbconn = "dbname=tmp1";
  dbBackEnd.connect( std::string( dbconn ) );
  dbSession.setConnection( dbBackEnd );
  dbSession.mapClass<ConfigEntry>( "session_configuration()" );
  auto conf = dbSession.find<ConfigEntry>(); 
  return 0;
}

My command line compilation (with g++ v8) is:
g++ -Wall p.cpp -lwtdbo -lwtdbopostgres

(On my system /usr/local/lib is among the default directories where the linker looks for the shared objects.)
The link errors are:
/usr/bin/ld: /tmp/ccF2vEMb.o: in function `main':
p.cpp:(.text+0xae): undefined reference to `void Wt::Dbo::Session::mapClass<ConfigEntry>(char const*)'
/usr/bin/ld: p.cpp:(.text+0xfd): undefined reference to `Wt::Dbo::Query<Wt::Dbo::ptr<ConfigEntry>, Wt::Dbo::DynamicBinding>::~Query()'
/usr/bin/ld: /tmp/ccF2vEMb.o: in function `Wt::Dbo::Query<Wt::Dbo::ptr<ConfigEntry>, Wt::Dbo::DynamicBinding> Wt::Dbo::Session::find<ConfigEntry>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
p.cpp:(.text._ZN2Wt3Dbo7Session4findI11ConfigEntryEENS0_5QueryINS0_3ptrIT_EENS0_14DynamicBindingEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_ZN2Wt3Dbo7Session4findI11ConfigEntryEENS0_5QueryINS0_3ptrIT_EENS0_14DynamicBindingEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]+0x36): undefined reference to `Wt::Dbo::Query<Wt::Dbo::ptr<ConfigEntry>, Wt::Dbo::DynamicBinding> Wt::Dbo::Session::find<ConfigEntry, Wt::Dbo::DynamicBinding>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
collect2: error: ld returned 1 exit status

I successfully recompiled wt-3.3.12 and checked the libraries were readable, the directory tree accessible.
I have also placed the proper type instead of auto
Wt::Dbo::Query<Wt::Dbo::ptr<ConfigEntry>, Wt::Dbo::DynamicBinding> conf = dbSession.find<ConfigEntry>();

The error is still there.
If this is fixed in v4, then it must be a bug. Isn't it?

RE: [v3][Dbo] How to read from a Set Returning Function (SRF) aka "table functions". - Added by lm at 6 months ago

I was able to reproduce the link error using Wt4. I added #include <Wt/Dbo/Dbo.h> to the top, and it links just fine. I'm not sure which header you're missing exactly, but Dbo.h includes everything you're likely to need.

RE: [v3][Dbo] How to read from a Set Returning Function (SRF) aka "table functions". - Added by Vincenzo Romano 6 months ago

C O R R E C T !
I think this is a bug in the header #include policies: that file should be automatically included with any Dbo-related header file!

Thanks a lot!

(1-6/6)