Type identifiers and anonymous types

Basic type identified by name
These can be quoted or unquoted, and with or without schema

unknown type: this is used for the types of literals in a kind of poor
mans type inference, modelled on postgresql's behaviour. Dialects can
choose not to use this approach and give a literal a type based only
on its syntax (and thus the dialect would never use the unknown
type. (The direct unknown typing isn't quite implemented yet).

any types

these are used to implement a kind of poor man's polymorphism. based
on the any types in postgresql. These are used for polymorphic
udfs. This is separate to overloading functions.

anonymous composite type

this represents a tuple of types, all, some or none of which can have
field names. This is used for composite types which are created on the
fly and don't have a name in the catalog or environment. Maybe this
should be changed so they are given a temporary name to reduce the
special cases

tref type

this is an internal type used by the typechecker (todo: can this be
hidden?) Maybe could add optional correlation names to the field names
in anonymous composite type and reuse that?

setof?
record?
void?

typeextra

ugly way to add nullability and precision to a type. This should get a
big rethink

step 1 todo:
combine composite and anonymous composite types
combine scalartype, domaintype, enum, named composite type

get rid of explicit array types and figure out a better way to handle
them

Split the errors into another module, and in the public api
The errors should contain not contain 'Type's.

figure out a better way of handling nullability, precision, scale than
the typeextra

> {-# LANGUAGE FlexibleInstances,DeriveDataTypeable,OverloadedStrings #-}
>
> module Database.HsSqlPpp.Internals.TypesInternal where
>
> import Data.Data
> --import Data.Generics.Uniplate.Data
> --import Data.Char
> import Data.Text (Text)
> --import qualified Data.Text as T
> --import Database.HsSqlPpp.Internals.Dialect
> --import Data.List
> --import Debug.Trace

> --import Control.Monad.Error
> --import Control.Monad.Except
> --import Control.Monad.Trans.Except

where should precision and nullability go?


TODO:
rename UnknownType to ScalarType "!unknown" ? or something else?
do we need separate entries for domain and enums?
think of a better way to implement array types - get rid of the
  special casing which is based on a postgresql implementation detail
get rid of pseudo types, maybe use ScalarType or SpecialType String
  which is dialect specific?

Maybe there should be a concept of a typeid, and a typedescription?
So the typeid is used everywhere and is just a string or something,
and the typedescription is got from the catalog/environment when
needed in the typechecking?


> -- | Standard types of things. This covers all the usual postgres types
> -- plus some extra ones added for use by the hssqlppp typechecker
> data Type = -- | basic type of a scalar value. These are either built in types
>             -- in postgres, or implemented in C or similar
>             ScalarType Text
>           -- | a domain type is used for a constraint on a table column which
>           -- would used on multiple columns on a table or in multiple tables,
>           -- using a domain type is a way of just writing the constraint once
>           | DomainType Text
>           -- | enum type, not really supported in hssqlppp yet
>           | EnumType Text
>           -- | String literals in postgres have an unknown type. The effective
>           -- type is determined using what seems to amount to some simple ad hoc rules
>           -- based on the context of the string literal. Hssqlppp also treats
>           -- ? placeholders and nulls the same way, so they have UnknownType,
>           -- not sure how closely this matches postgres
>           | UnknownType
>           -- | postgres automatically creates an array type for every scalar type
>           -- (plus some other types?) If there is no array type for a type in the
>           -- catalog, then you can't work with arrays of that type
>           | ArrayType Type
>           -- | refer to composite type in catalog by name. not sure if this needs
>           -- to exist along with CompositeType
>           | NamedCompositeType Text
>           -- | refer to composite type by structure
>           | CompositeType [(Text,TypeExtra)]
>           -- | CompositeTypeExtra [(Text,TypeExtra)]
>           -- | hack to support the environment for a tref
>           | TrefType [((Text,Text),TypeExtra)]
>           -- | the fields are anonymous as well as the type itself
>           | AnonymousCompositeType [Type]
>           -- | The pseudo type is used for types which only appear
>           -- as argument or return types in function definitions and/or
>           -- are used only in plpgsql and not regular sql. hssqlppp also
>           -- follows this usage for the types used in hssqlppp which don't
>           -- have an exact counterpart in postgres
>           | Pseudo PseudoType
>             deriving (Eq,Show,Ord,Typeable,Data)
>

> -- | Quick fix to add precision and nullable information to the
> -- annotation types. This approach should be revisited, maybe this
> -- information should be in the Type type?
> data TypeExtra = TypeExtra {teType :: Type
>                            ,tePrecision :: Maybe Int
>                            ,teScale :: Maybe Int
>                            ,teNullable :: Bool}
>                deriving (Eq,Ord,Show,Typeable,Data)
> mkTypeExtra :: Type -> TypeExtra
> mkTypeExtra t = TypeExtra t Nothing Nothing True
> mkTypeExtraNN :: Type -> TypeExtra
> mkTypeExtraNN t = TypeExtra t Nothing Nothing False
> mkNullable:: TypeExtra -> TypeExtra
> mkNullable te = te{teNullable=True}

> -- | Pseudo types: mainly used for the argument and return types of
> -- functions. The weird undocumented types are just used to represent
> -- functions with those types which are in the postgres default catalog
> data PseudoType =
>                 -- | setof is used for set returning functions
>                   SetOfType Type
>                   -- | used to represent polymorphic functions, all the
>                   -- AnyElement parameters and the return type if
>                   -- AnyElement must be the same type for a given function
>                   -- call invocation.
>                 | AnyElement
>                   -- | like AnyElement, but the type must be an array type
>                 | AnyArray
>                   -- | like AnyElement, but the type must be an enum type
>                 | AnyEnum
>                   -- | like AnyElement, but the type must be a non array type
>                 | AnyNonArray
>                 | AnyRange
>                   -- | Any drops the restriction that all the Any types must
>                   -- be the same type
>                 | Any
>                 -- | record types are used in plpgsql for a sort of dynamic
>                 -- typing or rough polymorphism substitute. They can refer to
>                 -- values of named composite type, composite type or
>                 -- anonymous composite type, not sure if non composite types as well.
>                 | Record (Maybe Type)
>                 -- | presumably used for the types of OLD and NEW in a trigger
>                 -- function. Hssqlppp will probably use the Record type above
>                 -- for these.
>                 --  | TriggerRecord
>                 --  | Trigger
>                 -- | cstring - a C string
>                 --  | Cstring
>                 -- | represents the return type of a function which doesn't return
>                 -- anything. Not sure if it is used anywhere else
>                 | Void
>                 --  | Internal
>                 --  | LanguageHandler
>                 --  | Opaque
>                 --  | FdwHandler
>                   deriving (Eq,Show,Ord,Typeable,Data)

TODO idea

> {-data Type = -- | A normal type identified by name. Includes scalar
>             -- types, domain types, enums, (non-anonymous)
>             -- structured types
>             Type (Maybe Text,Text)
>              -- | represents a unknown type like in postgres. Used
>              -- for literals in some dialects and a few other places
>           | UnknownType
>           | ArrayType Type
>           | CompositeType [(Text,TypeExtra)]
>           -- | hack to support the environment for a tref
>           | TrefType [((Text,Text),TypeExtra)]
>           -- | the fields are anonymous as well as the type itself
>           | AnonymousCompositeType [Type]
>           | SetOfType Type
>             -- | record types are used in plpgsql for a sort of dynamic
>             -- typing or rough polymorphism substitute. They can refer to
>             -- values of named composite type, composite type or
>             -- anonymous composite type, not sure if non composite types as well.
>           | Record (Maybe Type)
>             deriving (Eq,Show,Ord,Typeable,Data)-}


The possible type errors. This is a bit unorganised, at some point if
better error messages are wanted, then a lot more information could be
added.

> data TypeError = {-
>                | UnknownTypeError Type
>                | UnknownTypeName String
>                | NoMatchingOperator String [Type]
>                | TypelessEmptyArray
>                | IncompatibleTypeSet [Type]
>                | IncompatibleTypes Type Type
>                | ValuesListsMustBeSameLength
>                | NoRowsGivenForValues
>                | UnrecognisedIdentifier String
>                | UnrecognisedRelation String
>                | UnrecognisedCorrelationName String
>                | BadStarExpand
>                | ContextError String
>                | MissingJoinAttribute
>                | ExpressionMustBeBool
>                | WrongNumberOfColumns
>                | ExpectedDomainType Type
>                | BadCatalogUpdate String
>                | TypeAlreadyExists Type
>                | AnyAllError String
>                | InternalError String
>                | FromToTypesNotSame Type Type
>                | WrongNumberOfAliasCols Int Int

type conversion errors

>                | -} NoMatchingOperator Text [Type]
>                | AmbiguousOperator Text [Type]
>                | TypelessEmptyArray
>                | IncompatibleTypeSet [Type]
>                | IncompatibleTypes Type Type
>                | WrongNumberOfColumns
>                | WrongTypes Type [Type]
>                | IncompatibleUnionTypes Type Type


old catalog type errors: to be replaced when the catalog code is
gutted and rewritten

>                | TypeAlreadyExists Type
>                | SchemaAlreadyExists Text
>                | BadCatalogUpdate Text
>                | UnrecognisedRelation (Text,Text)
>                | DomainDefNotFound Type
>                | TypeNotKnown Type
>                | UnknownTypeName Text
>                | UnrecognisedIdentifier Text
>                | UnrecognisedCorrelationName Text
>                | SchemadColumnName Text
>                | DbSchemadColumnName Text
>                | BadStarExpand
>                | InternalError String
>                | AmbiguousIdentifier Text
>                | OdbcFuncBadContent
>                | DuplicateColumnName Text
>                | TooManyColumnsInInsert
>                  deriving (Eq,Show,Ord,Typeable,Data)
>