Supabase calls outdated function even when it is deleted - postgresql

I've created a new function in Supabase as follows:
drop function if exists select_whitelist_airdrop_address;
create
or replace function select_whitelist_airdrop_address(airdrop_address text)
returns table(owner text, hash text)
as $$
select a.owner, b.hash
from thirdparty_token_holders a
left join thirdparty_token_airdrops b
on a.id = b.holder_id
where (b.status = 1 AND b.hash != 'NOT PROCESSED' AND a.owner=airdrop_address)
limit 1
$$ language sql;
And deleted an older one called select_whitelist_airdrops. Upon deleting it, I've started getting the following error:
info: getAirdropWhitelistStatus -> error: {"error":{"message":"Could not find the public.select_whitelist_airdrops(hash) function or the public.select_whitelist_airdrops function with
a single unnamed json or jsonb parameter in the schema cache","hint":"If a new function was created in the database with this name and parameters, try reloading the schema cache."},"da
ta":null,"count":null,"status":404,"statusText":"Not Found","body":null}
Why is Supabase referring to this function when:
I no longer need it
I am using another function in my code, see below:
public async getAirdropWhitelistStatus(address: string) {
return this.supabase.rpc('select_whitelist_airdrop_address', {
airdrop_address: address
})
}
Why does Supabase keep referring back to the old proc when run?

Related

Porting Oracle associative arrays to Postgres and wrapping the data access using npgsql

It is great to get prompt replies on the npgsql queries. Thanks to its owner! I am trying to port a sproc that took in array valued parameters to postgres with similar abstraction/semantics. I am wondering how one would shape the pgsql sproc and use npgsql api to call that. I have another layer of application abstraction on top of our dal abstraction. We use data adapters to go to sql server, assoc arrays to oracle and trying to figure out what we could map this to for postgres using npgsql. We have some room in shaping the sproc but still keep the number of input params the same. we could certainly build this sproc much different but we still need it behind the same app api which supplies some set of typed arrays as shown below
public static void Flush2OraWithAssocArrayInsnetworkdatabatch(string dbKey ,int?[] ENDPOINTID,DateTime?[] INSERTEDDATETIME,int?[] RECORDTYPEID,long?[] RECORDVALUE,int?[] PACKETSIZE)
{
Database db = Helper.GetDatabase(dbKey);
using (DbConnection con = db.CreateConnection()){
con.Open();
using (DbCommand cmd = con.CreateCommand()){
cmd.CommandText = "Insnetworkdatabatch";
Helper.InitializeCommand(cmd, 300, "Insnetworkdatabatch");
BuildInsnetworkdatabatchOracleAssocArrayCommandParameters(cmd ,ENDPOINTID,INSERTEDDATETIME,RECORDTYPEID,RECORDVALUE,PACKETSIZE);
try {
Helper.ExecuteNonQuery(cmd, cmd.CommandText);
con.Close();
} catch (DALException ) {
throw;
}
}
}
}
I have a oracle sproc written as follows
create or replace PROCEDURE InsNetworkDataBatch2
(
-- Add the parameters for the stored procedure here
v_endPointID IN arrays.t_number ,
v_insertedDateTime IN arrays.t_date ,
v_recordTypeID IN arrays.t_number ,
v_recordValue IN arrays.t_number ,
v_packetSize IN arrays.t_number )
AS
BEGIN
DECLARE
BEGIN
FORALL i IN v_endpointID.FIRST..v_endpointID.LAST SAVE EXCEPTIONS
INSERT
INTO STGNETWORKSTATS
(
INSERTEDDATE,
ENDPOINTID,
RECORDTYPEID,
RECORDVALUE,
PACKETSIZE
)
VALUES
(
v_insertedDateTime(i),
v_endPointID(i),
v_recordTypeID(i),
v_recordValue(i),
v_packetSize(i)
);
END;
END;
-- END PL/SQL BLOCK (do not remove this line) ----------------------------------
Here is the assoc array package in oracle
create or replace PACKAGE Arrays AS
type t_number is table of number index by binary_integer;
type t_date is table of date index by binary_integer;
END Arrays;
Here is how we build the oracle parm and wondering what its equivalency if at all possible in postgres and trying to see how npgsql will support it
public override void CreateAssociativeArrayParameter(DbCommand cmd, string parameterName, object parameterValue, string dbType, ParameterDirection direction)
{
OracleDbType oracleDbType = dbSpecificTypesMap[dbType];
OracleParameter param = new OracleParameter(parameterName, oracleDbType, direction);
param.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
param.Value = parameterValue;
cmd.Parameters.Add(param);
}
I don't know anything about Oracle arrays or associative arrays. However, PostgreSQL has a rich support for complex types. PostgreSQL arrays are a good way to store an array of values in a column, and PostgreSQL even provides indexing and database-side functions to work with arrays.
If you're looking for a dictionary type (associative array?), take a look at hstore or json.
EDITED: If your associative array has a fixed schema (i.e. the fields don't change), you can also consider PostgreSQL composite.
Here is an attempt with Postgres stored procedure. This is now working. I got around some casting issues thrown from inside the npgsql which was a result of my .net type not being compatible with the sproc parameter data type in postgres.
Here is how i am trying to add the param value
create or replace FUNCTION InsNetworkDataBatch
(
-- Add the parameters for the stored procedure here
v_endPointID IN int[] ,
v_insertedDateTime IN timestamp[] ,
v_recordTypeID IN int[] ,
v_recordValue IN bigint[] ,
v_packetSize IN int[] ) RETURNS void
LANGUAGE 'plpgsql'
AS $$
BEGIN
DECLARE
BEGIN
FOR i IN array_lower(v_endPointID, 1) .. array_upper(v_endPointID, 1)
loop
INSERT INTO STGNETWORKSTATS
(
INSERTEDDATE,
ENDPOINTID,
RECORDTYPEID,
RECORDVALUE,
PACKETSIZE
)
VALUES
(
v_insertedDateTime[i],
v_endPointID[i],
v_recordTypeID[i],
v_recordValue[i],
v_packetSize[i]
);
end loop;
END;
END;
$$
Here is how i am trying to bind the app to the command params
public override void CreateAssociativeArrayParameter(DbCommand cmd, string parameterName, object parameterValue, string dbType, ParameterDirection direction)
{
NpgsqlDbType npgsqlDbType;
if (dbSpecificTypesMap.ContainsKey(dbType))
{
npgsqlDbType = dbSpecificTypesMap[dbType];
}
else
{
throw new ApplicationException($"The db type {dbType} could not be parsed into the target NpgsqlDbType. Please check the underlying type of the parameter");
}
NpgsqlParameter param = new NpgsqlParameter(parameterName.ToLower(), NpgsqlDbType.Array | npgsqlDbType);
param.Value = parameterValue;
cmd.Parameters.Add(param);
}

Stop jOOQ stripping characters from SQL field

I am implementing a function to get an estimate of the count as described in the PostgreSQL documentation here https://wiki.postgresql.org/wiki/Count_estimate
I'm using the function:
public static Field<Integer> countEstimate(final QueryPart query) {
final String sql = String.format("count_estimate(%s)", escape(query.toString()));
return field(sql(sql), PostgresDataType.INT);
}
Which looks fine until I pass it an IN clause array field in the query. When this happens jOOQ strips the array curly braces from within my SQL. e.g. Calling it with this java code:
final UUID[] ids = new UUID[]{UUID.randomUUID()};
return db.select(countEstimate(db.select(TABLE.ID)
.from(TABLE)
.where(overlaps(ids, TABLE.FILTER_IDS))));
Results in both the variable sql and DSL.sql(sql) in the above function rendering:
count_estimate(E'select "schema"."table"."id"
from "schema"."table"
where (
((\'{"75910f3b-83e6-41ed-bf57-085c225e0131"}\') && ("schema"."table"."filter_ids"))
)')
But field(sql(sql), PostgresDataType.INT) renders this:
count_estimate(E'select "schema"."table"."id"
from "schema"."table"
where (
((\'"75910f3b-83e6-41ed-bf57-085c225e0131"\') && ("schema"."table"."filter_ids"))
)')
Is there any way to work around this and to tell jOOQ to leave my query alone?
(jOOQ 3.8.3, PG 9.5.5, PG driver 9.4-1203-jdbc4)
It turns out it only strips '{}' style arrays. Replacing the code that turns the UUID[] into sql from
DSL.val(ids)
with
DSL.array(Arrays.stream(ids)
.map(UUID::toString)
.collect(Collectors.toList())
.toArray(new String[0]))
.cast(PostgresDataType.UUID.getArrayDataType()
results in it rendering cast(array[\'75910f3b-83e6-41ed-bf57-085c225e0131\'] as uuid[]) prevents it being stripped

Stored Procedure returns incorrect scalar value of -1, instead of return value

I am trying to return a scalar value from a stored procedure. I actually want to return the ID of a newly created record, but I have simplified my problem down to a stored procedure that takes an int and attempts to return that same int. This always returns -1. Thank you very much for your help.
Web API Controller call
var idtest = dbconn.my_return_int(123);
The stored procedure:
ALTER PROCEDURE [dbo].[my_return_int]
#ID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #return as int
SET #return = -999
RETURN #return
END
The Context generated stored procedure call
public virtual int my_return_int(Nullable<int> iD)
{
var iDParameter = iD.HasValue ?
new ObjectParameter("ID", iD) :
new ObjectParameter("ID", typeof(int));
return (IObjectContextAdapter)this).ObjectContext.ExecuteFunction("my_return_int", iDParameter);
}
When you execute ObjectContext.ExecuteFunction the result is:
from MSDN: discards any results returned from the function; and returns the number of rows affected by the execution
I.e. it doesn't return the output parameter, because it doesn't know there is one. Besides, as you have called SET NOCOUNT ON; in your stored procedure, it doesn't even return the number of affected rows, thus you get the -1.
So, you must do two changes:
change your procedure so that it doesn't return the value, but selects it, i.e. instead of RETURN #return do SELECT #return AS alias. NOTE that you need the "AS alias" part. The alias can be whatever column name you want.
change the mapping of the stored procedure, so that it expects an int32 value. If you have doubt, refer to this Q&A.
In this way you'll read the return value as a result set, instead of a return value.
to solve this entity framework issue and assuming you already have a stored procedure working and you don't want to fix the places where it works good using other ways then EF you can replace the:
RETURN(0)
with:
BEGIN
SELECT(0)
RETURN(0)
END
that is if its a part of an IF sentence,
theמ go to:
EF model (.edmx) -> Model Browser -> Function Imports -> (doubl click your func) ->Scalars -> Int32
now your return value is:
ObjectResult<Nullable<int>>
you can receive it by writing:
int? response = 0;
response = myEntity.myStoredProcedure(var1, var2).FirstOrDefault();
or in pics:
1.
2.
3.
doing all this makes the EF model (.edmx) also supporting the 'Update Model from Database...' and you can update it without worry to changes you just made.
Thank you, DavidG for the article. It got me started down the right path. So what I did to solve this was change my Stored Procedure to return an ObjectResult<int?> instead of an int. Then I did a SingleOrDefault() on the results of the Stored Procedure call, which yielded my int return value. Like this:
Stored Proc:
-- RETURN #return does not work. Can't return a scalar value
SELECT #return -- This returns a result set with a single object that contains an int.
Then, my generated code looks like above but instead of returning an int it returns an ObjectResult<int?>
and I read the results like this:
var id = myDbContext.My_Return_Int(123).SingleOrDefault();
I've just implemented another option in my project. I feed in another output parameter for #return.

Pass a NULL value to numeric parameter via Yii in PostgreSQL

I have written a function in PostgreSQL with a single parameter of type NUMERIC. I am attempting to call that function from a webapp developed using the Yii framework via the SqlDataProvider component. However, each time the parameter value is left empty, I keep getting the following error:
Ivalid input syntax for type 'numeric'.
Whenever I try to execute the function directly via PhpPgAdmin, everything seems to work flawlessly.
Below is the code for the discussed PL/pgSQL function search(..):
search("itemcode" character varying DEFAULT NULL, "taxpercentage" numeric DEFAULT NULL)
LANGUAGE plpgsql
AS $$
BEGIN
SELECT * FROM item WHERE (itemcode IS NULL OR item.item_code LIKE itemcode||'%')
AND (taxpercentage IS NULL OR item.tax_percentage = taxpercentage);
END;
$$;
In the Yii model, I have also created a search function which in turn calls the database-level PL/pgSQL function:
public function search()
{
$count=Yii::app()->db->createCommand("SELECT COUNT(*) FROM search('$this->item_code','$this->tax_percentage')")->queryScalar();
$sql="SELECT * FROM search('$this->item_code','$this->tax_percentage')";
$dataProvider=new CSqlDataProvider($sql, array(
'totalItemCount'=>$count,
'pagination'=>array(
'pageSize'=>10,
),
));
return $dataProvider;
}
How can I pass a NULL value to parameter of type NUMERIC?
All help will be much appreciated. Thanks in advance.
I solved it by checking for empty in the search function and using parameterized query. So the modified function is
public function search()
{
if(empty($this->tax_percentage))
$this->tax_percentage=null;
$count=Yii::app()->db->createCommand("SELECT COUNT(*) FROM search(:item_code,:tax_percentage)")->queryScalar();
$sql="SELECT * FROM search('$this->item_code','$this->tax_percentage')";
$dataProvider=new CSqlDataProvider($sql, array(
'params' => array(':item_code' => $this->item_code,':tax_percentage' => $this->tax_percentage),
'totalItemCount'=>$count,
'pagination'=>array(
'pageSize'=>10,
),
));
return $dataProvider;
}

PostgreSQL: plv8.start_proc

Set up startup procedure in config
plv8.start_proc = 'plv8_startup'
Created function:
CREATE OR REPLACE FUNCTION plv8_startup ()
RETURNS void AS
$body$
this.hello = function(name){
return name + ', hello!';
};
$body$
LANGUAGE 'plv8'
VOLATILE
CALLED ON NULL INPUT
SECURITY DEFINER
COST 100;
Under postgres user everything works well:
DO $$
plv8.elog(NOTICE, hello('John'));
$$ LANGUAGE plv8;
the result - John, hello!
Then created user test and tryed to run the function:
ERROR: ReferenceError: hello is not defined
SQL-state: XX000
tryied to grant user test on execute plv8_startup - the result is the same.
What is wrong?
It was my bug - function was created not in public schema, so system could not start it under the test user rights/