SOCI Cannot prepare statement - c++

I have a function like this:
CREATE OR REPLACE FUNCTION get_path_set_1(IN pathset_id_in character varying, OUT id character varying, OUT pathset_id character varying, OUT utility double precision)
RETURNS SETOF record AS
$BODY$
begin
if exists(SELECT 1 FROM "PathSet_Scaled_HITS_distinctODs" WHERE "ID" = $1) then
return query SELECT "ID", "PATHSET_ID", "UTILITY"
FROM "SinglePath_Scaled_HITS_distinctODs"
where "PATHSET_ID" = $1;
end if;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION get_path_set_1(character varying)
OWNER TO postgres;
when I call it in my program using this:
std::string testStr("43046,75502");// or std::string testStr("'43046,75502'");
soci::rowset<sim_mob::SinglePath> rs = (sql.prepare << "get_path_set_1(:pathset_id_in)",soci::use(testStr));
I get the following exception:
terminate called after throwing an instance of 'soci::postgresql_soci_error'
what(): Cannot prepare statement. ERROR: syntax error at or near "get_path_set_1"
LINE 1: get_path_set_1($1)
I will appreciate if you help me detect missing part
thank you

This does not solve the error you report. But simplify your function:
CREATE OR REPLACE FUNCTION get_path_set_1(pathset_id_in varchar)
RETURNS TABLE(id varchar, pathset_id varchar, utility double precision) AS
$func$
BEGIN
RETURN QUERY
SELECT "ID", "PATHSET_ID", "UTILITY"
FROM "SinglePath_Scaled_HITS_distinctODs"
WHERE "PATHSET_ID" = $1;
END
$func$ LANGUAGE plpgsql;
RETURNS TABLE is the modern, more elegant, equivalent form of the combination RETURNS SETOF record and OUT parameters.
IF exists ... is buying you nothing here. Run the query; if nothing is found, nothing is returned. Same result for half the cost.

From this piece of code:
soci::rowset<sim_mob::SinglePath> rs =
(sql.prepare << "get_path_set_1(:pathset_id_in)",soci::use(testStr));
it appears you're trying to prepare a query that just contains the function call without even a SELECT.
That's not valid in SQL. You want to prepare this query instead:
SELECT * FROM get_path_set_1(:pathset_id_in)
This form (select * from function(...)) is also necessary because the function returns a resultset with multiple columns, as opposed to just a scalar value.
Also as Erwin mentions, the OUT and SETOF RECORD are weird in this case, I'll second his advice on using RETURNS TABLE.

Related

Can I add a string type parameter to a SQL statement without quotes?

I have a C++Builder SQL Statement with a parameter like
UnicodeString SQLStatement = "INSERT INTO TABLENAME (DATETIME) VALUES (:dateTime)"
Can I add the parameter without quotes?
Usually I'd use
TADOQuery *query = new TADOQuery(NULL);
query->Parameters->CreateParameter("dateTime", ftString, pdInput, 255, DateTimeToStr(Now()));
which will eventually produce the SQL String
INSERT INTO TABLENAME (DATETIME) VALUES ('2022-01-14 14:33:00.000')
but because this is a legacy project (of course, it always is) and I have to maintain different database technologies, I need to be able to inject database specific date time conversion methods, so that the endresult would look like
INSERT INTO TABLENAME (DATETIME) VALUES (to_date('2022-01-14 14:33:00.000', 'dd.mm.yyyy hh24:mi:ss')))
If I try injecting this via my 'usual' method (because I don't think I can inject a second parameter into this one) it'd look like:
TADOQuery *query = new TADOQuery(NULL);
query->Parameters->CreateParameter("dateTime", ftInteger, pdInput, 255, "to_date('" + DateTimeToStr(Now()) + "', 'dd.mm.yyyy hh24:mi:ss')");
but of course the result would look like:
INSERT INTO TABLENAME (DATETIME) VALUES ('to_date('2022-01-14 14:33:00.000', 'dd.mm.yyyy hh24:mi:ss')'))
and therefore be invalid
Or is there another way to do this more cleanly and elegantly? Although I'd settle with 'working'.
I can work around this by preparing two SQL Statements and switch the statement when another database technology is but I just wanted to check if there is another way.
Why are you defining the parameter's DataType as ftInteger when your input value is clearly NOT an integer? You should be defining the DataType as ftDateTime instead, and then assigning Now() as-is to the parameter's Value. Let the database engine decide how it wants to format the date/time value in the final SQL per its own rules.
query->Parameters->CreateParameter("dateTime", ftDateTime, pdInput, 0, Now());

Parse data from table Greenplum

I have a table scheme2.central_id__new_numbers in Greenplum.
I need select data from scheme2.central_id__new_numbers in the form of a many-to-many relationship.
Also I write the code but must have made a wrong turn somewhere (the code doesn't work):
CREATE FUNCTION my_scheme.parse_new_numbers (varchar) RETURNS SETOF varchar as
$BODY$
declare
i int;
BEGIN
FOR i IN 1..10 LOOP
select
central_id,
(select regexp_split_to_table((select new_numbers
from scheme2.central_id__new_numbers limit 1 offset i), '\s+'))
from scheme2.central_id__new_numbers limit 1 offset i
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
I'd recommend using the UNNEST() function instead, i.e. assuming new_numbers column is of int[] data type,
SELECT central_id
, UNNEST(new_numbers) AS new_numbers
FROM central_id__new_numbers;
If new_columns column is not an array data type then you need to use i.e. string_to_array() or similar before using UNNEST().

Update column value from array element inside before insert trigger

i am trying to do a before insert trigger that updates one of the columns that will be inserted with a value taken from another column on the same record, however the catch is that that value is the first value of the said column after converting it to an array. when i include the function or the array i get a syntax error but the examples i have found for the proper syntax do not have the detail needed to make my code work. Here is my code:
Schema is as follows
create table events (
id int primary key,
performers varchar,
performer_id varchar
);
Function is:
create function events_set_performer() returns trigger
language plpgsql
as $$
declare
performer_ varchar := '0';
BEGIN
set NEW.performer_id = (string_to_array(NEW.performers,':'))[1];
return new;
END;
$$;

SQL String error? No Such Column

I'm using sqlite3 in my c++ program and am trying to run an SQL string in the
sqlite3_get_table function.
Here's my sql string.
SELECT name FROM sqlite_master WHERE type='table' AND name=test_table;
I keep getting the error "no such column "test_table"" .
All I am trying to do is confirm the existence of a table in my database. That's all.
Any clues as to what's wrong with my string.
In SQLite double quotes ('"') is the identifier-escape character, so assuming this is your SQL (raw SQL, nothing to do with C++):
SELECT
name
FROM
sqlite_master
WHERE
type = 'table'
AND
name = "test_table;"
Is equivalent to:
...
name = test_table
...which obviously isn't what you want.
You should use single-quoted strings in SQL, and the statement-terminating semicolon should go at the very end:
SELECT
name
FROM
sqlite_master
WHERE
type = 'table'
AND
name = 'test_table';

How do you insert variables into a database table using PostgreSQL via C++?

I have a C++ program that inserts values into a database table. I can't directly hardcode the values in because the data is constantly being updated, but I'm really confused about the syntax.
When I try to do this:
l.exec("INSERT INTO course VALUES(cid, term, 'subj',crse, sec, 'units', 'instructors');");
l.exec("INSERT INTO meeting VALUES(cid, term, 'type', 'days', 'time', 'build', room);");
l.exec("INSERT INTO enrolledin VALUES(cid, term, sid, 'major', 'classlevel', 'level', 'status', seat, numunits, 'grade');");
l.exec("INSERT INTO student VALUES(sid, 'surname', 'prefname', 'email');");
I get this error:
terminate called after throwing an instance of 'pqxx::undefined_column'
what(): ERROR: column "cid" does not exist
LINE 1: INSERT INTO course VALUES(cid, term, 'subj',crse, se...
^
HINT: There is a column named "cid" in table "course", but it cannot be referenced from this part of the query.
--
I was told that it's because I was inserting the literal string name instead of the values inside the string, and I'm confused as to how to insert the values inside the string via C++ while still using variable names.
Syntax of the used SQL INSERT query is incorrect. It should be:
INSERT INTO course (cid, subj) VALUES(1, 'subj');
You should specify table name together with columns to insert into and values after that. I reduced number of columns for simplicity. For a complete syntax of INSERT query check the PostgreSQL documentation.
To insert values from your variables you can do the following:
int cidValue = 1;
std::string subjValue = "subj";
l.exec("INSERT INTO course (cid, subj) VALUES(" + std::to_string(cidValue) + ", '" + l.esc(subjValue) + "')");
esc() function helps to prevent SQL injection attack.