PostgREST POST method converts Array of ints to text - postgresql

I have a PostgreSQL function logschema.movement that returns a subset of the table logschema.movement, the function looks like this:
CREATE OR REPLACE FUNCTION logschema.movement(
"ids" bigint[], "date" TEXT)
RETURNS SETOF logschema.movement
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $$
BEGIN
RETURN QUERY (SELECT * FROM logschema.movement WHERE "ids" = ANY ("ids") AND "day" >= $2::TIMESTAMP);
END;
$$;
This function works within PostgreSQL, e.g. SELECT logschema.movement(ARRAY[1,2,3], '2021-09-09') doesn't return an error.
If I try to query the function with PostgREST and axios like this:
let payload = {ids: [1,2,3], date: "2021-09-08"}
return await RequestService.postData(new URL(this.api + `/rpc/movement`, this.urlBase), payload);
I get a long error message which contains:
...
data:
{ hint:
'No function matches the given name and argument types. You might need to add explicit type casts.',
details: null,
code: '42883',
message:
'function logschema.movement(lastBatteryChangeDate => text, pseudoIds => text) does not exist' } }
...
It looks to me like my array got converted to a string but I'm not sure.
My PostgreSQL Version is PostgreSQL 12.8 on x86_64-pc-linux-musl, compiled by gcc (Alpine 10.3.1_git20210424) 10.3.1 20210424, 64-bit and my PostgREST Version is v7.0.1

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;

PostgreSql - calling stored proc to bulk upsert (insert on conflict) data isn't working via npgsql

I am trying bulk upsert data to via a stored proc. Following a few threads, I ended up creating a stored procs passing input records as json and using json_populate_recorset internally like this
CREATE OR REPLACE PROCEDURE public.test_proc3(IN par_records character varying)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
insert into firsttable
select * from json_populate_recordset(NULL::uttfirsttable, (par_records)::json)
on conflict(id)
do update set
createddate = excluded.createddate,
name = excluded.name;
END;
$BODY$;
btw uttfirsttable is a type declared as
CREATE TYPE public.uttfirsttable AS
(
id integer,
name character varying(100),
createddate timestamp without time zone
);
This works fine if I call it directly from PgAdmin as
call test_proc3(
'[
{
"id": 1,
"name": "newfirst",
"createddate": "2021-03-10T10:03:19.3589317+11:00"
},
{
"id": 6,
"name": "sixth",
"createddate": "2021-03-10T10:03:19.3689052+11:00"
},
{
"id": 2,
"name": "newsecond",
"createddate": "2021-03-10T10:03:19.3689052+11:00"
}
]'
);
However my .net code is somehow failing to insert/update anything despite passing exactly same json to the stored proc
string recordsJson = "[{\"id\": 1,\"name\": \"newfirst\",\"createddate\": \"2021-03-10T10:03:19.3589317+11:00\"},{\"id\": 6,\"name\": \"sixth\",\"createddate\": \"2021-03-10T10:03:19.3689052+11:00\"},{\"id\": 2,\"name\": \"newsecond\",\"createddate\": \"2021-03-10T10:03:19.3689052+11:00\"}]";// JsonConvert.SerializeObject(records, Formatting.Indented);
using (var lConn = GetConnection())
{
using (var trans = lConn.BeginTransaction())
{
using (var cmd = GetCommand("call test_proc3(#par_records)", lConn, trans, System.Data.CommandType.Text))
{
cmd.Parameters.Add("#par_records", NpgsqlDbType.Varchar, recordsJson.Length).Value = recordsJson;
int result = cmd.ExecuteNonQuery();
}
}
}
result has -1 value in it. Just for testing if I replace the 'call test_proc3(#par_records) with the full query from the stored proc, then cmd.ExecuteNonQuery returns 3, however still no records are added/updated.
Any idea what I could be doing wrong here?
Took me hours to notice a careless mistake of missing
trans.Commit
before exiting the function.

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.

Zend: Inserting Large data in CLOB and BLOB?

I am pulling data from Google Places API and trying to insert reviews into oracle database using zend framework. But reviews that are very long are giving error like :
ORA-01461: can bind a LONG value only for insert into a LONG
When i try to run the insert query in Orqcle SQL Developer its giving the following error:
I tried some of the solutions i got on google and stackoverflow but still not working.
Here is my db code in zend:
public function addReview($bind) {
$bind['STATUS'] = 1;
$bind['CREATED_TIME'] = $this->_curDate;
$text = htmlentities($bind['TEXT']);
$query = "Insert INTO ".$this->_name." (LID,AUTHOR_NAME,AUTHOR_URL,RATINGS,TYPE,TIME,STATUS,TEXT)
VALUES (".$bind['LID'].",
'".$bind['AUTHOR_NAME']."',
'".$bind['AUTHOR_URL']."',
'".$bind['RATINGS']."',
'".$bind['TYPE']."',
'".$bind['TIME']."',
".$bind['STATUS'].",'".$text."')";
try {
$insert = $this->_dbAdpt->query($query);
} catch (Exception $e) {
echo $query; exit;
}
}
Somehow creating a procedure for inserting the reviews worked! Below is the procedure :
create or replace procedure google_review (lid in int,author_name in varchar2, author_url in varchar2,ratings in varchar2,
type in varchar2,time in varchar2,status int,text in varchar2)
as
begin
INSERT INTO TBL_REVIEWS
(
LID,
AUTHOR_NAME,
AUTHOR_URL,
RATINGS,
TYPE,
TIME,
STATUS,
TEXT
)
VALUES
(
LID,
AUTHOR_NAME,
AUTHOR_URL,
RATINGS,
TYPE,
TIME,
STATUS,
TEXT
);
end;