Parameter in SELECT statement's fields list - error: Data type unknown - firebird

I have a problem with Firebird (embedded) database. I would like to set a parameter values in the select statement. For example:
SELECT name, surname, :string AS myText
FROM myTable
where :string is a parameter.
The above code works in SQLite and the result is (when the paramenter is "abcdef"):
+------+---------+---------+
|name |surname |myText |
+------+---------+---------+
|John |Black |abcdef |
+------+---------+---------+
|Thomas|Young |abcdef |
+------+---------+---------+
|... |... |abcdef |
+------+---------+---------+
|nameX |surnameY |abcdef |
+------+---------+---------+
When I try to execute this query then I get the following message: "An error was found in the application program input parameters for the SQL statement.
Dynamic SQL Error.
SQL error code = -804.
Data type unknown.

The problem is that Firebird needs to know the datatype of the parameter. IIRC in SQLite, everything is a string, but that is not the case in Firebird.
You will need to explicitly cast the parameter to inform Firebird about the expected type, for example:
SELECT name, surname, cast(? as varchar(100)) AS myText
FROM myTable
Where the ? is a positional parameter. Firebird doesn't have named parameters (except in procedures), but if your access library simulates named parameters, then probably the following will work as well:
SELECT name, surname, cast(:string as varchar(100)) AS myText
FROM myTable
The ability to cast parameters in the select-clause does not work in older Firebird version (I believe it was introduced in Firebird 2.5, but I'm not 100% sure).

Related

How to resolve syntax error with dynamic PostgreSQL statement

Suppose I have a table called my_table that has 3 columns
id | name | state
-----+------+--------
1020 | 'A ' | 'VA'
-----+------+--------
1021 | 'B' | 'VA'
-----+------+--------
1022 | 'C' | 'NC'
I am having an issue with a simple dynamic statement I am trying to run. I don't see anything wrong with this, do you?
EXECUTE 'SELECT * FROM my_schema.my_table WHERE id = '|| 1021;
I am just running this standalone. It should execute. Instead, I get a ERROR: syntax error at or near "'SELECT....
EXECUTE in plain SQL is used to run prepared statements.
Straight quote from the docs:
EXECUTE is used to execute a previously prepared statement. Since prepared statements only exist for the duration of a session, the prepared statement must have been created by a PREPARE statement executed earlier in the current session.
You're probably mixing it up with pl/pgsql EXECUTE, which is totally different.

Is there a way to organize Postgres Functions (using pgAdmin)?

I'm using pgAdmin 4.23, PostgreSQL 12.3 for Windows
Looks like all functions are dumped into one "folder". I installed the uuid and tablefunc extensions and they get tossed in with my own user defined functions. At least the 10 uuid ones are all prefixed with "uuid_". The 11 tablefunc ones all start with "connectby", "crosstab"*, "normal_rand".
I did prefix my own functions so those at least grouped together. But as this thing grows and I add extensions, I'm concerned that maintenance will become more difficult. Is there some sort of sub-foldering option I am missing, or is naming convention the normal approach for organization? Looks like stored procs would work the same way.
Would also be nice to be able to filter the Functions based on the names. I see the Search Objects popup, but it isn't as useful as a filter.
To filter functions based on their names you can use this function:
CREATE OR REPLACE FUNCTION public.find_function(fname text DEFAULT NULL::text)
RETURNS TABLE(routine_name text, routine_schema text, return_type text)
LANGUAGE sql
AS $function$
select routine_name, routine_schema, data_type
from information_schema.routines
where specific_schema not in ('pg_catalog', 'information_schema')
and case when fname is null then true else routine_name ~* fname end
order by routine_name;
$function$;
Here is an example - find all functions that have "test" in their name:
select * from find_function('test');
+-----------------------------+----------------+-------------+
| routine_name | routine_schema | return_type |
+-----------------------------+----------------+-------------+
| clear_web_tests | datavato | void |
+-----------------------------+----------------+-------------+
| etl_generic_tests | webaccess | text |
+-----------------------------+----------------+-------------+
| fill_web_tests | datavato | void |
+-----------------------------+----------------+-------------+
| pan_arguments_test | helpers | jsonb |
+-----------------------------+----------------+-------------+
| test_bizday | public | boolean |
+-----------------------------+----------------+-------------+
| test_checkdigits | public | boolean |
+-----------------------------+----------------+-------------+
| test_jasper_dynamic_columns | scratch | record |
+-----------------------------+----------------+-------------+
I'm adding this here in case it helps for future searches...
Per #horse_with_no_name's suggestion above, and the official documentation I went with a separate schema for my third-party stuff. Here is a bit from conversation with the other db people in our company:
I didn't want third party extensions (like uuid-ossp for Guids)
installed in my public schema since that is where we keep all of our
user defined functions specific to that database. When I originally
installed the extension I put it into the public schema, then just
transferred it to a schema named extfunc. Then we have a table named
usr that references extfunc.uuid_generate_v4() in one of the column
constraints. Everything works as expected.
However, when I try to backup our Dev db and restore to QA, the
pg_dump and pg_restore tasks do not handle it properly. The restore
would error and not create the usr table. The extension was not being
properly restored to extfunc, which prevented the usr table from being
created.
The solution is to create the extension in the desired schema from the
start. Do not create it and try and move it to the destination
schema. Backup/restore now work as expected.

How to explicitly set type of constant value in SELECT clause [duplicate]

I have a problem with Firebird (embedded) database. I would like to set a parameter values in the select statement. For example:
SELECT name, surname, :string AS myText
FROM myTable
where :string is a parameter.
The above code works in SQLite and the result is (when the paramenter is "abcdef"):
+------+---------+---------+
|name |surname |myText |
+------+---------+---------+
|John |Black |abcdef |
+------+---------+---------+
|Thomas|Young |abcdef |
+------+---------+---------+
|... |... |abcdef |
+------+---------+---------+
|nameX |surnameY |abcdef |
+------+---------+---------+
When I try to execute this query then I get the following message: "An error was found in the application program input parameters for the SQL statement.
Dynamic SQL Error.
SQL error code = -804.
Data type unknown.
The problem is that Firebird needs to know the datatype of the parameter. IIRC in SQLite, everything is a string, but that is not the case in Firebird.
You will need to explicitly cast the parameter to inform Firebird about the expected type, for example:
SELECT name, surname, cast(? as varchar(100)) AS myText
FROM myTable
Where the ? is a positional parameter. Firebird doesn't have named parameters (except in procedures), but if your access library simulates named parameters, then probably the following will work as well:
SELECT name, surname, cast(:string as varchar(100)) AS myText
FROM myTable
The ability to cast parameters in the select-clause does not work in older Firebird version (I believe it was introduced in Firebird 2.5, but I'm not 100% sure).

List tables in a PostgreSQL schema

When I do a \dt in psql I only get a listing of tables in the current schema (public by default).
How can I get a list of all tables in all schemas or a particular schema?
In all schemas:
=> \dt *.*
In a particular schema:
=> \dt public.*
It is possible to use regular expressions with some restrictions
\dt (public|s).(s|t)
List of relations
Schema | Name | Type | Owner
--------+------+-------+-------
public | s | table | cpn
public | t | table | cpn
s | t | table | cpn
Advanced users can use regular-expression notations such as character classes, for example [0-9] to match any digit. All regular expression special characters work as specified in Section 9.7.3, except for . which is taken as a separator as mentioned above, * which is translated to the regular-expression notation .*, ? which is translated to ., and $ which is matched literally. You can emulate these pattern characters at need by writing ? for ., (R+|) for R*, or (R|) for R?. $ is not needed as a regular-expression character since the pattern must match the whole name, unlike the usual interpretation of regular expressions (in other words, $ is automatically appended to your pattern). Write * at the beginning and/or end if you don't wish the pattern to be anchored. Note that within double quotes, all regular expression special characters lose their special meanings and are matched literally. Also, the regular expression special characters are matched literally in operator name patterns (i.e., the argument of \do).
You can select the tables from information_schema
SELECT * FROM information_schema.tables
WHERE table_schema = 'public'
Alternatively to information_schema it is possible to use pg_tables:
select * from pg_tables where schemaname='public';
For those coming across this in the future:
If you would like to see a list of relations for several schemas:
$psql mydatabase
mydatabase=# SET search_path TO public, usa; #schema examples
SET
mydatabase=# \dt
List of relations
Schema | Name | Type | Owner
--------+-----------------+-------+----------
public | counties | table | postgres
public | spatial_ref_sys | table | postgres
public | states | table | postgres
public | us_cities | table | postgres
usa | census2010 | table | postgres
If you are interested in listing all tables in a particular schema, I found this answer relevant :
SELECT table_schema||'.'||table_name AS full_rel_name
FROM information_schema.tables
WHERE table_schema = 'yourschemaname';

Why is this postgres function failing only on one specifc database?

I'm trying to fix an issue with a legacy database. The quote_literal function is not working for a specific database on an 8.4 install of postgres.
Here's my results on a fresh test database:
select quote_literal(42);
quote_literal
---------------
'42'
(1 row)
And now the same on the target db
select quote_literal(42);
ERROR: function quote_literal(integer) is not unique
LINE 1: select quote_literal(42);
^
HINT: Could not choose a best candidate function. You might need to add explicit type casts.
AIUI, the quote_literal(anyvalue) function should handle integer values ok, and this seems to be upheld by the first test.
So I figured the quote_literal function must have been overridden in this db but no this doesn't seem to be the case. I could override it with a specific quote_literal(integer) function but I don't see why I should have to.
The question is what is could be causing the failure of this function in this specific database whilst not affecting the fresh db?
Another possibility: Somebody has added implicit casts from text to your database. This was a common workaround for an intentional BC break in 8.3. See the release notes for 8.3, E.57.2. Migration to Version 8.3
Demo:
regress=# \df quote_literal
List of functions
Schema | Name | Result data type | Argument data types | Type
------------+---------------+------------------+---------------------+--------
pg_catalog | quote_literal | text | anyelement | normal
pg_catalog | quote_literal | text | text | normal
(2 rows)
regress=# CREATE FUNCTION pg_catalog.text(integer) RETURNS text STRICT IMMUTABLE LANGUAGE SQL AS 'SELECT textin(int4out($1));';
CREATE FUNCTION
regress=# CREATE CAST (integer AS text) WITH FUNCTION pg_catalog.text(integer) AS IMPLICIT;
CREATE CAST
regress=# SELECT quote_literal(42);
ERROR: function quote_literal(integer) is not unique
LINE 1: SELECT quote_literal(42);
^
HINT: Could not choose a best candidate function. You might need to add explicit type casts.
regress=#
This'll fix it, but probably break other code that's still relying on the cast:
regress=# DROP CAST (integer AS text);
DROP CAST
regress=# SELECT quote_literal(42);
quote_literal
---------------
'42'
(1 row)
Somebody has probably defined another single-argument quote_literal function with an argument type that's assignment-compatible to integer, like bigint.
In psql, connect and run:
\df quote_literal
and you'll see multiple entries, like this:
regress=> \df quote_literal
List of functions
Schema | Name | Result data type | Argument data types | Type
------------+---------------+------------------+---------------------+--------
pg_catalog | quote_literal | text | anyelement | normal
pg_catalog | quote_literal | text | text | normal
public | quote_literal | text | bigint | normal
(3 rows)
You only want the 1st two, in pg_catalog. However, I can't advise you to just:
DROP FUNCTION public.quote_literal(bigint);
... because you might have code that expects it to exist. Time to go digging and see where it's used. Have fun.
Demo showing that this is likely the problem:
regress=> SELECT quote_literal(42);
quote_literal
---------------
'42'
(1 row)
regress=> CREATE OR REPLACE FUNCTION quote_literal(bigint) RETURNS text AS 'SELECT ''borkborkbork''::text;' LANGUAGE sql;
CREATE FUNCTION
regress=> SELECT quote_literal(42);
ERROR: function quote_literal(integer) is not unique
LINE 1: SELECT quote_literal(42);
^
HINT: Could not choose a best candidate function. You might need to add explicit type casts.
regress=>