Which part of PostgreSQL code is handling type definition? - postgresql

In PostgreSQL when I call NUMERIC(10,2) to define a variable type. Which part of the PostgreSQL C code is handling it?
I am interested in knowing where the precision and scale are handled.

Lots of parts.
The lexer and parser transforms it into a type name and type modifier.
The system catalogs and syscache look up numeric to find the matching type oid.
The numeric.c code handles the actual type input/output and operators, and interprets the type modifier.
The index access methods and index operator classes handle selection of operators for comparisons etc.

Related

Built-in list of numeric types in Matlab

Does Matlab provide a list of numeric datatypes?
Some functions, like zeros, take an optional typename argument, a string naming a numeric type (e.g., 'double' or 'uint8'), that determines the type of the returned array. I would like to add something similar to my own code, and a complete list of numeric types would help with argument validation, as in:
ip = inputParer()
...
ip.addParameter('DataType', 'double', #(x) ismember(x, numeric_types()));
It seems as though something similar must exist, but I haven't been able to find it.
isnumeric checks an instance, rather than the typename itself.
superclasses doesn't return anything for numeric types on 2018b.
Obviously, this is not hard to implement, but it'd be nice to use a built-in if it existed.

In PostgreSQL, which types can be cast with the type name first?

Reading the PostgreSQL docs, I see that you can cast a longish bit of text to xml like this:
SELECT xml '<long>long text, may span many lines</long>'
SELECT xml '...'
Curious, I found that I could do the same with JSON:
SELECT json '{"arg1":"val1", <more args spanning many lines>}'
(I couldn't find an official reference for this one. It just works!)
By contrast, this does not work:
SELECT float8 3.14159
I like this alternate syntax from a readability perspective. Now I'm looking for a reference listing which types may be specified up front like this. but I haven't found it yet.
Any pointers?
The documentation says:
A constant of an arbitrary type can be entered using any one of the following notations:
type 'string'
'string'::type
CAST ( 'string' AS type )
The string constant's text is passed to the input conversion routine for the type called type. The result is a constant of the indicated type. The explicit type cast can be omitted if there is no ambiguity as to the type the constant must be (for example, when it is assigned directly to a table column), in which case it is automatically coerced.
The form you are asking about is the first one.
So this can be used for all PostgreSQL types.
Note that the data must be specified as a string literal (in single or dollar quotes) when you use that syntax.

User defined postgresql types using Npgsql from F#

We use postgresql's features to the maximum to ease our development effort. We make heavy use of custom types (user defined types) in postgresql; most of our functions and stored procedures either take them as input parameters or return them.
We would like to make use of them from F#'s SqlDataProvider. That means we should somehow be able to tell F# how to map F# user type to postgresql user type. In other words
Postgresql has our defined user type post_user_defined
F# has our defined user type fsharp_user_defined
We should instruct Npgsql to somehow perform this mapping. My research so far points me to two approaches and none of them are completely clear to me. Any help is appreciated
Approach 1
NpgsqlTypes namespace has pre-defined set of postgresql types mapped to .NET out of box. Few of them are classes, others structures. Say I would like to use postgresql's built in type point which is mapped to .NET by Npgsql via NpgsqlPoint. I can map this to application specific data structure like this:
let point (x,y) = NpgsqlTypes.NpgsqlPoint(x,y)
(From PostgreSQLTests.fsx)
In this case, postgresql point and NpgsqlPoint (.NET) are already defined. Now I would like to do the same for my custom type.
Suppose the user defined postgresql composite is
create type product_t as ( name text, product_type text);
And the application data structure (F#) is the record
type product_f = {name :string; ptype :string }
or a tuple
type product_f = string * string
How do I tell Npgsql to make use of my type when passed as a parameter to postgresql functions/procedures? It looks like I will need to use NpgsqTypes.NpgsqlDbType.Composite or Npgsql.PostgresCompositeType which doesn't have a constructor that is public.
I am at a dead end here!
Approach 2
Taking cue from this post, I could create a custom type and register with MapCompositeGlobally and use it to pass to postgresql functions.So, here I try my hand at it
On Postgresql side, the type and functions are respectively
CREATE TYPE product_t AS
(name text,
product_type text)
and
func_product(p product_t) RETURNS void AS
And from my application in F#
type PgProductType(Name:string,ProductType:string)=
member this.Name = Name
member this.ProductType = ProductType
new() = PgProductType("","")
Npgsql.NpgsqlConnection.MapCompositeGlobally<PgProductType>("product_t",null)
and then
type Provider = SqlDataProvider
let ctx = Provider.GetDataContext()
let prd = new PgProductType("F#Product","")
ctx.Functions.FuncProduct.Invoke(prd);;
ctx.Functions.FuncIproduct.Invoke(prd);;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stdin(29,1): error FS0501: The member or object constructor 'Invoke' takes 0 argument(s) but is here given 1. The requir
ed signature is 'SqlDataProvider<...>.dataContext.Functions.FuncIproduct.Result.Invoke() : Unit'.
Its strange to note that the error reports that : constructor 'Invoke' takes 0 argument(s) but is here given 1. F# side of things are completely blind to the argument that postgresql function takes. It does recognize that the function FuncIproduct exists but blind to the arguments it takes.
Regarding your 1st approach, as you've understood NpgsqlTypes contains some types which Npgsql supports out of the box - but these are only PostgreSQL built-in types. You cannot add a new type into there without changing Npgsql's source code, which isn't something you want to do.
Also, you should understand the difference between user-defined types (which PostgreSQL calls "composite") and totally independent types such as point. The latter are full types (similar to int4), with their own custom binary representation, while the former aren't.
Your 2nd approach is the right one - Npgsql comes with full support for PostgreSQL composite types. I have no idea how SqlDataProvider functions - I'm assuming this is an F#-specific type provider - but once you've properly mapped your composite via MapCompositeGlobally, Npgsql allows you to write it transparently by setting an NpgsqlParameter's Value to an instance of PgProductType. It may be worth trying to get it working with type providers first.

PostgreSQL syntax error in parameterized query on "date $1"

Trying to parameterize my SQL queries (using libpq function PQexecParams), I was stuck on a syntax error:
SELECT date $1
The error is:
ERROR: syntax error at or near "$1"
Prepared statements
The explanation for this can be found in the chapter Constants of Other Types of the manual:
The ::, CAST(), and function-call syntaxes can also be used to specify
run-time type conversions of arbitrary expressions, as discussed in
Section 4.2.9. To avoid syntactic ambiguity, the type 'string' syntax
can only be used to specify the type of a simple literal constant.
Another restriction on the type 'string' syntax is that it does not
work for array types; use :: or CAST() to specify the type of an array
constant.
Bold emphasis mine.
Parameters for prepared statements are not actually sting literals but typed values, so you cannot use the form type 'string'. Use one of the other two forms to cast the value to a different type, like you found yourself already.
Example:
PREPARE foo AS SELECT $1::date;
EXECUTE foo('2005-1-1');
Similar for PQexecParams in the libpq C library
The documentation:
... In the SQL command text, attach an explicit cast to the parameter
symbol to show what data type you will send. For example:
SELECT * FROM mytable WHERE x = $1::bigint;
This forces parameter $1 to be treated as bigint, whereas by default
it would be assigned the same type as x. Forcing the parameter type
decision, either this way or by specifying a numeric type OID, is
strongly recommended. ...
The alternative, as mentioned in the quote above, is to pass the OIDs of respective data types with paramTypes[] - if you actually need the cast. In most cases it should work just fine to let Postgres derive data types from the query context.
paramTypes[]
Specifies, by OID, the data types to be assigned to the parameter
symbols. If paramTypes is NULL, or any particular element in the array
is zero, the server infers a data type for the parameter symbol in the
same way it would do for an untyped literal string.
You can get the OID of data types from the system catalog pg_type:
SELECT oid FROM pg_type WHERE typname = 'date';
You must use the correct internal type name. For instance: int4 for integer.
Or with a convenience cast to regtype:
SELECT 'date'::regtype::oid;
This is more flexible as known aliases for the type name are accepted as well. For instance: int4, int or integer for integer.
The solution is to use a type cast instead of date:
SELECT $1::date

Fortran numeric class

In fortran I can use Class (*) in a subroutine and use
Select Type (ir)
Type Is (Integer (Int8))
Type Is (Integer (Int16))
End Select
Does there exist any way to pass a numeric value rather than using Class (*), by using Class (Integer) for example or something similar.
Intrinsic types are not extended types, they have no common ancestor, nothing like that exist. You can use the unlimited polymorphism (class(*)) or you must indicate exact type and kind (real(dp)). You can also write type(real) in Fortran 2008, but that does not change anything, it is just a different syntax for the same.
Have a look at some common techniques for generic programming with different kinds like, for example, How to make some generic programming in fortran 90/95 working with intrinsic types , STL analogue in Fortran and others. You normally make a separate procedure for each kind and paste the code body from an include file.