How to add subset of fields from stored procedure to table variable? - tsql

Declare #tempTableVariable Table(
email varchar(50)
)
Insert INTO #tempTableVariable
EXEC GetData
select email
from #tempTableVariable
I get the following error:
"Column name or number of supplied values does not match table definition."
Is there a simple way of getting a subset from GetData without explicitly declaring all the fields in the table variable declaration?

If you don't have control over the GetData stored procedure, I don't think there is any way you can get around having to declare all the fields in your table variable.
If you can control GetData, you could add a parameter to it that when equal to 1 would returnt the results the way you want them, and otherwise would do what it does currently.
I'll mention it for the sake of completeness, but there are lots of other options besides INSERT EXEC. http://www.sommarskog.se/share_data.html is a great explanation of the options.

Related

How can generic functions can be used for computed fields in hasura?

I've a logs table, which is it contains all the actions (updated, created) taken by operators (admin users).
On this table 2 of these columns (indexed as hash) target_entity and target_id Which respectively stores
table name: table name of the action taken on.
record id added or updated record's id in the target table.
So, what I am trying to achieve;
I would like to add a computed field named eg:logs which depends on a function;
FUNCTION public."fetchLogs"(
referenceId integer,
referenceName TEXT
)
First parameter is the current table's primary key.
I'm not sure if I can automatically send primary key as first argument
So probably it should be something like table_row table
Second parameter is a static value which is table's name, planning to statically pass as argument.
This function returns a JSON object;
RETURNS json LANGUAGE plpgsql STABLE
AS $function$
It should return log records related to this record.
At this point I have 2 things needs to be tackled with;
Since the first parameter is the reference (primary) key, I don't know If I can just use primary key as an argument. I'm guessing I need to use as table_row (anytable if that's a thing) then table_row.id
In the Hasura console, Add Computed Field > Function Name selector does not list this function, guessing because it doesn't explicitly indicated in the function which table is this action for.
Answers I'm looking for if this is achievable or is there a better practice for this kind of things?
Maybe I need a encapsulating function for each table needs this computed column. But I'm not sure is it possible or how can be done.
P.S. In case if you are wondering all primary keys are same type and name yes. All tables (will be using this computed column) has a primary key named as id and type is integer.

How to create tsvector_update_trigger on Non-character type data

How can we create tsvector update trigger on Non-character data type.
For example, i have created a ts vector trigger something like this.
CREATE TRIGGER tr_doc_id_col
BEFORE INSERT OR UPDATE
ON document
FOR EACH ROW
EXECUTE PROCEDURE tsvector_update_trigger('tsv_doc_id', 'pg_catalog.english', doc_id');
Here,
tr_doc_id_col -- Name of the trigger
document -- Name of the table
tsv_doc_id -- tsvector form of the doc_id
doc_id -- Name of the column. It's data type is integer
This trigger should update the tsv_doc_id, when there is insert, delete or update happens on doc_id column.
But, the trigger is throwing an error saying that doc_id is not of character type (i.e it is not able to update based on non-character type column).
I have tried creating same kind of triggers on columns like title, body which are text data type. In this case it is working very well, but in the earlier case.
Can any of you tell me how to do in the case of non-character data type like doc_id?
tsvector_update_trigger is just a convenience function, and it does what it does. You can always write your own implementation of it with whatever embellishments you want (in this case, casting to text), but you can't change the behavior of the existing one. But it is also rather obsolete. The modern way to do it is with GENERATED columns.
create table document (
doc_id int,
tsv_doc_id tsvector generated always as (to_tsvector('english',doc_id::text)) stored
);
Although I would question the utility of a tsvector which always contains exactly one integer.

What is the scope of Postgres policies?

I am trying to wrap my head around row level security in Postgres. Unfortunately the documentation is not very verbose on the matter. My problem is the following:
I have two tables: locations and locations_owners. There is a TRIGGER set on INSERT for locations, which will automatically add a new row to the locations_owners table including the request.jwt.claim.sub variable.
This works all just fine, however when I want to create a policy for DELETE like this:
CREATE POLICY location_delete ON eventzimmer.locations FOR DELETE TO organizer USING(
(SELECT EXISTS (SELECT name FROM protected.locations_owners AS owners WHERE owners.name = name AND owners.sub = (SELECT current_setting('request.jwt.claim.sub', true))))
);
It will always evaluate to true, no matter the actual content. I know that I can call a custom procedure with SELECT here, however I ended up with the following questions:
what is the scope of a policy? Can I access tables? Can I access procedures? The documentation says "Any SQL conditional expression" so SELECT EXISTS should be fine
how are the column names of the rows mapped to the policy. The examples just magically use the column names (which I adopted by using the name variable), however I have not found any documentation about what this actually does
what is the magic user_name variable. Where does it come from? I believe it is the current role which is executing the query, but how can I know?
why is there no WITH CHECK expression available for DELETE? If I understand correctly, WITH CHECK will fail any row with invalid constraint, which is the behaviour I would prefer (because otherwise PostgREST will always return 204)
I am a little bit confused by the astonishingly missing amount of information in the (otherwise) very good documentation of PostgreSQL. Where is this information? How can I find it?
For the sake of completeness I have also attached the column definitions below:
CREATE TABLE eventzimmer.locations (
name varchar PRIMARY KEY NOT NULL,
latitude float NOT NULL,
longitude float NOT NULL
);
CREATE TABLE IF NOT EXISTS protected.locations_owners (
name varchar NOT NULL REFERENCES eventzimmer.locations(name) ON DELETE CASCADE,
sub varchar NOT NULL
);
Many of the questions will become clear once you understand how row level security is implemented: the conditions in the policies will automatically be added to the query, just as if you added another WHERE condition.
Use EXPLAIN to see the query plan, and you will see the policy's conditions in there.
So you can use any columns from the table on which the policy is defined.
Essentially, you can use anything in a policy definition that you could use in a WHERE conditions: Function calls, subqueries and so on.
You can also qualify the column name with the table name if that is required for disambiguation. This can be used in the policy from your example: The unqualified name is interpreted as owners.name, so the test always succeeds. To fix the policy, use locations.name instead of name.
There is no magic user_name variable, and I don't know where you get that from. There is, however, the current_user function, which is always available and can of course also be used in a policy definition.
WITH CHECK is a condition that the new row added by INSERT or UPDATE must fulfill. Since DELETE doesn't add any data, WITH CHECK doesn't apply to it.

Getting error for auto increment fields when inserting records without specifying columns

We're in process of converting over from SQL Server to Postgres. I have a scenario that I am trying to accommodate. It involves inserting records from one table into another, WITHOUT listing out all of the columns. I realize this is not recommended practice, but let's set that aside for now.
drop table if exists pk_test_table;
create table public.pk_test_table
(
recordid SERIAL PRIMARY KEY NOT NULL,
name text
);
--example 1: works and will insert a record with an id of 1
insert into pk_test_table values(default,'puppies');
--example 2: fails
insert into pk_test_table
select first_name from person_test;
Error I receive in the second example:
column "recordid" is of type integer but expression is of type
character varying Hint: You will need to rewrite or cast the
expression.
The default keyword will tell the database to grab the next value.
Is there any way to utilize this keyword in the second example? Or some way to tell the database to ignore auto-incremented columns and just them be populated like normal?
I would prefer to not use a subquery to grab the next "id".
This functionality works in SQL Server and hence the question.
Thanks in advance for your help!
If you can't list column names, you should instead use the DEFAULT keyword, as you've done in the simple insert example. This won't work with a in insert into ... select ....
For that, you need to invoke nextval. A subquery is not required, just:
insert into pk_test_table
select nextval('pk_test_table_id_seq'), first_name from person_test;
You do need to know the sequence name. You could get that from information_schema based on the table name and inferring its primary key, using a function that takes just the table name as an argument. It'd be ugly, but it'd work. I don't think there's any way around needing to know the table name.
You're inserting value into the first column, but you need to add a value in the second position.
Therefore you can use INSERT INTO table(field) VALUES(value) syntax.
Since you need to fetch values from another table, you have to remove VALUES and put the subquery there.
insert into pk_test_table(name)
select first_name from person_test;
I hope it helps
I do it this way via a separate function- though I think I'm getting around the issue via the table level having the DEFAULT settings on a per field basis.
create table public.pk_test_table
(
recordid integer NOT NULL DEFAULT nextval('pk_test_table_id_seq'),
name text,
field3 integer NOT NULL DEFAULT 64,
null_field_if_not_set integer,
CONSTRAINT pk_test_table_pkey PRIMARY KEY ("recordid")
);
With function:
CREATE OR REPLACE FUNCTION func_pk_test_table() RETURNS void AS
$BODY$
INSERT INTO pk_test_table (name)
SELECT first_name FROM person_test;
$BODY$
LANGUAGE sql VOLATILE;
Then just execute the function via a SELECT FROM func_pk_test_table();
Notice it hasn't had to specify all the fields- as long as constraints allow it.

Create global variable in Postgresql

I am creating trigger for log table. In that trigger i want to store xuserno to log table. xuserno is a argument of all function
example:
CREATE OR REPLACE FUNCTION fn_consume(xmode text, xuserno integer)
RETURNS text AS
....
.....
.....
END;
Each table have this type of function. So how can i access the xuserno in my trigger. How can i create global variable for this purpose? or any other solution is have achive this?
It is possible to use transaction-local custom GUCs for this purpose but it's not usually a great idea.
In most cases it is preferable to just use an ON COMMIT DROP temporary table with a single row containing the value of interest.
See:
Passing user id to PostgreSQL triggers
How do you use script variables in PostgreSQL?