How to reload a postgres C extension? - postgresql

I've created a C extension defining the shell of a function that I can call from SQL code in Postgresql 12.3. I'm using PGXS to build and install the extension. I can build, install and call the function, but if I make changes and reinstall, the changes don't show.
The make file is:
MODULES = bar
EXTENSION = bar
DATA = bar--0.0.1.sql
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
bar.control is
comment = 'Simple bar function'
default_version = '0.0.1'
relocatable = true
module_pathname = '$libdir/bar'
bar--0.0.1.sql is:
CREATE OR REPLACE FUNCTION
bar(jsonb) RETURNS int AS 'MODULE_PATHNAME','bar'
LANGUAGE C STRICT;
bar.c is:
#include "postgres.h"
#include "fmgr.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(bar);
Datum bar(PG_FUNCTION_ARGS)
{
PG_RETURN_INT32(101);
}
I run make install to do the install. And then
drop extension bar; create extension bar; but the changes won't show when I call the function. The only way I can install a new version is to restart postgres. What step am I missing?

Well, I discovered that if I just create a new connection to the DB the changes will show. That isn't so bad, I suppose. Does that have to do with how postgres uses fork() to create a new process for each connection?

When you execute your function, the shared library gets loaded into your backend process and stays there. Replacing the shared library on disk does not modify the in-memory copy loaded into your process. You have to start a new database connection and execute the function again to get the new version.

Related

Error with static compilation Qt with postgresql driver

I have installed through Mainteinance Tool Qt 5.12.5 and the sources. I have the next directories:
C:\Qt\5.12.5\Src
C:\Qt\Tools\mingw730_32\
C:\Qt\Tools\mingw730_64\
On the other hand, I have read that downloable Postgres version is compiled with MSVC, and I must to compile my own version. I have do it following link, and now I have a postgresql version in c:\pgsql
Finally I have added c:\pgsql to user Path
Next step, I have opened PowerShell in Admin mode and I´ve gone to C:\Qt\5.12.5\Src\.
Next, set the env path for this PowerShell session:
$env:Path += ";C:\Qt\Tools\mingw730_64\bin\;C:\Qt\5.12.5\Src;C:\pgsql\include\;C:\pgsql\lib\;C:\pgsql\bin\" (setting the pgsql path again....)
After that, I execute configure.bat like that:
configure -v -static -release -static-runtime -platform win32-g++ -prefix C:\Qt\5.12.5\Estatico\ -opensource -confirm-license -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype -opengl desktop -no-openssl -opensource -confirm-license -skip webengine -make libs -nomake tools -nomake examples -nomake tests -sql-psql
But I have get this error:
ERROR: Feature 'sql-psql' was enabled, but the pre-condition 'libs.psql' failed.
Searching in config.log I can read those lines:
loaded result for library config.qtbase_sqldrivers.libraries.psql
Trying source 0 (type pkgConfig) of library psql ...
pkg-config use disabled globally.
=> source produced no result.
Trying source 1 (type psqlConfig) of library psql ...
pg_config not found.
=> source produced no result.
Trying source 2 (type psqlEnv) of library psql ...
None of [liblibpq.dll.a liblibpq.a libpq.dll.a libpq.a libpq.lib] found in [] and global paths.
=> source produced no result.
Trying source 3 (type psqlEnv) of library psql ...
=> source failed condition '!config.win32'.
test config.qtbase_sqldrivers.libraries.psql FAILED
What can I do or what is the properly way to do that?
Thank you in advance.
UPDATE
There are similar question here but it hasn´t been solved, and those question ask about Visual Studio.
I want to compile it under mingw.
The solution suggested by #Soheil Armin doesn´t work too
The solution suggested by #Soheil Armin works fine, but I need to delete the entire source tree and reinstall it as he suggested. If not, a new configure won't work.
Also, the ^ character can be saved:
configure <your parameters>
PSQL_LIBS="C:\pgsql\lib\libpq.a"
-I "C:\pgsql\include"
-L "C:\pgsql\lib"
You need to explicitly define library paths of Postgres.
configure <your parameters> ^
PSQL_LIBS="C:\pgsql\lib\libpq.a" ^
-I "C:\pgsql\include" ^
-L "C:\pgsql\lib"

CREATE EXTENSION pljava failed on PostgreSql 9.6

I try to install pljava for postgesql 9.6 in Ubuntu 16.04, but it fails with error.
A gradlew script makes an installation, but it fails with the following error"
Failed to execute: CREATE EXTENSION pljava; because: ERROR: could not access file "pljava-so-1.5.1-BETA1": No such file or directory
A gradlew source:
Sql sql = establishConnection()
try {
sql.execute("SET pljava.libjvm_location TO '${javaNative}';")
sql.execute("SET pljava.vmoptions TO '-Xshare:on -XX:+DisableAttachMechanism';")
sql.execute("ALTER DATABASE postgres SET pljava.libjvm_location FROM CURRENT;")
sql.execute("ALTER DATABASE postgres SET pljava.vmoptions FROM CURRENT;")
sql.execute("CREATE EXTENSION pljava;")
} finally {
sql.close()
}
As i understand, it fails during a creation of extension pljava, commands above was executed without any errors.
According to #ChapmanFlack advice:
I have no any mentions about pljava-so-1.5.1-BETA1 file at pg_config --libdir directory. Also i didn't find that file at pg_config --sharedir
grep LOAD pljava--1.5.1-BETA1.sql output following:
touched off by the LOAD command, making possible a decent installation
LOAD command, but finds the CREATE EXTENSION command instead). So,
temporarily LOAD 'pljava-so-1.5.1-BETA1'; Ok, the LOAD succeeded, so
everything happened ... unless ... the same PostgreSQL turns LOAD into
a (successful) no-op in that case, meaning To fail fast in that case,
expect that the LOAD actions should have
I think PL/Java builds from a prebuilt, because of that line at gradlew:
commandLine 'java', '-jar', '../installer/build/dependencies/pljava-pg9.6.jar'
I would be appreciate for any advice

Postgres PL/JAVA: java.lang.ClassNotFoundException error after loading JAR file in database

I am getting the java.lang.ClassNotFoundException: error inside Postgres when running a function that calls a JAR file I have loaded. I have installed and configured PL/JAVA (including the delivered examples) in my database and can run the examples to success. I am not attempting to load/install my first JAR, but I am doing something wrong.
My host controls the OS version: CentOS 6.8. Postgres is version 8.4.
I am attempting to install my own very simple java class, which is a derivative of the delivered example Parameters.addOne class. All my code is in /tmp. Here are the steps I've followed:
Doug.java:
package com.msmetric;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.logging.Logger;
public class Doug {
public static int addOne(int value) {
return value + 1;
}
}
Compile Doug.java using 'javac Doug.java' succeeds.
Create JAR file with Doug.class file in it using 'jar -cvf Doug.jar Doug.class. This works fine.
Now I load the JAR file into Postgres (public schema), change the classpath, create the function that calls the JAR, then attempt to run at psql prompt.
Run sqlj.install_jar from psql:
select sqlj.install_jar('file:/tmp/Doug.jar','Doug',false);
Set the classpath inside Postgres (from psql prompt postgres=#):
select sqlj.set_classpath('public','Doug');
Create the function that calls the JAR. This create function code is taken directly from the examples.ddr file that came with PL/JAVA. I simply changed org.postgres to com.msmetric.
create or replace function addone(int) returns int as 'com.msmetric.Doug.addOne(java.lang.Integer)' language java;
Now with the JAR loaded and function created, I attempt to run it. This function should simply add 1 to the number provided.
select addone(3);
Results:
ERROR: java.lang.ClassNotFoundException: com.msmetric.Doug
Thoughts?
I'm very sorry I didn't see your question sooner. Underneath all the exotic details (PostgreSQL, PL/Java, schemas, classpaths...), there's just a bit of basic Java going on here: if a jar file contains a class Doug.class in package com.msmetric, its path within the jar has to reflect that: it has to be com/msmetric/Doug.class. Otherwise, it won't be found.
You can set up that whole structure step by step:
javac Doug.java
mkdir com
mkdir com/msmetric
mv Doug.class com/msmetric/
jar -cvf Doug.jar com/msmetric/Doug.class
Or, you can let javac do more of the work for you:
mkdir classes
javac -d classes Doug.java
jar -cvf Doug.jar -C classes .
When you give javac a -ddirectory option, instead of just writing class files next to their .java sources, it will put them all in their proper places under the directory you named, and then you can just tell jar to change into that directory and slurp them all up (don't overlook the . at the end of that jar command).
Once you fix that, if you retry your original steps, you'll see that you now get a different error:
ERROR: Unable to find static method com.msmetric.Doug.addOne with signature (Ljava/lang/Integer;)I
That happens because you declared the function in Doug.java with int addOne(int value) (that is, taking a primitive int argument), but you declared it in SQL with returns int as 'com.msmetric.Doug.addOne(java.lang.Integer)' taking an Integer object.
Once you correct that:
create or replace function addone(int) returns int as 'com.msmetric.Doug.addOne(int)' language java;
you'll be able to see:
# select addone(3);
addone
--------
4
(1 row)
If you happen to see this belated answer, may I ask what version of PL/Java you are using? That's one detail you didn't mention. If it is older than 1.5.0, there are newer features that can help you out. For one, you can just annotate that function:
#Function
public static int addOne(int value) {
return value + 1;
}
and have javac spit out not only the Doug.class file but also a pljava.ddr file with your SQL function declaration already written correctly (no mixing up argument types!). There is a way to include that .ddr file into the jar you create so that you can just call sqlj.install_jar with the last parameter true so it runs the commands in the .ddr and your functions are ready to use. There's a Hello, world example in the docs that shows more of how it's done.
Cheers,
-Chap

error in creating new hook method in PostgreSQL

I have written a plugin module for PostgreSQL for my academic requirements(version: PostgreSQL9.3.4) I am using hooks to influence planner behaviour in this plugin module. I am able to use join_search_hook, planner_hook successfully. But I wanted to create a new hook for a method which is not already having a hook defined.
I wanted to define a hook for
void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel)
method in costsize.c
I declared a hook in optimizer/paths.h
typedef void (*size_estimates_hook_type) (PlannerInfo *root, RelOptInfo *rels);
extern PGDLLIMPORT size_estimates_hook_type size_estimates_hook;
and initialized it at top of allpaths.c
size_estimates_hook_type size_estimates_hook = NULL;
I added this check in allpaths.c in a method to decide whether to invoke hooked method or not.
if (size_estimates_hook)
(*size_estimates_hook) (root, rel);
else
set_baserel_size_estimates(root, rel);
Now coming to plugin module code,
static join_search_hook_type prev_join_search = NULL;
static size_estimates_hook_type prev_size_estimates = NULL;
The first line compiles fine, but second line gives error
"error: unknown type name ‘size_estimates_hook_type’"
Am i missing some step in defining a new hook method?
note: Plugin is compiled using a dedicated Makefile.
Using the following makefile for compiling the plugin module solved the issue.
MODULES = module_name
ifdef USE_PGXS
PG_CONFIG = <path to /backend/bin/pg_config>
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/module_name
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif

Automake, generated source files and VPATH builds

I'm doing VPATH builds with automake. I'm now also using generated source, with SWIG. I've got rules in Makefile.am like:
dist_noinst_DATA = whatever.swig
whatever.cpp: whatever.swig
swig -c++ -php $^
Then the file gets used later:
myprogram_SOURCES = ... whatever.cpp
It works fine when $builddir == $srcdir. But when doing VPATH builds (e.g. mkdir build; cd build; ../configure; make), I get error messages about missing whatever.cpp.
Should generated source files go to $builddir or $srcdir? (I reckon probably $builddir.)
How should dependencies and rules be specified to put generated files in the right place?
Simple answer
You should assume that $srcdir is a read-only, so you must not write anything there.
So, your generated source-code will end up in $(builddir).
By default, autotool-generated Makefiles will only look for source-files in $srcdir, so you have to tell it to check $builddir as well. Adding the following to your Makefile.am should help:
VPATH = $(srcdir) $(builddir)
After that you might end up with a no rule to make target ... error, which you should be able to fix by updating your source-generating rule as in:
$(builddir)/whatever.cpp: whatever.swig
# ...
A better solution
You might notice that in your current setup, the release tarball (as created by make dist) will contain the whatever.cpp file as part of your sources, since you added this file to the myprogram_SOURCES.
If you don't want this (e.g. because it might mean that the build-process will really take the pregenerated file rather than generating it again), you might want to use something like the following.
It uses a wrapper source-file (whatever_includer.cpp) that simply includes the generated file, and it uses -I$(builddir) to then find the generated file.
Makefile.am:
dist_noinst_DATA = whatever.swig
whatever.cpp: whatever.swig
swig -c++ -php $^
whatever_includer.cpp: whatever.cpp
myprogram_SOURCES = ... whatever_includer.cpp
myprogram_CPPFLAGS = ... -I$(builddir)
clean-local::
rm -f $(builddir)/whatever.cpp
whatever_includer.cpp:
#include "whatever.cpp"
Usually, you want to keep $srcdir readonly, so that if for instance the source is distributed unpacked on a CDROM, you can still run /.../configure from some other part of the file-system.
However if you are using SWIG to generate source code for a wrapper library, you probably want to distribute that SWIG-generated code as well so that your users do not need to install SWIG to compile your code. Then you have indeed a choice: you can decide that the SWIG-generated code should end in $builddir (it's OK: make dist will collect it there and include it in the tarball), or you could decide to output SWIG-generated code in $srcdir since it is really a source from the point of view of the distributed package. An advantage of keeping it in $srcdir is that when make distcheck attempts to build your package from a read-only source directory, it will fail on any attempt to call SWIG to regenerate the wrapper source. If you have your wrapper source in $builddir, you might not notice you have some broken rule that cause SWIG to be run on the user's host; by generating in $srcdir you ensure that SWIG is not needed by your users.
So my preference is to output SWIG wrapper sources in $srcdir. My setup for Python wrappers looks as follows:
EXTRA_DIST = spot.i
python_PYTHON = $(srcdir)/spot.py # _PYTHON is distributed by default
pyexec_LTLIBRARIES = _spot.la
MAINTAINERCLEANFILES = $(srcdir)/spot_wrap.cxx $(srcdir)/spot.py
_spot_la_SOURCES = $(srcdir)/spot_wrap.cxx $(srcdir)/spot_wrap.h
_spot_la_LDFLAGS = -avoid-version -module
_spot_la_LIBADD = $(top_builddir)/src/libspot.la
$(srcdir)/spot_wrap.cxx: $(srcdir)/spot.i
$(SWIG) -c++ -python -I$(srcdir) -I$(top_srcdir)/src $(srcdir)/spot.i
# Handle the multi-file output of SWIG.
$(srcdir)/spot.py: $(srcdir)/spot.i
$(MAKE) $(AM_MAKEFLAGS) spot_wrap.cxx
Note that I use $(srcdir) for all targets, because of limitations of the VPATH feature on various flavors of make. My setup to deal with the multiple files output by SWIG could be improved, but as these rules are not run by users and it has never caused me any problem, I do not bother.