Calling a function on insert with JDBC - postgresql

I have the following function and table in my PostgreSQL database:
CREATE OR REPLACE FUNCTION generate_uid(size INT) RETURNS TEXT AS $$
DECLARE
characters TEXT := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
bytes BYTEA := gen_random_bytes(size);
l INT := length(characters);
i INT := 0;
output TEXT := '';
BEGIN
WHILE i < size LOOP
output := output || substr(characters, get_byte(bytes, i) % l + 1, 1);
i := i + 1;
END LOOP;
RETURN output;
END;
$$ LANGUAGE plpgsql VOLATILE;
create table users
(
userid text primary key default generate_uid(50)
, username varchar (50) not null
, pass varchar (50) not null
, firstname varchar (100) not null
, lastname varchar (100) not null
, email varchar (150) not null
, roleid int not null
, constraint fkrole foreign key(roleid) references userrole(roleid)
);
Then I call on the function in my DAO in JDBC with this block of code:
Account A = new Account();
String sha256hex = Hashing.sha256()
.hashString(password, StandardCharsets.UTF_8)
.toString();
try (Connection conn = CustomClassFactory.getConnection()) {
String sql = "INSERT INTO users (username, pass, firstname, lastname, email, roleid) VALUES (?,?,?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userName);
ps.setString(2, sha256hex);
ps.setString(3, firstName);
ps.setString(4, lastName);
ps.setString(5, email);
ps.setInt(6, roleId);
System.out.println(ps.toString());
int i = ps.executeUpdate(); // <---update not query. this line is what sends the information to the DB
if (i == 0) {
System.out.println("Sorry, database was not updated. Returning to menu");
return null;
}
} catch (SQLException e) {
System.out.println("Sorry, database was not contacted. Bring your developer coffee. In the Insert Statement");
e.printStackTrace();
return null;
}
I am receiving the following error from the Stack Trace:
org.postgresql.util.PSQLException: ERROR: function gen_random_bytes(integer) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Where: PL/pgSQL function generate_uid(integer) line 8 during statement block local variable initialization
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2552)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2284)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:322)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:481)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:401)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:130)
at dao.AccountDaoImp.CreateAccount(AccountDaoImp.java:35)
at testing.Tester.main(Tester.java:11)
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "models.Account.toString()" because the return value of "dao.AccountDaoImp.CreateAccount(String, String, String, String, String, int)" is null
at testing.Tester.main(Tester.java:11)
How do I make sure it sees the function when I create a new user? The function is designed to generate a random string of text to use as a unique ID.

gen_random_bytes is part of the pgcrypto extension.
So run this in your database:
CREATE EXTENSION pgcrypto SCHEMA public;
To make sure you don't have to rely on search_path, you can prefix public to the function call, like in public.gen_random_uuid().

Related

default date value to store in a table in snowflake

I created below snowflake procedure and from that procedure I want to
insert default date value into a table. Below is the script.
create or replace procedure test_dt() returns string not null language
javascript //execute as owner
as
$$
try {
var c_dt=`select current_date()`;
snowflake.execute({sqlText:c_dt});
var sql_query = `insert into test_date values (:1)`;
var resultSet = snowflake.execute( {sqlText: sql_query, binds:c_dt});
}
catch(err) {
return err.message;
}
$$;
call test_dt();
while executing the procedure I am getting below error.
"Date 'select current_date()' is not recognized"
Please help me on this.
you are binding the "date" in the second query, to the input sql that "gets the current_date()" and not the actual result, thus it's the same as
insert into test_date values ('select current_date()');
so you ether want to save the result of the first query OR just use the current date aka CURRENT_DATE
insert into test_date values (CURRENT_DATE);
create or replace procedure test_dt() returns string not null language
javascript //execute as owner
as
$$
try {
var sql_query = `insert into test_date values (current_date)`;
var resultSet = snowflake.execute( {sqlText: sql_query});
}
catch(err) {
return err.message;
}
$$;```

Can a return value from a function be named with a specific name for Postgraphile?

I have this function in PostgreSQL:
CREATE FUNCTION it_exists(
email text,
name text
) RETURNS boolean AS $$
DECLARE
_eva1 boolean;
_eva2 boolean;
BEGIN
_eva1 := EXISTS(SELECT * FROM tableA AS A WHERE A.email = $1::citext);
_eva2 := EXISTS(SELECT * FROM tableB AS A WHERE A.name::citext = $2::citext);
RETURN _eva1 OR _eva2;
END;
$$ LANGUAGE plpgsql STRICT SECURITY DEFINER;
It is translated into Postgraphile like this:
mutation MyMutation($email: String!, $name: String!) {
itExists(
input: { email: $email, name: $name }
) {
boolean
}
}
I'd wish to change "boolean" name to something like "result", any suggestion? Consider I have many functions with different return values.
I think that Postgraphile does this to have its custom mutations follow the Relay specification which says
By convention, mutations are named as verbs, their inputs are the name with "Input" appended at the end, and they return an object that is the name with "Payload" appended.
So your custom mutation creates an ItExistsPayload type with only a single field on it instead of returning a GraphQL Boolean. In the future you might want to extend this payload object with more fields.
It is possible to rename that field by using the #resultFieldName smart tag. In your case:
COMMENT ON FUNCTION it_exists(text, text) IS '#resultFieldName result';
Try returning a table instead:
CREATE FUNCTION it_exists(
email text,
name text
) RETURNS TABLE (result boolean) AS $$ -- return TABLE type
DECLARE
_eva1 boolean;
_eva2 boolean;
BEGIN
_eva1 := EXISTS(SELECT * FROM tableA AS A WHERE A.email = $1::citext);
_eva2 := EXISTS(SELECT * FROM tableB AS A WHERE A.name::citext = $2::citext);
RETURN QUERY SELECT _eva1 OR _eva2; -- modify RETURN to suit TABLE type
END;
$$ LANGUAGE plpgsql STRICT SECURITY DEFINER;

NpgSql and PostgreSQL 12.4 - Only getting the cursor name from data reader instead of the rows of data

I'm trying to pull back data from PostgreSQL using a data reader. Each time I run my code the only value returned is the name of the refcursor.
I created the following to illustrate my problem. I'm using NpgSql .net core 3.1 aginst a PostgreSQL 12.4 database. Can anyone point out what I'm doing wrong?
Here is a simple table of cities with a function that is supposed to return the list of cities stored in the tblcities table.
CREATE TABLE public.tblcities
(
cityname character varying(100) COLLATE pg_catalog."default" NOT NULL,
state character varying(2) COLLATE pg_catalog."default",
CONSTRAINT tblcities_pkey PRIMARY KEY (cityname)
);
INSERT INTO public.tblcities(cityname, state) VALUES ('San Francisco','CA');
INSERT INTO public.tblcities(cityname, state) VALUES ('San Diego','CA');
INSERT INTO public.tblcities(cityname, state) VALUES ('Los Angeles','CA');
CREATE OR REPLACE Function getcities() RETURNS REFCURSOR
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
ref refcursor := 'city_cursor';
BEGIN
OPEN ref FOR
select *
from tblcities;
Return ref;
END;
$BODY$;
The following is the .net code.
public static void GetCities()
{
using (var cn = new NpgsqlConnection(dbconn_string))
{
if (cn.State != ConnectionState.Open)
cn.Open();
using (NpgsqlCommand cmd = cn.CreateCommand())
{
cmd.CommandText = "getcities";
cmd.Connection = cn;
cmd.CommandType = CommandType.StoredProcedure;
NpgsqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
//There is only one row returned when there should be 3.
//The single value returned is the name of the refcursor - 'city_cursor'
//Where are the city rows I'm expecting?
var value1 = dr[0];
}
}
}
}
In PostgreSQL, rather than returning a refcursor, you generally return the data itself - change the function to have RETURNS TABLE instead of RETURNS REFCURSOR (see the docs for more details). If you return a cursor to the client, the client must then perform another roundtrip to fetch the results for that cursor, whereas when returning a table directly no additional round-trip is needed.
This is one of the main reasons Npgsql doesn't automatically "dereference" cursors - lots of people coming from other databases write functions returning cursors, when in reality doing that is very rarely necessary.
For some discussions around this, see https://github.com/npgsql/npgsql/issues/1785 and https://github.com/npgsql/npgsql/issues/438.

PostgreSQL, Spring Data JPA: Integer null interpreted as bytea

In PostgreSQL I have the table
CREATE TABLE public.my_table
(
id integer NOT NULL,
...
I want to perform the query: Show me the rows with a given id. If id is null, show me all rows.
I tried it with
public interface MyRepository extends JpaRepository<MyTable, Integer> {
#Query(value = "SELECT * FROM my_table WHERE (?1 IS NULL OR id = ?1)", nativeQuery = true)
List<MyTable> findAll(Integer id);
If id != null, everything is fine. But if id == null, I will receive the error
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:261) ~[spring-orm-4.3.13.RELEASE.jar:4.3.13.RELEASE]
...
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
...
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: integer = bytea
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2440) ~[postgresql-42.2.5.jar:42.2.5]
...
Obviously short circuit evaluation does not work and null is transformed into bytea.
As a workaround I have changed the query value into
SELECT * FROM my_table WHERE (?1 IS NULL OR id = (CAST (CAST(?1 AS character varying) AS integer)))
But this is not nice, because the int is cast to string and to int again. Do you have a better solution, e.g. a better cast or sql query?
Another workaround for this is to create the query manually from the EntityManager (em in the example) and call setParameter on it once with a non-null value, then again with the real value.
private static final Integer exampleInt = 1;
List<MyTable> findAll(Integer id) {
return em.createNativeQuery("SELECT * FROM my_table WHERE (:id IS NULL OR id = :id)", MyTable.class)
.setParameter("id", exampleInt)
.setParameter("id", id)
.resultList();
}
This ensures that Hibernate knows the type of value the next second time it's called, even if it's null.
The fault is in the PostgreSQL server, and not in Hibernate, but they have refused to fix it, because it works as intended. You just have a few hundred types of SQL NULL on the server and they're mostly incompatible with each-other, even though it's supposed to be one singular special value.

Sqlx Get with prepared statements

I am trying to fetch some data from postgress table using prepared statements
If I try with database.Get() everything is returned.
Table:
create table accounts
(
id bigserial not null
constraint accounts_pkey
primary key,
identificator text not null,
password text not null,
salt text not null,
type smallint not null,
level smallint not null,
created_at timestamp not null,
updated timestamp not null,
expiry_date timestamp,
qr_key text
);
Account struct:
type Account struct {
ID string `db:"id"`
Identificator string `db:"identificator"`
Password string `db:"password"`
Salt string `db:"salt"`
Type int `db:"type"`
Level int `db:"level"`
ExpiryDate time.Time `db:"expiry_date"`
CreatedAt time.Time `db:"created_at"`
UpdateAt time.Time `db:"updated_at"`
QrKey sql.NullString `db:"qr_key"`
}
BTW i tried using ? instead of $1 & $2
stmt, err := database.Preparex(`SELECT * FROM accounts where identificator = $1 and type = $2`)
if err != nil {
panic(err)
}
accounts := []account.Account{}
err = stmt.Get(&accounts, "asd", 123)
if err != nil {
panic(err)
}
The error I get is
"errorMessage": "scannable dest type slice with \u003e1 columns (10) in result",
In the table there are no records I tried to remove all fields except the ID from Account (struct), however it does not work.
Documentation for sqlx described Get and Select as:
Get and Select use rows.Scan on scannable types and rows.StructScan on
non-scannable types. They are roughly analagous to QueryRow and Query,
where Get is useful for fetching a single result and scanning it, and
Select is useful for fetching a slice of results:
For fetching a single record use Get.
stmt, err := database.Preparex(`SELECT * FROM accounts where identificator = $1 and type = $2`)
var account Account
err = stmt.Get(&account, "asd", 123)
If your query returns more than a single record use Select with statement as:
stmt, err := database.Preparex(`SELECT * FROM accounts where identificator = $1 and type = $2`)
var accounts []Account
err = stmt.Select(&accounts, "asd", 123)
In your case if you use stmt.Select instead if stmt.Get. It will work.