postgresql-typed 0.4.4 → 0.4.5
raw patch · 16 files changed
+2375/−185 lines, 16 filesdep +HDBCdep +HUnitdep +convertibledep ~base
Dependencies added: HDBC, HUnit, convertible
Dependency ranges changed: base
Files
- Database/PostgreSQL/Typed.hs +2/−2
- Database/PostgreSQL/Typed/Array.hs +3/−0
- Database/PostgreSQL/Typed/Dynamic.hs +7/−10
- Database/PostgreSQL/Typed/Enum.hs +19/−8
- Database/PostgreSQL/Typed/ErrCodes.hs +1506/−0
- Database/PostgreSQL/Typed/HDBC.hs +352/−0
- Database/PostgreSQL/Typed/Internal.hs +0/−51
- Database/PostgreSQL/Typed/Protocol.hs +198/−62
- Database/PostgreSQL/Typed/Query.hs +15/−21
- Database/PostgreSQL/Typed/Range.hs +1/−1
- Database/PostgreSQL/Typed/SQLToken.hs +131/−0
- Database/PostgreSQL/Typed/TH.hs +15/−4
- Database/PostgreSQL/Typed/Types.hs +43/−11
- postgresql-typed.cabal +30/−10
- test/Main.hs +37/−5
- test/hdbc/runtests.hs +16/−0
Database/PostgreSQL/Typed.hs view
@@ -115,7 +115,7 @@ -- There are two steps to running a query: a Template Haskell quasiquoter to perform type-inference at compile time and create a 'PGQuery'; and a run-time function to execute the query ('pgRunQuery', 'pgQuery', 'pgExecute'). -- $compile--- Both TH functions take a single SQL string, which may contain in-line placeholders of the form @${expr}@ (where @expr@ is any valid Haskell expression that does not contain @{}@) and/or PostgreSQL placeholders of the form @$1@, @$2@, etc.+-- Both TH functions take a single SQL string, which may contain in-line placeholders of the form @${expr}@ (where @expr@ is any valid Haskell expression) and/or PostgreSQL placeholders of the form @$1@, @$2@, etc. -- -- > let q = [pgSQL|SELECT id, name, address FROM people WHERE name LIKE ${query++"%"} OR email LIKE $1|] :: PGSimpleQuery [(Int32, String, Maybe String)] --@@ -125,7 +125,7 @@ -- -- > [pgSQL|SELECT id FROM people WHERE name = $1|] :: String -> PGSimpleQuery [Int32] ----- To produce 'PGPreparedQuery' objects instead, put a single @$@ at the beginning of the query.+-- To produce 'PGPreparedQuery' objects instead of 'PGSimpleQuery', put a single @$@ at the beginning of the query. -- You can also create queries at run-time using 'rawPGSimpleQuery' or 'rawPGPreparedQuery'. -- $run
Database/PostgreSQL/Typed/Array.hs view
@@ -1,5 +1,8 @@ {-# LANGUAGE CPP, MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies, UndecidableInstances, DataKinds, OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-}+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif -- | -- Module: Database.PostgreSQL.Typed.Array -- Copyright: 2015 Dylan Simon
Database/PostgreSQL/Typed/Dynamic.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, FunctionalDependencies, UndecidableInstances, DataKinds, DefaultSignatures, PatternGuards, GADTs, TemplateHaskell #-}+{-# LANGUAGE CPP, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, FunctionalDependencies, UndecidableInstances, DataKinds, DefaultSignatures, PatternGuards, GADTs, TemplateHaskell, AllowAmbiguousTypes #-} -- | -- Module: Database.PostgreSQL.Typed.Dynamic -- Copyright: 2015 Dylan Simon@@ -36,8 +36,8 @@ import Language.Haskell.Meta.Parse (parseExp) import qualified Language.Haskell.TH as TH -import Database.PostgreSQL.Typed.Internal import Database.PostgreSQL.Typed.Types+import Database.PostgreSQL.Typed.SQLToken -- |Represents canonical/default PostgreSQL representation for various Haskell types, allowing convenient type-driven marshalling. class PGType t => PGRep t a | a -> t where@@ -95,6 +95,7 @@ #endif instance PGRep "date" Time.Day instance PGRep "time without time zone" Time.TimeOfDay+instance PGRep "time with time zone" (Time.TimeOfDay, Time.TimeZone) instance PGRep "timestamp without time zone" Time.LocalTime instance PGRep "timestamp with time zone" Time.UTCTime instance PGRep "interval" Time.DiffTime@@ -110,12 +111,8 @@ -- This lets you do safe, type-driven literal substitution into SQL fragments without needing a full query, bypassing placeholder inference and any prepared queries, for example when using 'Database.PostgreSQL.Typed.Protocol.pgSimpleQuery' or 'Database.PostgreSQL.Typed.Protocol.pgSimpleQueries_'. -- Unlike most other TH functions, this does not require any database connection. pgSubstituteLiterals :: String -> TH.ExpQ-pgSubstituteLiterals sql = TH.AppE (TH.VarE 'BSL.fromChunks) . TH.ListE <$> ssl (sqlSplitExprs sql) where- ssl :: SQLSplit String 'True -> TH.Q [TH.Exp]- ssl (SQLLiteral s l) = (TH.VarE 'fromString `TH.AppE` stringE s :) <$> ssp l- ssl SQLSplitEnd = return []- ssp :: SQLSplit String 'False -> TH.Q [TH.Exp]- ssp (SQLPlaceholder e l) = do+pgSubstituteLiterals sql = TH.AppE (TH.VarE 'BSL.fromChunks) . TH.ListE <$> mapM sst (sqlTokens sql) where+ sst (SQLExpr e) = do v <- either (fail . (++) ("Failed to parse expression {" ++ e ++ "}: ")) return $ parseExp e- (TH.VarE 'pgSafeLiteral `TH.AppE` v :) <$> ssl l- ssp SQLSplitEnd = return []+ return $ TH.VarE 'pgSafeLiteral `TH.AppE` v+ sst t = return $ TH.VarE 'fromString `TH.AppE` TH.LitE (TH.StringL $ show t)
Database/PostgreSQL/Typed/Enum.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TemplateHaskell, FlexibleInstances, MultiParamTypeClasses, DataKinds #-}+{-# LANGUAGE CPP, TemplateHaskell, FlexibleInstances, MultiParamTypeClasses, DataKinds #-} -- | -- Module: Database.PostgreSQL.Typed.Enum -- Copyright: 2015 Dylan Simon@@ -57,18 +57,25 @@ valn = map (\[PGTextValue v] -> let u = BSC.unpack v in (TH.mkName $ valnf u, map (TH.IntegerL . fromIntegral) $ BS.unpack v, TH.StringL u)) vals dv <- TH.newName "x" return- [ TH.DataD [] typn [] (map (\(n, _, _) -> TH.NormalC n []) valn)+ [ TH.DataD [] typn []+#if MIN_VERSION_template_haskell(2,11,0)+ Nothing+#endif+ (map (\(n, _, _) -> TH.NormalC n []) valn) $+#if MIN_VERSION_template_haskell(2,11,0)+ map TH.ConT+#endif [''Eq, ''Ord, ''Enum, ''Ix, ''Bounded, ''Typeable]- , TH.InstanceD [] (TH.ConT ''Show `TH.AppT` typt)+ , instanceD [] (TH.ConT ''Show `TH.AppT` typt) [ TH.FunD 'show $ map (\(n, _, v) -> TH.Clause [TH.ConP n []] (TH.NormalB $ TH.LitE v) []) valn ]- , TH.InstanceD [] (TH.ConT ''PGType `TH.AppT` typl) []- , TH.InstanceD [] (TH.ConT ''PGParameter `TH.AppT` typl `TH.AppT` typt)+ , instanceD [] (TH.ConT ''PGType `TH.AppT` typl) []+ , instanceD [] (TH.ConT ''PGParameter `TH.AppT` typl `TH.AppT` typt) [ TH.FunD 'pgEncode $ map (\(n, l, _) -> TH.Clause [TH.WildP, TH.ConP n []] (TH.NormalB $ TH.VarE 'BS.pack `TH.AppE` TH.ListE (map TH.LitE l)) []) valn ]- , TH.InstanceD [] (TH.ConT ''PGColumn `TH.AppT` typl `TH.AppT` typt)+ , instanceD [] (TH.ConT ''PGColumn `TH.AppT` typl `TH.AppT` typt) [ TH.FunD 'pgDecode [TH.Clause [TH.WildP, TH.VarP dv] (TH.NormalB $ TH.CaseE (TH.VarE 'BS.unpack `TH.AppE` TH.VarE dv) $ map (\(n, l, _) -> TH.Match (TH.ListP (map TH.LitP l)) (TH.NormalB $ TH.ConE n) []) valn ++@@ -77,10 +84,14 @@ []]) []] ]- , TH.InstanceD [] (TH.ConT ''PGRep `TH.AppT` typl `TH.AppT` typt) []- , TH.InstanceD [] (TH.ConT ''PGEnum `TH.AppT` typt) []+ , instanceD [] (TH.ConT ''PGRep `TH.AppT` typl `TH.AppT` typt) []+ , instanceD [] (TH.ConT ''PGEnum `TH.AppT` typt) [] ] where typn = TH.mkName typs typt = TH.ConT typn typl = TH.LitT (TH.StrTyLit name)+ instanceD = TH.InstanceD+#if MIN_VERSION_template_haskell(2,11,0)+ Nothing+#endif
+ Database/PostgreSQL/Typed/ErrCodes.hs view
@@ -0,0 +1,1506 @@+-- Automatically generated from /src/postgresql-9.5.3/src/src/backend/utils/errcodes.txt using errcodes.hs 2016-09-28 20:17:05.706135604 UTC.+{-# LANGUAGE OverloadedStrings #-}+-- |PostgreSQL error codes.+module Database.PostgreSQL.Typed.ErrCodes (names+ -- * Class 00 - Successful Completion+ , successful_completion+ -- * Class 01 - Warning+ , warning+ , warning_dynamic_result_sets_returned+ , warning_implicit_zero_bit_padding+ , warning_null_value_eliminated_in_set_function+ , warning_privilege_not_granted+ , warning_privilege_not_revoked+ , warning_string_data_right_truncation+ , warning_deprecated_feature+ -- * Class 02 - No Data (this is also a warning class per the SQL standard)+ , no_data+ , no_additional_dynamic_result_sets_returned+ -- * Class 03 - SQL Statement Not Yet Complete+ , sql_statement_not_yet_complete+ -- * Class 08 - Connection Exception+ , connection_exception+ , connection_does_not_exist+ , connection_failure+ , sqlclient_unable_to_establish_sqlconnection+ , sqlserver_rejected_establishment_of_sqlconnection+ , transaction_resolution_unknown+ , protocol_violation+ -- * Class 09 - Triggered Action Exception+ , triggered_action_exception+ -- * Class 0A - Feature Not Supported+ , feature_not_supported+ -- * Class 0B - Invalid Transaction Initiation+ , invalid_transaction_initiation+ -- * Class 0F - Locator Exception+ , locator_exception+ , invalid_locator_specification+ -- * Class 0L - Invalid Grantor+ , invalid_grantor+ , invalid_grant_operation+ -- * Class 0P - Invalid Role Specification+ , invalid_role_specification+ -- * Class 0Z - Diagnostics Exception+ , diagnostics_exception+ , stacked_diagnostics_accessed_without_active_handler+ -- * Class 20 - Case Not Found+ , case_not_found+ -- * Class 21 - Cardinality Violation+ , cardinality_violation+ -- * Class 22 - Data Exception+ , data_exception+ , _ARRAY_ELEMENT_ERROR+ , array_subscript_error+ , character_not_in_repertoire+ , datetime_field_overflow+ , _DATETIME_VALUE_OUT_OF_RANGE+ , division_by_zero+ , error_in_assignment+ , escape_character_conflict+ , indicator_overflow+ , interval_field_overflow+ , invalid_argument_for_logarithm+ , invalid_argument_for_ntile_function+ , invalid_argument_for_nth_value_function+ , invalid_argument_for_power_function+ , invalid_argument_for_width_bucket_function+ , invalid_character_value_for_cast+ , invalid_datetime_format+ , invalid_escape_character+ , invalid_escape_octet+ , invalid_escape_sequence+ , nonstandard_use_of_escape_character+ , invalid_indicator_parameter_value+ , invalid_parameter_value+ , invalid_regular_expression+ , invalid_row_count_in_limit_clause+ , invalid_row_count_in_result_offset_clause+ , invalid_tablesample_argument+ , invalid_tablesample_repeat+ , invalid_time_zone_displacement_value+ , invalid_use_of_escape_character+ , most_specific_type_mismatch+ , null_value_not_allowed+ , null_value_no_indicator_parameter+ , numeric_value_out_of_range+ , string_data_length_mismatch+ , string_data_right_truncation+ , substring_error+ , trim_error+ , unterminated_c_string+ , zero_length_character_string+ , floating_point_exception+ , invalid_text_representation+ , invalid_binary_representation+ , bad_copy_file_format+ , untranslatable_character+ , not_an_xml_document+ , invalid_xml_document+ , invalid_xml_content+ , invalid_xml_comment+ , invalid_xml_processing_instruction+ -- * Class 23 - Integrity Constraint Violation+ , integrity_constraint_violation+ , restrict_violation+ , not_null_violation+ , foreign_key_violation+ , unique_violation+ , check_violation+ , exclusion_violation+ -- * Class 24 - Invalid Cursor State+ , invalid_cursor_state+ -- * Class 25 - Invalid Transaction State+ , invalid_transaction_state+ , active_sql_transaction+ , branch_transaction_already_active+ , held_cursor_requires_same_isolation_level+ , inappropriate_access_mode_for_branch_transaction+ , inappropriate_isolation_level_for_branch_transaction+ , no_active_sql_transaction_for_branch_transaction+ , read_only_sql_transaction+ , schema_and_data_statement_mixing_not_supported+ , no_active_sql_transaction+ , in_failed_sql_transaction+ -- * Class 26 - Invalid SQL Statement Name+ , invalid_sql_statement_name+ -- * Class 27 - Triggered Data Change Violation+ , triggered_data_change_violation+ -- * Class 28 - Invalid Authorization Specification+ , invalid_authorization_specification+ , invalid_password+ -- * Class 2B - Dependent Privilege Descriptors Still Exist+ , dependent_privilege_descriptors_still_exist+ , dependent_objects_still_exist+ -- * Class 2D - Invalid Transaction Termination+ , invalid_transaction_termination+ -- * Class 2F - SQL Routine Exception+ , sql_routine_exception+ , s_r_e_function_executed_no_return_statement+ , s_r_e_modifying_sql_data_not_permitted+ , s_r_e_prohibited_sql_statement_attempted+ , s_r_e_reading_sql_data_not_permitted+ -- * Class 34 - Invalid Cursor Name+ , invalid_cursor_name+ -- * Class 38 - External Routine Exception+ , external_routine_exception+ , e_r_e_containing_sql_not_permitted+ , e_r_e_modifying_sql_data_not_permitted+ , e_r_e_prohibited_sql_statement_attempted+ , e_r_e_reading_sql_data_not_permitted+ -- * Class 39 - External Routine Invocation Exception+ , external_routine_invocation_exception+ , e_r_i_e_invalid_sqlstate_returned+ , e_r_i_e_null_value_not_allowed+ , e_r_i_e_trigger_protocol_violated+ , e_r_i_e_srf_protocol_violated+ , e_r_i_e_event_trigger_protocol_violated+ -- * Class 3B - Savepoint Exception+ , savepoint_exception+ , invalid_savepoint_specification+ -- * Class 3D - Invalid Catalog Name+ , invalid_catalog_name+ -- * Class 3F - Invalid Schema Name+ , invalid_schema_name+ -- * Class 40 - Transaction Rollback+ , transaction_rollback+ , transaction_integrity_constraint_violation+ , serialization_failure+ , statement_completion_unknown+ , deadlock_detected+ -- * Class 42 - Syntax Error or Access Rule Violation+ , syntax_error_or_access_rule_violation+ , syntax_error+ , insufficient_privilege+ , cannot_coerce+ , grouping_error+ , windowing_error+ , invalid_recursion+ , invalid_foreign_key+ , invalid_name+ , name_too_long+ , reserved_name+ , datatype_mismatch+ , indeterminate_datatype+ , collation_mismatch+ , indeterminate_collation+ , wrong_object_type+ , undefined_column+ , _UNDEFINED_CURSOR+ , _UNDEFINED_DATABASE+ , undefined_function+ , _UNDEFINED_PSTATEMENT+ , _UNDEFINED_SCHEMA+ , undefined_table+ , undefined_parameter+ , undefined_object+ , duplicate_column+ , duplicate_cursor+ , duplicate_database+ , duplicate_function+ , duplicate_prepared_statement+ , duplicate_schema+ , duplicate_table+ , duplicate_alias+ , duplicate_object+ , ambiguous_column+ , ambiguous_function+ , ambiguous_parameter+ , ambiguous_alias+ , invalid_column_reference+ , invalid_column_definition+ , invalid_cursor_definition+ , invalid_database_definition+ , invalid_function_definition+ , invalid_prepared_statement_definition+ , invalid_schema_definition+ , invalid_table_definition+ , invalid_object_definition+ -- * Class 44 - WITH CHECK OPTION Violation+ , with_check_option_violation+ -- * Class 53 - Insufficient Resources+ , insufficient_resources+ , disk_full+ , out_of_memory+ , too_many_connections+ , configuration_limit_exceeded+ -- * Class 54 - Program Limit Exceeded+ , program_limit_exceeded+ , statement_too_complex+ , too_many_columns+ , too_many_arguments+ -- * Class 55 - Object Not In Prerequisite State+ , object_not_in_prerequisite_state+ , object_in_use+ , cant_change_runtime_param+ , lock_not_available+ -- * Class 57 - Operator Intervention+ , operator_intervention+ , query_canceled+ , admin_shutdown+ , crash_shutdown+ , cannot_connect_now+ , database_dropped+ -- * Class 58 - System Error (errors external to PostgreSQL itself)+ , system_error+ , io_error+ , undefined_file+ , duplicate_file+ -- * Class F0 - Configuration File Error+ , config_file_error+ , lock_file_exists+ -- * Class HV - Foreign Data Wrapper Error (SQL/MED)+ , fdw_error+ , fdw_column_name_not_found+ , fdw_dynamic_parameter_value_needed+ , fdw_function_sequence_error+ , fdw_inconsistent_descriptor_information+ , fdw_invalid_attribute_value+ , fdw_invalid_column_name+ , fdw_invalid_column_number+ , fdw_invalid_data_type+ , fdw_invalid_data_type_descriptors+ , fdw_invalid_descriptor_field_identifier+ , fdw_invalid_handle+ , fdw_invalid_option_index+ , fdw_invalid_option_name+ , fdw_invalid_string_length_or_buffer_length+ , fdw_invalid_string_format+ , fdw_invalid_use_of_null_pointer+ , fdw_too_many_handles+ , fdw_out_of_memory+ , fdw_no_schemas+ , fdw_option_name_not_found+ , fdw_reply_handle+ , fdw_schema_not_found+ , fdw_table_not_found+ , fdw_unable_to_create_execution+ , fdw_unable_to_create_reply+ , fdw_unable_to_establish_connection+ -- * Class P0 - PL/pgSQL Error+ , plpgsql_error+ , raise_exception+ , no_data_found+ , too_many_rows+ , assert_failure+ -- * Class XX - Internal Error+ , internal_error+ , data_corrupted+ , index_corrupted+) where++import Data.ByteString (ByteString)+import Data.Map.Strict (Map, fromDistinctAscList)++-- |@SUCCESSFUL_COMPLETION@: 00000 (Success)+successful_completion :: ByteString+successful_completion = "00000"++-- |@WARNING@: 01000 (Warning)+warning :: ByteString+warning = "01000"++-- |@WARNING_DYNAMIC_RESULT_SETS_RETURNED@: 0100C (Warning)+warning_dynamic_result_sets_returned :: ByteString+warning_dynamic_result_sets_returned = "0100C"++-- |@WARNING_IMPLICIT_ZERO_BIT_PADDING@: 01008 (Warning)+warning_implicit_zero_bit_padding :: ByteString+warning_implicit_zero_bit_padding = "01008"++-- |@WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION@: 01003 (Warning)+warning_null_value_eliminated_in_set_function :: ByteString+warning_null_value_eliminated_in_set_function = "01003"++-- |@WARNING_PRIVILEGE_NOT_GRANTED@: 01007 (Warning)+warning_privilege_not_granted :: ByteString+warning_privilege_not_granted = "01007"++-- |@WARNING_PRIVILEGE_NOT_REVOKED@: 01006 (Warning)+warning_privilege_not_revoked :: ByteString+warning_privilege_not_revoked = "01006"++-- |@WARNING_STRING_DATA_RIGHT_TRUNCATION@: 01004 (Warning)+warning_string_data_right_truncation :: ByteString+warning_string_data_right_truncation = "01004"++-- |@WARNING_DEPRECATED_FEATURE@: 01P01 (Warning)+warning_deprecated_feature :: ByteString+warning_deprecated_feature = "01P01"++-- |@NO_DATA@: 02000 (Warning)+no_data :: ByteString+no_data = "02000"++-- |@NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED@: 02001 (Warning)+no_additional_dynamic_result_sets_returned :: ByteString+no_additional_dynamic_result_sets_returned = "02001"++-- |@SQL_STATEMENT_NOT_YET_COMPLETE@: 03000 (Error)+sql_statement_not_yet_complete :: ByteString+sql_statement_not_yet_complete = "03000"++-- |@CONNECTION_EXCEPTION@: 08000 (Error)+connection_exception :: ByteString+connection_exception = "08000"++-- |@CONNECTION_DOES_NOT_EXIST@: 08003 (Error)+connection_does_not_exist :: ByteString+connection_does_not_exist = "08003"++-- |@CONNECTION_FAILURE@: 08006 (Error)+connection_failure :: ByteString+connection_failure = "08006"++-- |@SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION@: 08001 (Error)+sqlclient_unable_to_establish_sqlconnection :: ByteString+sqlclient_unable_to_establish_sqlconnection = "08001"++-- |@SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION@: 08004 (Error)+sqlserver_rejected_establishment_of_sqlconnection :: ByteString+sqlserver_rejected_establishment_of_sqlconnection = "08004"++-- |@TRANSACTION_RESOLUTION_UNKNOWN@: 08007 (Error)+transaction_resolution_unknown :: ByteString+transaction_resolution_unknown = "08007"++-- |@PROTOCOL_VIOLATION@: 08P01 (Error)+protocol_violation :: ByteString+protocol_violation = "08P01"++-- |@TRIGGERED_ACTION_EXCEPTION@: 09000 (Error)+triggered_action_exception :: ByteString+triggered_action_exception = "09000"++-- |@FEATURE_NOT_SUPPORTED@: 0A000 (Error)+feature_not_supported :: ByteString+feature_not_supported = "0A000"++-- |@INVALID_TRANSACTION_INITIATION@: 0B000 (Error)+invalid_transaction_initiation :: ByteString+invalid_transaction_initiation = "0B000"++-- |@LOCATOR_EXCEPTION@: 0F000 (Error)+locator_exception :: ByteString+locator_exception = "0F000"++-- |@L_E_INVALID_SPECIFICATION@: 0F001 (Error)+invalid_locator_specification :: ByteString+invalid_locator_specification = "0F001"++-- |@INVALID_GRANTOR@: 0L000 (Error)+invalid_grantor :: ByteString+invalid_grantor = "0L000"++-- |@INVALID_GRANT_OPERATION@: 0LP01 (Error)+invalid_grant_operation :: ByteString+invalid_grant_operation = "0LP01"++-- |@INVALID_ROLE_SPECIFICATION@: 0P000 (Error)+invalid_role_specification :: ByteString+invalid_role_specification = "0P000"++-- |@DIAGNOSTICS_EXCEPTION@: 0Z000 (Error)+diagnostics_exception :: ByteString+diagnostics_exception = "0Z000"++-- |@STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER@: 0Z002 (Error)+stacked_diagnostics_accessed_without_active_handler :: ByteString+stacked_diagnostics_accessed_without_active_handler = "0Z002"++-- |@CASE_NOT_FOUND@: 20000 (Error)+case_not_found :: ByteString+case_not_found = "20000"++-- |@CARDINALITY_VIOLATION@: 21000 (Error)+cardinality_violation :: ByteString+cardinality_violation = "21000"++-- |@DATA_EXCEPTION@: 22000 (Error)+data_exception :: ByteString+data_exception = "22000"++-- |@ARRAY_ELEMENT_ERROR@: 2202E (Error)+_ARRAY_ELEMENT_ERROR :: ByteString+_ARRAY_ELEMENT_ERROR = "2202E"++-- |@ARRAY_SUBSCRIPT_ERROR@: 2202E (Error)+array_subscript_error :: ByteString+array_subscript_error = "2202E"++-- |@CHARACTER_NOT_IN_REPERTOIRE@: 22021 (Error)+character_not_in_repertoire :: ByteString+character_not_in_repertoire = "22021"++-- |@DATETIME_FIELD_OVERFLOW@: 22008 (Error)+datetime_field_overflow :: ByteString+datetime_field_overflow = "22008"++-- |@DATETIME_VALUE_OUT_OF_RANGE@: 22008 (Error)+_DATETIME_VALUE_OUT_OF_RANGE :: ByteString+_DATETIME_VALUE_OUT_OF_RANGE = "22008"++-- |@DIVISION_BY_ZERO@: 22012 (Error)+division_by_zero :: ByteString+division_by_zero = "22012"++-- |@ERROR_IN_ASSIGNMENT@: 22005 (Error)+error_in_assignment :: ByteString+error_in_assignment = "22005"++-- |@ESCAPE_CHARACTER_CONFLICT@: 2200B (Error)+escape_character_conflict :: ByteString+escape_character_conflict = "2200B"++-- |@INDICATOR_OVERFLOW@: 22022 (Error)+indicator_overflow :: ByteString+indicator_overflow = "22022"++-- |@INTERVAL_FIELD_OVERFLOW@: 22015 (Error)+interval_field_overflow :: ByteString+interval_field_overflow = "22015"++-- |@INVALID_ARGUMENT_FOR_LOG@: 2201E (Error)+invalid_argument_for_logarithm :: ByteString+invalid_argument_for_logarithm = "2201E"++-- |@INVALID_ARGUMENT_FOR_NTILE@: 22014 (Error)+invalid_argument_for_ntile_function :: ByteString+invalid_argument_for_ntile_function = "22014"++-- |@INVALID_ARGUMENT_FOR_NTH_VALUE@: 22016 (Error)+invalid_argument_for_nth_value_function :: ByteString+invalid_argument_for_nth_value_function = "22016"++-- |@INVALID_ARGUMENT_FOR_POWER_FUNCTION@: 2201F (Error)+invalid_argument_for_power_function :: ByteString+invalid_argument_for_power_function = "2201F"++-- |@INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION@: 2201G (Error)+invalid_argument_for_width_bucket_function :: ByteString+invalid_argument_for_width_bucket_function = "2201G"++-- |@INVALID_CHARACTER_VALUE_FOR_CAST@: 22018 (Error)+invalid_character_value_for_cast :: ByteString+invalid_character_value_for_cast = "22018"++-- |@INVALID_DATETIME_FORMAT@: 22007 (Error)+invalid_datetime_format :: ByteString+invalid_datetime_format = "22007"++-- |@INVALID_ESCAPE_CHARACTER@: 22019 (Error)+invalid_escape_character :: ByteString+invalid_escape_character = "22019"++-- |@INVALID_ESCAPE_OCTET@: 2200D (Error)+invalid_escape_octet :: ByteString+invalid_escape_octet = "2200D"++-- |@INVALID_ESCAPE_SEQUENCE@: 22025 (Error)+invalid_escape_sequence :: ByteString+invalid_escape_sequence = "22025"++-- |@NONSTANDARD_USE_OF_ESCAPE_CHARACTER@: 22P06 (Error)+nonstandard_use_of_escape_character :: ByteString+nonstandard_use_of_escape_character = "22P06"++-- |@INVALID_INDICATOR_PARAMETER_VALUE@: 22010 (Error)+invalid_indicator_parameter_value :: ByteString+invalid_indicator_parameter_value = "22010"++-- |@INVALID_PARAMETER_VALUE@: 22023 (Error)+invalid_parameter_value :: ByteString+invalid_parameter_value = "22023"++-- |@INVALID_REGULAR_EXPRESSION@: 2201B (Error)+invalid_regular_expression :: ByteString+invalid_regular_expression = "2201B"++-- |@INVALID_ROW_COUNT_IN_LIMIT_CLAUSE@: 2201W (Error)+invalid_row_count_in_limit_clause :: ByteString+invalid_row_count_in_limit_clause = "2201W"++-- |@INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE@: 2201X (Error)+invalid_row_count_in_result_offset_clause :: ByteString+invalid_row_count_in_result_offset_clause = "2201X"++-- |@INVALID_TABLESAMPLE_ARGUMENT@: 2202H (Error)+invalid_tablesample_argument :: ByteString+invalid_tablesample_argument = "2202H"++-- |@INVALID_TABLESAMPLE_REPEAT@: 2202G (Error)+invalid_tablesample_repeat :: ByteString+invalid_tablesample_repeat = "2202G"++-- |@INVALID_TIME_ZONE_DISPLACEMENT_VALUE@: 22009 (Error)+invalid_time_zone_displacement_value :: ByteString+invalid_time_zone_displacement_value = "22009"++-- |@INVALID_USE_OF_ESCAPE_CHARACTER@: 2200C (Error)+invalid_use_of_escape_character :: ByteString+invalid_use_of_escape_character = "2200C"++-- |@MOST_SPECIFIC_TYPE_MISMATCH@: 2200G (Error)+most_specific_type_mismatch :: ByteString+most_specific_type_mismatch = "2200G"++-- |@NULL_VALUE_NOT_ALLOWED@: 22004 (Error)+null_value_not_allowed :: ByteString+null_value_not_allowed = "22004"++-- |@NULL_VALUE_NO_INDICATOR_PARAMETER@: 22002 (Error)+null_value_no_indicator_parameter :: ByteString+null_value_no_indicator_parameter = "22002"++-- |@NUMERIC_VALUE_OUT_OF_RANGE@: 22003 (Error)+numeric_value_out_of_range :: ByteString+numeric_value_out_of_range = "22003"++-- |@STRING_DATA_LENGTH_MISMATCH@: 22026 (Error)+string_data_length_mismatch :: ByteString+string_data_length_mismatch = "22026"++-- |@STRING_DATA_RIGHT_TRUNCATION@: 22001 (Error)+string_data_right_truncation :: ByteString+string_data_right_truncation = "22001"++-- |@SUBSTRING_ERROR@: 22011 (Error)+substring_error :: ByteString+substring_error = "22011"++-- |@TRIM_ERROR@: 22027 (Error)+trim_error :: ByteString+trim_error = "22027"++-- |@UNTERMINATED_C_STRING@: 22024 (Error)+unterminated_c_string :: ByteString+unterminated_c_string = "22024"++-- |@ZERO_LENGTH_CHARACTER_STRING@: 2200F (Error)+zero_length_character_string :: ByteString+zero_length_character_string = "2200F"++-- |@FLOATING_POINT_EXCEPTION@: 22P01 (Error)+floating_point_exception :: ByteString+floating_point_exception = "22P01"++-- |@INVALID_TEXT_REPRESENTATION@: 22P02 (Error)+invalid_text_representation :: ByteString+invalid_text_representation = "22P02"++-- |@INVALID_BINARY_REPRESENTATION@: 22P03 (Error)+invalid_binary_representation :: ByteString+invalid_binary_representation = "22P03"++-- |@BAD_COPY_FILE_FORMAT@: 22P04 (Error)+bad_copy_file_format :: ByteString+bad_copy_file_format = "22P04"++-- |@UNTRANSLATABLE_CHARACTER@: 22P05 (Error)+untranslatable_character :: ByteString+untranslatable_character = "22P05"++-- |@NOT_AN_XML_DOCUMENT@: 2200L (Error)+not_an_xml_document :: ByteString+not_an_xml_document = "2200L"++-- |@INVALID_XML_DOCUMENT@: 2200M (Error)+invalid_xml_document :: ByteString+invalid_xml_document = "2200M"++-- |@INVALID_XML_CONTENT@: 2200N (Error)+invalid_xml_content :: ByteString+invalid_xml_content = "2200N"++-- |@INVALID_XML_COMMENT@: 2200S (Error)+invalid_xml_comment :: ByteString+invalid_xml_comment = "2200S"++-- |@INVALID_XML_PROCESSING_INSTRUCTION@: 2200T (Error)+invalid_xml_processing_instruction :: ByteString+invalid_xml_processing_instruction = "2200T"++-- |@INTEGRITY_CONSTRAINT_VIOLATION@: 23000 (Error)+integrity_constraint_violation :: ByteString+integrity_constraint_violation = "23000"++-- |@RESTRICT_VIOLATION@: 23001 (Error)+restrict_violation :: ByteString+restrict_violation = "23001"++-- |@NOT_NULL_VIOLATION@: 23502 (Error)+not_null_violation :: ByteString+not_null_violation = "23502"++-- |@FOREIGN_KEY_VIOLATION@: 23503 (Error)+foreign_key_violation :: ByteString+foreign_key_violation = "23503"++-- |@UNIQUE_VIOLATION@: 23505 (Error)+unique_violation :: ByteString+unique_violation = "23505"++-- |@CHECK_VIOLATION@: 23514 (Error)+check_violation :: ByteString+check_violation = "23514"++-- |@EXCLUSION_VIOLATION@: 23P01 (Error)+exclusion_violation :: ByteString+exclusion_violation = "23P01"++-- |@INVALID_CURSOR_STATE@: 24000 (Error)+invalid_cursor_state :: ByteString+invalid_cursor_state = "24000"++-- |@INVALID_TRANSACTION_STATE@: 25000 (Error)+invalid_transaction_state :: ByteString+invalid_transaction_state = "25000"++-- |@ACTIVE_SQL_TRANSACTION@: 25001 (Error)+active_sql_transaction :: ByteString+active_sql_transaction = "25001"++-- |@BRANCH_TRANSACTION_ALREADY_ACTIVE@: 25002 (Error)+branch_transaction_already_active :: ByteString+branch_transaction_already_active = "25002"++-- |@HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL@: 25008 (Error)+held_cursor_requires_same_isolation_level :: ByteString+held_cursor_requires_same_isolation_level = "25008"++-- |@INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION@: 25003 (Error)+inappropriate_access_mode_for_branch_transaction :: ByteString+inappropriate_access_mode_for_branch_transaction = "25003"++-- |@INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION@: 25004 (Error)+inappropriate_isolation_level_for_branch_transaction :: ByteString+inappropriate_isolation_level_for_branch_transaction = "25004"++-- |@NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION@: 25005 (Error)+no_active_sql_transaction_for_branch_transaction :: ByteString+no_active_sql_transaction_for_branch_transaction = "25005"++-- |@READ_ONLY_SQL_TRANSACTION@: 25006 (Error)+read_only_sql_transaction :: ByteString+read_only_sql_transaction = "25006"++-- |@SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED@: 25007 (Error)+schema_and_data_statement_mixing_not_supported :: ByteString+schema_and_data_statement_mixing_not_supported = "25007"++-- |@NO_ACTIVE_SQL_TRANSACTION@: 25P01 (Error)+no_active_sql_transaction :: ByteString+no_active_sql_transaction = "25P01"++-- |@IN_FAILED_SQL_TRANSACTION@: 25P02 (Error)+in_failed_sql_transaction :: ByteString+in_failed_sql_transaction = "25P02"++-- |@INVALID_SQL_STATEMENT_NAME@: 26000 (Error)+invalid_sql_statement_name :: ByteString+invalid_sql_statement_name = "26000"++-- |@TRIGGERED_DATA_CHANGE_VIOLATION@: 27000 (Error)+triggered_data_change_violation :: ByteString+triggered_data_change_violation = "27000"++-- |@INVALID_AUTHORIZATION_SPECIFICATION@: 28000 (Error)+invalid_authorization_specification :: ByteString+invalid_authorization_specification = "28000"++-- |@INVALID_PASSWORD@: 28P01 (Error)+invalid_password :: ByteString+invalid_password = "28P01"++-- |@DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST@: 2B000 (Error)+dependent_privilege_descriptors_still_exist :: ByteString+dependent_privilege_descriptors_still_exist = "2B000"++-- |@DEPENDENT_OBJECTS_STILL_EXIST@: 2BP01 (Error)+dependent_objects_still_exist :: ByteString+dependent_objects_still_exist = "2BP01"++-- |@INVALID_TRANSACTION_TERMINATION@: 2D000 (Error)+invalid_transaction_termination :: ByteString+invalid_transaction_termination = "2D000"++-- |@SQL_ROUTINE_EXCEPTION@: 2F000 (Error)+sql_routine_exception :: ByteString+sql_routine_exception = "2F000"++-- |@S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT@: 2F005 (Error)+s_r_e_function_executed_no_return_statement :: ByteString+s_r_e_function_executed_no_return_statement = "2F005"++-- |@S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED@: 2F002 (Error)+s_r_e_modifying_sql_data_not_permitted :: ByteString+s_r_e_modifying_sql_data_not_permitted = "2F002"++-- |@S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED@: 2F003 (Error)+s_r_e_prohibited_sql_statement_attempted :: ByteString+s_r_e_prohibited_sql_statement_attempted = "2F003"++-- |@S_R_E_READING_SQL_DATA_NOT_PERMITTED@: 2F004 (Error)+s_r_e_reading_sql_data_not_permitted :: ByteString+s_r_e_reading_sql_data_not_permitted = "2F004"++-- |@INVALID_CURSOR_NAME@: 34000 (Error)+invalid_cursor_name :: ByteString+invalid_cursor_name = "34000"++-- |@EXTERNAL_ROUTINE_EXCEPTION@: 38000 (Error)+external_routine_exception :: ByteString+external_routine_exception = "38000"++-- |@E_R_E_CONTAINING_SQL_NOT_PERMITTED@: 38001 (Error)+e_r_e_containing_sql_not_permitted :: ByteString+e_r_e_containing_sql_not_permitted = "38001"++-- |@E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED@: 38002 (Error)+e_r_e_modifying_sql_data_not_permitted :: ByteString+e_r_e_modifying_sql_data_not_permitted = "38002"++-- |@E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED@: 38003 (Error)+e_r_e_prohibited_sql_statement_attempted :: ByteString+e_r_e_prohibited_sql_statement_attempted = "38003"++-- |@E_R_E_READING_SQL_DATA_NOT_PERMITTED@: 38004 (Error)+e_r_e_reading_sql_data_not_permitted :: ByteString+e_r_e_reading_sql_data_not_permitted = "38004"++-- |@EXTERNAL_ROUTINE_INVOCATION_EXCEPTION@: 39000 (Error)+external_routine_invocation_exception :: ByteString+external_routine_invocation_exception = "39000"++-- |@E_R_I_E_INVALID_SQLSTATE_RETURNED@: 39001 (Error)+e_r_i_e_invalid_sqlstate_returned :: ByteString+e_r_i_e_invalid_sqlstate_returned = "39001"++-- |@E_R_I_E_NULL_VALUE_NOT_ALLOWED@: 39004 (Error)+e_r_i_e_null_value_not_allowed :: ByteString+e_r_i_e_null_value_not_allowed = "39004"++-- |@E_R_I_E_TRIGGER_PROTOCOL_VIOLATED@: 39P01 (Error)+e_r_i_e_trigger_protocol_violated :: ByteString+e_r_i_e_trigger_protocol_violated = "39P01"++-- |@E_R_I_E_SRF_PROTOCOL_VIOLATED@: 39P02 (Error)+e_r_i_e_srf_protocol_violated :: ByteString+e_r_i_e_srf_protocol_violated = "39P02"++-- |@E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED@: 39P03 (Error)+e_r_i_e_event_trigger_protocol_violated :: ByteString+e_r_i_e_event_trigger_protocol_violated = "39P03"++-- |@SAVEPOINT_EXCEPTION@: 3B000 (Error)+savepoint_exception :: ByteString+savepoint_exception = "3B000"++-- |@S_E_INVALID_SPECIFICATION@: 3B001 (Error)+invalid_savepoint_specification :: ByteString+invalid_savepoint_specification = "3B001"++-- |@INVALID_CATALOG_NAME@: 3D000 (Error)+invalid_catalog_name :: ByteString+invalid_catalog_name = "3D000"++-- |@INVALID_SCHEMA_NAME@: 3F000 (Error)+invalid_schema_name :: ByteString+invalid_schema_name = "3F000"++-- |@TRANSACTION_ROLLBACK@: 40000 (Error)+transaction_rollback :: ByteString+transaction_rollback = "40000"++-- |@T_R_INTEGRITY_CONSTRAINT_VIOLATION@: 40002 (Error)+transaction_integrity_constraint_violation :: ByteString+transaction_integrity_constraint_violation = "40002"++-- |@T_R_SERIALIZATION_FAILURE@: 40001 (Error)+serialization_failure :: ByteString+serialization_failure = "40001"++-- |@T_R_STATEMENT_COMPLETION_UNKNOWN@: 40003 (Error)+statement_completion_unknown :: ByteString+statement_completion_unknown = "40003"++-- |@T_R_DEADLOCK_DETECTED@: 40P01 (Error)+deadlock_detected :: ByteString+deadlock_detected = "40P01"++-- |@SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION@: 42000 (Error)+syntax_error_or_access_rule_violation :: ByteString+syntax_error_or_access_rule_violation = "42000"++-- |@SYNTAX_ERROR@: 42601 (Error)+syntax_error :: ByteString+syntax_error = "42601"++-- |@INSUFFICIENT_PRIVILEGE@: 42501 (Error)+insufficient_privilege :: ByteString+insufficient_privilege = "42501"++-- |@CANNOT_COERCE@: 42846 (Error)+cannot_coerce :: ByteString+cannot_coerce = "42846"++-- |@GROUPING_ERROR@: 42803 (Error)+grouping_error :: ByteString+grouping_error = "42803"++-- |@WINDOWING_ERROR@: 42P20 (Error)+windowing_error :: ByteString+windowing_error = "42P20"++-- |@INVALID_RECURSION@: 42P19 (Error)+invalid_recursion :: ByteString+invalid_recursion = "42P19"++-- |@INVALID_FOREIGN_KEY@: 42830 (Error)+invalid_foreign_key :: ByteString+invalid_foreign_key = "42830"++-- |@INVALID_NAME@: 42602 (Error)+invalid_name :: ByteString+invalid_name = "42602"++-- |@NAME_TOO_LONG@: 42622 (Error)+name_too_long :: ByteString+name_too_long = "42622"++-- |@RESERVED_NAME@: 42939 (Error)+reserved_name :: ByteString+reserved_name = "42939"++-- |@DATATYPE_MISMATCH@: 42804 (Error)+datatype_mismatch :: ByteString+datatype_mismatch = "42804"++-- |@INDETERMINATE_DATATYPE@: 42P18 (Error)+indeterminate_datatype :: ByteString+indeterminate_datatype = "42P18"++-- |@COLLATION_MISMATCH@: 42P21 (Error)+collation_mismatch :: ByteString+collation_mismatch = "42P21"++-- |@INDETERMINATE_COLLATION@: 42P22 (Error)+indeterminate_collation :: ByteString+indeterminate_collation = "42P22"++-- |@WRONG_OBJECT_TYPE@: 42809 (Error)+wrong_object_type :: ByteString+wrong_object_type = "42809"++-- |@UNDEFINED_COLUMN@: 42703 (Error)+undefined_column :: ByteString+undefined_column = "42703"++-- |@UNDEFINED_CURSOR@: 34000 (Error)+_UNDEFINED_CURSOR :: ByteString+_UNDEFINED_CURSOR = "34000"++-- |@UNDEFINED_DATABASE@: 3D000 (Error)+_UNDEFINED_DATABASE :: ByteString+_UNDEFINED_DATABASE = "3D000"++-- |@UNDEFINED_FUNCTION@: 42883 (Error)+undefined_function :: ByteString+undefined_function = "42883"++-- |@UNDEFINED_PSTATEMENT@: 26000 (Error)+_UNDEFINED_PSTATEMENT :: ByteString+_UNDEFINED_PSTATEMENT = "26000"++-- |@UNDEFINED_SCHEMA@: 3F000 (Error)+_UNDEFINED_SCHEMA :: ByteString+_UNDEFINED_SCHEMA = "3F000"++-- |@UNDEFINED_TABLE@: 42P01 (Error)+undefined_table :: ByteString+undefined_table = "42P01"++-- |@UNDEFINED_PARAMETER@: 42P02 (Error)+undefined_parameter :: ByteString+undefined_parameter = "42P02"++-- |@UNDEFINED_OBJECT@: 42704 (Error)+undefined_object :: ByteString+undefined_object = "42704"++-- |@DUPLICATE_COLUMN@: 42701 (Error)+duplicate_column :: ByteString+duplicate_column = "42701"++-- |@DUPLICATE_CURSOR@: 42P03 (Error)+duplicate_cursor :: ByteString+duplicate_cursor = "42P03"++-- |@DUPLICATE_DATABASE@: 42P04 (Error)+duplicate_database :: ByteString+duplicate_database = "42P04"++-- |@DUPLICATE_FUNCTION@: 42723 (Error)+duplicate_function :: ByteString+duplicate_function = "42723"++-- |@DUPLICATE_PSTATEMENT@: 42P05 (Error)+duplicate_prepared_statement :: ByteString+duplicate_prepared_statement = "42P05"++-- |@DUPLICATE_SCHEMA@: 42P06 (Error)+duplicate_schema :: ByteString+duplicate_schema = "42P06"++-- |@DUPLICATE_TABLE@: 42P07 (Error)+duplicate_table :: ByteString+duplicate_table = "42P07"++-- |@DUPLICATE_ALIAS@: 42712 (Error)+duplicate_alias :: ByteString+duplicate_alias = "42712"++-- |@DUPLICATE_OBJECT@: 42710 (Error)+duplicate_object :: ByteString+duplicate_object = "42710"++-- |@AMBIGUOUS_COLUMN@: 42702 (Error)+ambiguous_column :: ByteString+ambiguous_column = "42702"++-- |@AMBIGUOUS_FUNCTION@: 42725 (Error)+ambiguous_function :: ByteString+ambiguous_function = "42725"++-- |@AMBIGUOUS_PARAMETER@: 42P08 (Error)+ambiguous_parameter :: ByteString+ambiguous_parameter = "42P08"++-- |@AMBIGUOUS_ALIAS@: 42P09 (Error)+ambiguous_alias :: ByteString+ambiguous_alias = "42P09"++-- |@INVALID_COLUMN_REFERENCE@: 42P10 (Error)+invalid_column_reference :: ByteString+invalid_column_reference = "42P10"++-- |@INVALID_COLUMN_DEFINITION@: 42611 (Error)+invalid_column_definition :: ByteString+invalid_column_definition = "42611"++-- |@INVALID_CURSOR_DEFINITION@: 42P11 (Error)+invalid_cursor_definition :: ByteString+invalid_cursor_definition = "42P11"++-- |@INVALID_DATABASE_DEFINITION@: 42P12 (Error)+invalid_database_definition :: ByteString+invalid_database_definition = "42P12"++-- |@INVALID_FUNCTION_DEFINITION@: 42P13 (Error)+invalid_function_definition :: ByteString+invalid_function_definition = "42P13"++-- |@INVALID_PSTATEMENT_DEFINITION@: 42P14 (Error)+invalid_prepared_statement_definition :: ByteString+invalid_prepared_statement_definition = "42P14"++-- |@INVALID_SCHEMA_DEFINITION@: 42P15 (Error)+invalid_schema_definition :: ByteString+invalid_schema_definition = "42P15"++-- |@INVALID_TABLE_DEFINITION@: 42P16 (Error)+invalid_table_definition :: ByteString+invalid_table_definition = "42P16"++-- |@INVALID_OBJECT_DEFINITION@: 42P17 (Error)+invalid_object_definition :: ByteString+invalid_object_definition = "42P17"++-- |@WITH_CHECK_OPTION_VIOLATION@: 44000 (Error)+with_check_option_violation :: ByteString+with_check_option_violation = "44000"++-- |@INSUFFICIENT_RESOURCES@: 53000 (Error)+insufficient_resources :: ByteString+insufficient_resources = "53000"++-- |@DISK_FULL@: 53100 (Error)+disk_full :: ByteString+disk_full = "53100"++-- |@OUT_OF_MEMORY@: 53200 (Error)+out_of_memory :: ByteString+out_of_memory = "53200"++-- |@TOO_MANY_CONNECTIONS@: 53300 (Error)+too_many_connections :: ByteString+too_many_connections = "53300"++-- |@CONFIGURATION_LIMIT_EXCEEDED@: 53400 (Error)+configuration_limit_exceeded :: ByteString+configuration_limit_exceeded = "53400"++-- |@PROGRAM_LIMIT_EXCEEDED@: 54000 (Error)+program_limit_exceeded :: ByteString+program_limit_exceeded = "54000"++-- |@STATEMENT_TOO_COMPLEX@: 54001 (Error)+statement_too_complex :: ByteString+statement_too_complex = "54001"++-- |@TOO_MANY_COLUMNS@: 54011 (Error)+too_many_columns :: ByteString+too_many_columns = "54011"++-- |@TOO_MANY_ARGUMENTS@: 54023 (Error)+too_many_arguments :: ByteString+too_many_arguments = "54023"++-- |@OBJECT_NOT_IN_PREREQUISITE_STATE@: 55000 (Error)+object_not_in_prerequisite_state :: ByteString+object_not_in_prerequisite_state = "55000"++-- |@OBJECT_IN_USE@: 55006 (Error)+object_in_use :: ByteString+object_in_use = "55006"++-- |@CANT_CHANGE_RUNTIME_PARAM@: 55P02 (Error)+cant_change_runtime_param :: ByteString+cant_change_runtime_param = "55P02"++-- |@LOCK_NOT_AVAILABLE@: 55P03 (Error)+lock_not_available :: ByteString+lock_not_available = "55P03"++-- |@OPERATOR_INTERVENTION@: 57000 (Error)+operator_intervention :: ByteString+operator_intervention = "57000"++-- |@QUERY_CANCELED@: 57014 (Error)+query_canceled :: ByteString+query_canceled = "57014"++-- |@ADMIN_SHUTDOWN@: 57P01 (Error)+admin_shutdown :: ByteString+admin_shutdown = "57P01"++-- |@CRASH_SHUTDOWN@: 57P02 (Error)+crash_shutdown :: ByteString+crash_shutdown = "57P02"++-- |@CANNOT_CONNECT_NOW@: 57P03 (Error)+cannot_connect_now :: ByteString+cannot_connect_now = "57P03"++-- |@DATABASE_DROPPED@: 57P04 (Error)+database_dropped :: ByteString+database_dropped = "57P04"++-- |@SYSTEM_ERROR@: 58000 (Error)+system_error :: ByteString+system_error = "58000"++-- |@IO_ERROR@: 58030 (Error)+io_error :: ByteString+io_error = "58030"++-- |@UNDEFINED_FILE@: 58P01 (Error)+undefined_file :: ByteString+undefined_file = "58P01"++-- |@DUPLICATE_FILE@: 58P02 (Error)+duplicate_file :: ByteString+duplicate_file = "58P02"++-- |@CONFIG_FILE_ERROR@: F0000 (Error)+config_file_error :: ByteString+config_file_error = "F0000"++-- |@LOCK_FILE_EXISTS@: F0001 (Error)+lock_file_exists :: ByteString+lock_file_exists = "F0001"++-- |@FDW_ERROR@: HV000 (Error)+fdw_error :: ByteString+fdw_error = "HV000"++-- |@FDW_COLUMN_NAME_NOT_FOUND@: HV005 (Error)+fdw_column_name_not_found :: ByteString+fdw_column_name_not_found = "HV005"++-- |@FDW_DYNAMIC_PARAMETER_VALUE_NEEDED@: HV002 (Error)+fdw_dynamic_parameter_value_needed :: ByteString+fdw_dynamic_parameter_value_needed = "HV002"++-- |@FDW_FUNCTION_SEQUENCE_ERROR@: HV010 (Error)+fdw_function_sequence_error :: ByteString+fdw_function_sequence_error = "HV010"++-- |@FDW_INCONSISTENT_DESCRIPTOR_INFORMATION@: HV021 (Error)+fdw_inconsistent_descriptor_information :: ByteString+fdw_inconsistent_descriptor_information = "HV021"++-- |@FDW_INVALID_ATTRIBUTE_VALUE@: HV024 (Error)+fdw_invalid_attribute_value :: ByteString+fdw_invalid_attribute_value = "HV024"++-- |@FDW_INVALID_COLUMN_NAME@: HV007 (Error)+fdw_invalid_column_name :: ByteString+fdw_invalid_column_name = "HV007"++-- |@FDW_INVALID_COLUMN_NUMBER@: HV008 (Error)+fdw_invalid_column_number :: ByteString+fdw_invalid_column_number = "HV008"++-- |@FDW_INVALID_DATA_TYPE@: HV004 (Error)+fdw_invalid_data_type :: ByteString+fdw_invalid_data_type = "HV004"++-- |@FDW_INVALID_DATA_TYPE_DESCRIPTORS@: HV006 (Error)+fdw_invalid_data_type_descriptors :: ByteString+fdw_invalid_data_type_descriptors = "HV006"++-- |@FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER@: HV091 (Error)+fdw_invalid_descriptor_field_identifier :: ByteString+fdw_invalid_descriptor_field_identifier = "HV091"++-- |@FDW_INVALID_HANDLE@: HV00B (Error)+fdw_invalid_handle :: ByteString+fdw_invalid_handle = "HV00B"++-- |@FDW_INVALID_OPTION_INDEX@: HV00C (Error)+fdw_invalid_option_index :: ByteString+fdw_invalid_option_index = "HV00C"++-- |@FDW_INVALID_OPTION_NAME@: HV00D (Error)+fdw_invalid_option_name :: ByteString+fdw_invalid_option_name = "HV00D"++-- |@FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH@: HV090 (Error)+fdw_invalid_string_length_or_buffer_length :: ByteString+fdw_invalid_string_length_or_buffer_length = "HV090"++-- |@FDW_INVALID_STRING_FORMAT@: HV00A (Error)+fdw_invalid_string_format :: ByteString+fdw_invalid_string_format = "HV00A"++-- |@FDW_INVALID_USE_OF_NULL_POINTER@: HV009 (Error)+fdw_invalid_use_of_null_pointer :: ByteString+fdw_invalid_use_of_null_pointer = "HV009"++-- |@FDW_TOO_MANY_HANDLES@: HV014 (Error)+fdw_too_many_handles :: ByteString+fdw_too_many_handles = "HV014"++-- |@FDW_OUT_OF_MEMORY@: HV001 (Error)+fdw_out_of_memory :: ByteString+fdw_out_of_memory = "HV001"++-- |@FDW_NO_SCHEMAS@: HV00P (Error)+fdw_no_schemas :: ByteString+fdw_no_schemas = "HV00P"++-- |@FDW_OPTION_NAME_NOT_FOUND@: HV00J (Error)+fdw_option_name_not_found :: ByteString+fdw_option_name_not_found = "HV00J"++-- |@FDW_REPLY_HANDLE@: HV00K (Error)+fdw_reply_handle :: ByteString+fdw_reply_handle = "HV00K"++-- |@FDW_SCHEMA_NOT_FOUND@: HV00Q (Error)+fdw_schema_not_found :: ByteString+fdw_schema_not_found = "HV00Q"++-- |@FDW_TABLE_NOT_FOUND@: HV00R (Error)+fdw_table_not_found :: ByteString+fdw_table_not_found = "HV00R"++-- |@FDW_UNABLE_TO_CREATE_EXECUTION@: HV00L (Error)+fdw_unable_to_create_execution :: ByteString+fdw_unable_to_create_execution = "HV00L"++-- |@FDW_UNABLE_TO_CREATE_REPLY@: HV00M (Error)+fdw_unable_to_create_reply :: ByteString+fdw_unable_to_create_reply = "HV00M"++-- |@FDW_UNABLE_TO_ESTABLISH_CONNECTION@: HV00N (Error)+fdw_unable_to_establish_connection :: ByteString+fdw_unable_to_establish_connection = "HV00N"++-- |@PLPGSQL_ERROR@: P0000 (Error)+plpgsql_error :: ByteString+plpgsql_error = "P0000"++-- |@RAISE_EXCEPTION@: P0001 (Error)+raise_exception :: ByteString+raise_exception = "P0001"++-- |@NO_DATA_FOUND@: P0002 (Error)+no_data_found :: ByteString+no_data_found = "P0002"++-- |@TOO_MANY_ROWS@: P0003 (Error)+too_many_rows :: ByteString+too_many_rows = "P0003"++-- |@ASSERT_FAILURE@: P0004 (Error)+assert_failure :: ByteString+assert_failure = "P0004"++-- |@INTERNAL_ERROR@: XX000 (Error)+internal_error :: ByteString+internal_error = "XX000"++-- |@DATA_CORRUPTED@: XX001 (Error)+data_corrupted :: ByteString+data_corrupted = "XX001"++-- |@INDEX_CORRUPTED@: XX002 (Error)+index_corrupted :: ByteString+index_corrupted = "XX002"++-- |All known error code names by code.+names :: Map ByteString String+names = fromDistinctAscList+ [(successful_completion,"successful_completion")+ ,(warning,"warning")+ ,(warning_null_value_eliminated_in_set_function,"null_value_eliminated_in_set_function")+ ,(warning_string_data_right_truncation,"string_data_right_truncation")+ ,(warning_privilege_not_revoked,"privilege_not_revoked")+ ,(warning_privilege_not_granted,"privilege_not_granted")+ ,(warning_implicit_zero_bit_padding,"implicit_zero_bit_padding")+ ,(warning_dynamic_result_sets_returned,"dynamic_result_sets_returned")+ ,(warning_deprecated_feature,"deprecated_feature")+ ,(no_data,"no_data")+ ,(no_additional_dynamic_result_sets_returned,"no_additional_dynamic_result_sets_returned")+ ,(sql_statement_not_yet_complete,"sql_statement_not_yet_complete")+ ,(connection_exception,"connection_exception")+ ,(sqlclient_unable_to_establish_sqlconnection,"sqlclient_unable_to_establish_sqlconnection")+ ,(connection_does_not_exist,"connection_does_not_exist")+ ,(sqlserver_rejected_establishment_of_sqlconnection,"sqlserver_rejected_establishment_of_sqlconnection")+ ,(connection_failure,"connection_failure")+ ,(transaction_resolution_unknown,"transaction_resolution_unknown")+ ,(protocol_violation,"protocol_violation")+ ,(triggered_action_exception,"triggered_action_exception")+ ,(feature_not_supported,"feature_not_supported")+ ,(invalid_transaction_initiation,"invalid_transaction_initiation")+ ,(locator_exception,"locator_exception")+ ,(invalid_locator_specification,"invalid_locator_specification")+ ,(invalid_grantor,"invalid_grantor")+ ,(invalid_grant_operation,"invalid_grant_operation")+ ,(invalid_role_specification,"invalid_role_specification")+ ,(diagnostics_exception,"diagnostics_exception")+ ,(stacked_diagnostics_accessed_without_active_handler,"stacked_diagnostics_accessed_without_active_handler")+ ,(case_not_found,"case_not_found")+ ,(cardinality_violation,"cardinality_violation")+ ,(data_exception,"data_exception")+ ,(string_data_right_truncation,"string_data_right_truncation")+ ,(null_value_no_indicator_parameter,"null_value_no_indicator_parameter")+ ,(numeric_value_out_of_range,"numeric_value_out_of_range")+ ,(null_value_not_allowed,"null_value_not_allowed")+ ,(error_in_assignment,"error_in_assignment")+ ,(invalid_datetime_format,"invalid_datetime_format")+ ,(datetime_field_overflow,"datetime_field_overflow")+ ,(_DATETIME_VALUE_OUT_OF_RANGE,"DATETIME_VALUE_OUT_OF_RANGE")+ ,(invalid_time_zone_displacement_value,"invalid_time_zone_displacement_value")+ ,(escape_character_conflict,"escape_character_conflict")+ ,(invalid_use_of_escape_character,"invalid_use_of_escape_character")+ ,(invalid_escape_octet,"invalid_escape_octet")+ ,(zero_length_character_string,"zero_length_character_string")+ ,(most_specific_type_mismatch,"most_specific_type_mismatch")+ ,(not_an_xml_document,"not_an_xml_document")+ ,(invalid_xml_document,"invalid_xml_document")+ ,(invalid_xml_content,"invalid_xml_content")+ ,(invalid_xml_comment,"invalid_xml_comment")+ ,(invalid_xml_processing_instruction,"invalid_xml_processing_instruction")+ ,(invalid_indicator_parameter_value,"invalid_indicator_parameter_value")+ ,(substring_error,"substring_error")+ ,(division_by_zero,"division_by_zero")+ ,(invalid_argument_for_ntile_function,"invalid_argument_for_ntile_function")+ ,(interval_field_overflow,"interval_field_overflow")+ ,(invalid_argument_for_nth_value_function,"invalid_argument_for_nth_value_function")+ ,(invalid_character_value_for_cast,"invalid_character_value_for_cast")+ ,(invalid_escape_character,"invalid_escape_character")+ ,(invalid_regular_expression,"invalid_regular_expression")+ ,(invalid_argument_for_logarithm,"invalid_argument_for_logarithm")+ ,(invalid_argument_for_power_function,"invalid_argument_for_power_function")+ ,(invalid_argument_for_width_bucket_function,"invalid_argument_for_width_bucket_function")+ ,(invalid_row_count_in_limit_clause,"invalid_row_count_in_limit_clause")+ ,(invalid_row_count_in_result_offset_clause,"invalid_row_count_in_result_offset_clause")+ ,(character_not_in_repertoire,"character_not_in_repertoire")+ ,(indicator_overflow,"indicator_overflow")+ ,(invalid_parameter_value,"invalid_parameter_value")+ ,(unterminated_c_string,"unterminated_c_string")+ ,(invalid_escape_sequence,"invalid_escape_sequence")+ ,(string_data_length_mismatch,"string_data_length_mismatch")+ ,(trim_error,"trim_error")+ ,(_ARRAY_ELEMENT_ERROR,"ARRAY_ELEMENT_ERROR")+ ,(array_subscript_error,"array_subscript_error")+ ,(invalid_tablesample_repeat,"invalid_tablesample_repeat")+ ,(invalid_tablesample_argument,"invalid_tablesample_argument")+ ,(floating_point_exception,"floating_point_exception")+ ,(invalid_text_representation,"invalid_text_representation")+ ,(invalid_binary_representation,"invalid_binary_representation")+ ,(bad_copy_file_format,"bad_copy_file_format")+ ,(untranslatable_character,"untranslatable_character")+ ,(nonstandard_use_of_escape_character,"nonstandard_use_of_escape_character")+ ,(integrity_constraint_violation,"integrity_constraint_violation")+ ,(restrict_violation,"restrict_violation")+ ,(not_null_violation,"not_null_violation")+ ,(foreign_key_violation,"foreign_key_violation")+ ,(unique_violation,"unique_violation")+ ,(check_violation,"check_violation")+ ,(exclusion_violation,"exclusion_violation")+ ,(invalid_cursor_state,"invalid_cursor_state")+ ,(invalid_transaction_state,"invalid_transaction_state")+ ,(active_sql_transaction,"active_sql_transaction")+ ,(branch_transaction_already_active,"branch_transaction_already_active")+ ,(inappropriate_access_mode_for_branch_transaction,"inappropriate_access_mode_for_branch_transaction")+ ,(inappropriate_isolation_level_for_branch_transaction,"inappropriate_isolation_level_for_branch_transaction")+ ,(no_active_sql_transaction_for_branch_transaction,"no_active_sql_transaction_for_branch_transaction")+ ,(read_only_sql_transaction,"read_only_sql_transaction")+ ,(schema_and_data_statement_mixing_not_supported,"schema_and_data_statement_mixing_not_supported")+ ,(held_cursor_requires_same_isolation_level,"held_cursor_requires_same_isolation_level")+ ,(no_active_sql_transaction,"no_active_sql_transaction")+ ,(in_failed_sql_transaction,"in_failed_sql_transaction")+ ,(invalid_sql_statement_name,"invalid_sql_statement_name")+ ,(_UNDEFINED_PSTATEMENT,"UNDEFINED_PSTATEMENT")+ ,(triggered_data_change_violation,"triggered_data_change_violation")+ ,(invalid_authorization_specification,"invalid_authorization_specification")+ ,(invalid_password,"invalid_password")+ ,(dependent_privilege_descriptors_still_exist,"dependent_privilege_descriptors_still_exist")+ ,(dependent_objects_still_exist,"dependent_objects_still_exist")+ ,(invalid_transaction_termination,"invalid_transaction_termination")+ ,(sql_routine_exception,"sql_routine_exception")+ ,(s_r_e_modifying_sql_data_not_permitted,"modifying_sql_data_not_permitted")+ ,(s_r_e_prohibited_sql_statement_attempted,"prohibited_sql_statement_attempted")+ ,(s_r_e_reading_sql_data_not_permitted,"reading_sql_data_not_permitted")+ ,(s_r_e_function_executed_no_return_statement,"function_executed_no_return_statement")+ ,(invalid_cursor_name,"invalid_cursor_name")+ ,(_UNDEFINED_CURSOR,"UNDEFINED_CURSOR")+ ,(external_routine_exception,"external_routine_exception")+ ,(e_r_e_containing_sql_not_permitted,"containing_sql_not_permitted")+ ,(e_r_e_modifying_sql_data_not_permitted,"modifying_sql_data_not_permitted")+ ,(e_r_e_prohibited_sql_statement_attempted,"prohibited_sql_statement_attempted")+ ,(e_r_e_reading_sql_data_not_permitted,"reading_sql_data_not_permitted")+ ,(external_routine_invocation_exception,"external_routine_invocation_exception")+ ,(e_r_i_e_invalid_sqlstate_returned,"invalid_sqlstate_returned")+ ,(e_r_i_e_null_value_not_allowed,"null_value_not_allowed")+ ,(e_r_i_e_trigger_protocol_violated,"trigger_protocol_violated")+ ,(e_r_i_e_srf_protocol_violated,"srf_protocol_violated")+ ,(e_r_i_e_event_trigger_protocol_violated,"event_trigger_protocol_violated")+ ,(savepoint_exception,"savepoint_exception")+ ,(invalid_savepoint_specification,"invalid_savepoint_specification")+ ,(invalid_catalog_name,"invalid_catalog_name")+ ,(_UNDEFINED_DATABASE,"UNDEFINED_DATABASE")+ ,(invalid_schema_name,"invalid_schema_name")+ ,(_UNDEFINED_SCHEMA,"UNDEFINED_SCHEMA")+ ,(transaction_rollback,"transaction_rollback")+ ,(serialization_failure,"serialization_failure")+ ,(transaction_integrity_constraint_violation,"transaction_integrity_constraint_violation")+ ,(statement_completion_unknown,"statement_completion_unknown")+ ,(deadlock_detected,"deadlock_detected")+ ,(syntax_error_or_access_rule_violation,"syntax_error_or_access_rule_violation")+ ,(insufficient_privilege,"insufficient_privilege")+ ,(syntax_error,"syntax_error")+ ,(invalid_name,"invalid_name")+ ,(invalid_column_definition,"invalid_column_definition")+ ,(name_too_long,"name_too_long")+ ,(duplicate_column,"duplicate_column")+ ,(ambiguous_column,"ambiguous_column")+ ,(undefined_column,"undefined_column")+ ,(undefined_object,"undefined_object")+ ,(duplicate_object,"duplicate_object")+ ,(duplicate_alias,"duplicate_alias")+ ,(duplicate_function,"duplicate_function")+ ,(ambiguous_function,"ambiguous_function")+ ,(grouping_error,"grouping_error")+ ,(datatype_mismatch,"datatype_mismatch")+ ,(wrong_object_type,"wrong_object_type")+ ,(invalid_foreign_key,"invalid_foreign_key")+ ,(cannot_coerce,"cannot_coerce")+ ,(undefined_function,"undefined_function")+ ,(reserved_name,"reserved_name")+ ,(undefined_table,"undefined_table")+ ,(undefined_parameter,"undefined_parameter")+ ,(duplicate_cursor,"duplicate_cursor")+ ,(duplicate_database,"duplicate_database")+ ,(duplicate_prepared_statement,"duplicate_prepared_statement")+ ,(duplicate_schema,"duplicate_schema")+ ,(duplicate_table,"duplicate_table")+ ,(ambiguous_parameter,"ambiguous_parameter")+ ,(ambiguous_alias,"ambiguous_alias")+ ,(invalid_column_reference,"invalid_column_reference")+ ,(invalid_cursor_definition,"invalid_cursor_definition")+ ,(invalid_database_definition,"invalid_database_definition")+ ,(invalid_function_definition,"invalid_function_definition")+ ,(invalid_prepared_statement_definition,"invalid_prepared_statement_definition")+ ,(invalid_schema_definition,"invalid_schema_definition")+ ,(invalid_table_definition,"invalid_table_definition")+ ,(invalid_object_definition,"invalid_object_definition")+ ,(indeterminate_datatype,"indeterminate_datatype")+ ,(invalid_recursion,"invalid_recursion")+ ,(windowing_error,"windowing_error")+ ,(collation_mismatch,"collation_mismatch")+ ,(indeterminate_collation,"indeterminate_collation")+ ,(with_check_option_violation,"with_check_option_violation")+ ,(insufficient_resources,"insufficient_resources")+ ,(disk_full,"disk_full")+ ,(out_of_memory,"out_of_memory")+ ,(too_many_connections,"too_many_connections")+ ,(configuration_limit_exceeded,"configuration_limit_exceeded")+ ,(program_limit_exceeded,"program_limit_exceeded")+ ,(statement_too_complex,"statement_too_complex")+ ,(too_many_columns,"too_many_columns")+ ,(too_many_arguments,"too_many_arguments")+ ,(object_not_in_prerequisite_state,"object_not_in_prerequisite_state")+ ,(object_in_use,"object_in_use")+ ,(cant_change_runtime_param,"cant_change_runtime_param")+ ,(lock_not_available,"lock_not_available")+ ,(operator_intervention,"operator_intervention")+ ,(query_canceled,"query_canceled")+ ,(admin_shutdown,"admin_shutdown")+ ,(crash_shutdown,"crash_shutdown")+ ,(cannot_connect_now,"cannot_connect_now")+ ,(database_dropped,"database_dropped")+ ,(system_error,"system_error")+ ,(io_error,"io_error")+ ,(undefined_file,"undefined_file")+ ,(duplicate_file,"duplicate_file")+ ,(config_file_error,"config_file_error")+ ,(lock_file_exists,"lock_file_exists")+ ,(fdw_error,"fdw_error")+ ,(fdw_out_of_memory,"fdw_out_of_memory")+ ,(fdw_dynamic_parameter_value_needed,"fdw_dynamic_parameter_value_needed")+ ,(fdw_invalid_data_type,"fdw_invalid_data_type")+ ,(fdw_column_name_not_found,"fdw_column_name_not_found")+ ,(fdw_invalid_data_type_descriptors,"fdw_invalid_data_type_descriptors")+ ,(fdw_invalid_column_name,"fdw_invalid_column_name")+ ,(fdw_invalid_column_number,"fdw_invalid_column_number")+ ,(fdw_invalid_use_of_null_pointer,"fdw_invalid_use_of_null_pointer")+ ,(fdw_invalid_string_format,"fdw_invalid_string_format")+ ,(fdw_invalid_handle,"fdw_invalid_handle")+ ,(fdw_invalid_option_index,"fdw_invalid_option_index")+ ,(fdw_invalid_option_name,"fdw_invalid_option_name")+ ,(fdw_option_name_not_found,"fdw_option_name_not_found")+ ,(fdw_reply_handle,"fdw_reply_handle")+ ,(fdw_unable_to_create_execution,"fdw_unable_to_create_execution")+ ,(fdw_unable_to_create_reply,"fdw_unable_to_create_reply")+ ,(fdw_unable_to_establish_connection,"fdw_unable_to_establish_connection")+ ,(fdw_no_schemas,"fdw_no_schemas")+ ,(fdw_schema_not_found,"fdw_schema_not_found")+ ,(fdw_table_not_found,"fdw_table_not_found")+ ,(fdw_function_sequence_error,"fdw_function_sequence_error")+ ,(fdw_too_many_handles,"fdw_too_many_handles")+ ,(fdw_inconsistent_descriptor_information,"fdw_inconsistent_descriptor_information")+ ,(fdw_invalid_attribute_value,"fdw_invalid_attribute_value")+ ,(fdw_invalid_string_length_or_buffer_length,"fdw_invalid_string_length_or_buffer_length")+ ,(fdw_invalid_descriptor_field_identifier,"fdw_invalid_descriptor_field_identifier")+ ,(plpgsql_error,"plpgsql_error")+ ,(raise_exception,"raise_exception")+ ,(no_data_found,"no_data_found")+ ,(too_many_rows,"too_many_rows")+ ,(assert_failure,"assert_failure")+ ,(internal_error,"internal_error")+ ,(data_corrupted,"data_corrupted")+ ,(index_corrupted,"index_corrupted")]
+ Database/PostgreSQL/Typed/HDBC.hs view
@@ -0,0 +1,352 @@+-- |+-- Module: Database.PostgreSQL.Typed.HDBC+-- Copyright: 2016 Dylan Simon+-- +-- Use postgresql-typed as a backend for HDBC.+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+module Database.PostgreSQL.Typed.HDBC+ ( Connection, connectionPG+ , connect+ , fromPGConnection+ , reloadTypes+ , connectionFetchSize+ , setFetchSize+ ) where++import Control.Arrow ((&&&))+import Control.Concurrent.MVar (MVar, newMVar, withMVar)+import Control.Exception (handle, throwIO)+import Control.Monad (void, guard)+import qualified Data.ByteString.Char8 as BSC+import qualified Data.ByteString.Lazy.Char8 as BSLC+import Data.IORef (newIORef, readIORef, writeIORef, modifyIORef')+import Data.Int (Int16)+import qualified Data.IntMap.Lazy as IntMap+import Data.List (uncons)+import qualified Data.Map.Lazy as Map+import Data.Maybe (fromMaybe, isNothing)+import Data.Time.Clock (DiffTime)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import Data.Time.LocalTime (zonedTimeToUTC)+import Data.Word (Word32)+import qualified Database.HDBC.Types as HDBC+import qualified Database.HDBC.ColTypes as HDBC+import System.Mem.Weak (addFinalizer)+import Text.Read (readMaybe)++import Database.PostgreSQL.Typed.Protocol+import Database.PostgreSQL.Typed.Types+import Database.PostgreSQL.Typed.Dynamic+import Database.PostgreSQL.Typed.TH+import Database.PostgreSQL.Typed.SQLToken+import Paths_postgresql_typed (version)++-- |A wrapped 'PGConnection'.+-- This differs from a bare 'PGConnection' in a few ways:+--+-- 1. It always has exactly one active transaction (with 'pgBegin')+-- 2. It automatically disconnects on GC+-- 3. It provides a mutex around the underlying 'PGConnection' for thread-safety+--+data Connection = Connection+ { connectionPG :: MVar PGConnection -- ^Access the underlying 'PGConnection' directly. You must be careful to ensure that the first invariant is preserved: you should not call 'pgBegin', 'pgCommit', or 'pgRollback' on it. All other operations should be safe.+ , connectionServerVer :: String+ , connectionTypes :: IntMap.IntMap SqlType+ , connectionFetchSize :: Word32 -- ^Number of rows to fetch (and cache) with 'HDBC.execute' and each time 'HDBC.fetchRow' requires more rows. A higher value will result in fewer round-trips to the database but potentially more wasted data. Defaults to 1. 0 means fetch all rows.+ }++sqlError :: IO a -> IO a+sqlError = handle $ \(PGError m) -> + let f c = BSC.unpack $ Map.findWithDefault BSC.empty c m+ fC = f 'C'+ fD = f 'D' in+ throwIO HDBC.SqlError + { HDBC.seState = fC+ , HDBC.seNativeError = if null fC then -1 else fromMaybe 0 $ readMaybe (f 'P')+ , HDBC.seErrorMsg = f 'S' ++ ": " ++ f 'M' ++ if null fD then fD else '\n':fD+ }++withPG :: Connection -> (PGConnection -> IO a) -> IO a+withPG c = sqlError . withMVar (connectionPG c)++takePGConnection :: PGConnection -> IO (MVar PGConnection)+takePGConnection pg = do+ addFinalizer pg (pgDisconnectOnce pg)+ pgBegin pg+ newMVar pg++-- |Convert an existing 'PGConnection' to an HDBC-compatible 'Connection'.+-- The caveats under 'connectionPG' apply if you plan to continue using the original 'PGConnection'.+fromPGConnection :: PGConnection -> IO Connection+fromPGConnection pg = do+ pgv <- takePGConnection pg+ reloadTypes Connection+ { connectionPG = pgv+ , connectionServerVer = maybe "" BSC.unpack $ pgServerVersion pg+ , connectionTypes = mempty+ , connectionFetchSize = 1+ }++-- |Connect to a database for HDBC use (equivalent to 'pgConnect' and 'pgBegin').+connect :: PGDatabase -> IO Connection+connect d = sqlError $ do+ pg <- pgConnect d+ fromPGConnection pg++-- |Reload the table of all types from the database.+-- This may be needed if you make structural changes to the database.+reloadTypes :: Connection -> IO Connection+reloadTypes c = withPG c $ \pg -> do+ t <- pgLoadTypes pg+ return c{ connectionTypes = IntMap.map (sqlType $ pgTypeEnv pg) t }++-- |Change the 'connectionFetchSize' for new 'HDBC.Statement's created with 'HDBC.prepare'.+-- Ideally this could be set with each call to 'HDBC.execute' and 'HDBC.fetchRow', but the HDBC interface provides no way to do this.+setFetchSize :: Word32 -> Connection -> Connection+setFetchSize i c = c{ connectionFetchSize = i }++sqls :: String -> BSLC.ByteString+sqls = BSLC.pack++placeholders :: Int -> [SQLToken] -> [SQLToken]+placeholders n (SQLQMark False : l) = SQLParam n : placeholders (succ n) l+placeholders n (SQLQMark True : l) = SQLQMark False : placeholders n l+placeholders n (t : l) = t : placeholders n l+placeholders _ [] = []++data ColDesc = ColDesc+ { colDescName :: String+ , colDesc :: HDBC.SqlColDesc+ , colDescDecode :: PGValue -> HDBC.SqlValue+ }++data Cursor = Cursor+ { cursorDesc :: [ColDesc]+ , cursorRow :: [PGValues]+ , cursorActive :: Bool+ , _cursorStatement :: HDBC.Statement -- keep a handle to prevent GC+ }++noCursor :: HDBC.Statement -> Cursor+noCursor = Cursor [] [] False++getType :: Connection -> PGConnection -> Maybe Bool -> PGColDescription -> ColDesc+getType c pg nul PGColDescription{..} = ColDesc+ { colDescName = BSC.unpack colName+ , colDesc = HDBC.SqlColDesc+ { HDBC.colType = sqlTypeId t+ , HDBC.colSize = fromIntegral colModifier <$ guard (colModifier >= 0)+ , HDBC.colOctetLength = fromIntegral colSize <$ guard (colSize >= 0)+ , HDBC.colDecDigits = Nothing+ , HDBC.colNullable = nul+ }+ , colDescDecode = sqlTypeDecode t+ } where t = IntMap.findWithDefault (sqlType (pgTypeEnv pg) $ show colType) (fromIntegral colType) (connectionTypes c)++instance HDBC.IConnection Connection where+ disconnect c = withPG c+ pgDisconnectOnce+ commit c = withPG c $ \pg -> do+ pgCommitAll pg+ pgBegin pg+ rollback c = withPG c $ \pg -> do+ pgRollbackAll pg+ pgBegin pg+ runRaw c q = withPG c $ \pg ->+ pgSimpleQueries_ pg $ sqls q+ run c q v = withPG c $ \pg -> do+ let q' = sqls $ show $ placeholders 1 $ sqlTokens q+ v' = map encode v+ fromMaybe 0 <$> pgRun pg q' [] v'+ prepare c q = do+ let q' = sqls $ show $ placeholders 1 $ sqlTokens q+ n <- withPG c $ \pg -> pgPrepare pg q' []+ cr <- newIORef $ error "Cursor"+ let+ execute v = withPG c $ \pg -> do+ d <- pgBind pg n (map encode v)+ (r, e) <- pgFetch pg n (connectionFetchSize c)+ modifyIORef' cr $ \p -> p+ { cursorDesc = map (getType c pg Nothing) d+ , cursorRow = r+ , cursorActive = isNothing e+ }+ return $ fromMaybe 0 e+ stmt = HDBC.Statement+ { HDBC.execute = execute+ , HDBC.executeRaw = void $ execute []+ , HDBC.executeMany = mapM_ execute+ , HDBC.finish = withPG c $ \pg -> do+ writeIORef cr $ noCursor stmt+ pgClose pg n+ , HDBC.fetchRow = withPG c $ \pg -> do+ p <- readIORef cr+ fmap (zipWith colDescDecode (cursorDesc p)) <$> case cursorRow p of+ [] | cursorActive p -> do+ (rl, e) <- pgFetch pg n (connectionFetchSize c)+ let rl' = uncons rl+ writeIORef cr p+ { cursorRow = maybe [] snd rl'+ , cursorActive = isNothing e+ }+ return $ fst <$> rl'+ | otherwise ->+ return Nothing+ (r:l) -> do+ writeIORef cr p{ cursorRow = l }+ return $ Just r+ , HDBC.getColumnNames =+ map colDescName . cursorDesc <$> readIORef cr+ , HDBC.originalQuery = q+ , HDBC.describeResult =+ map (colDescName &&& colDesc) . cursorDesc <$> readIORef cr+ }+ writeIORef cr $ noCursor stmt+ addFinalizer stmt $ withPG c $ \pg -> pgClose pg n+ return stmt+ clone c = withPG c $ \pg -> do+ pg' <- pgConnect $ pgConnectionDatabase pg+ pgv <- takePGConnection pg'+ return c{ connectionPG = pgv }+ hdbcDriverName _ = "postgresql-typed"+ hdbcClientVer _ = show version+ proxiedClientName = HDBC.hdbcDriverName+ proxiedClientVer = HDBC.hdbcClientVer+ dbServerVer = connectionServerVer+ dbTransactionSupport _ = True+ getTables c = withPG c $ \pg ->+ map (pgDecodeRep . head) . snd <$> pgSimpleQuery pg (BSLC.fromChunks+ [ "SELECT relname "+ , "FROM pg_class "+ , "JOIN pg_namespace "+ , "ON relnamespace = pg_namespace.oid "+ , "WHERE nspname = ANY (current_schemas(false)) "+ , "AND relkind IN ('r','v','m','f')"+ ])+ describeTable c t = withPG c $ \pg -> do+ let makecol ~[attname, attrelid, attnum, atttypid, attlen, atttypmod, attnotnull] =+ colDescName &&& colDesc $ getType c pg (Just $ not $ pgDecodeRep attnotnull) PGColDescription+ { colName = pgDecodeRep attname+ , colTable = pgDecodeRep attrelid+ , colNumber = pgDecodeRep attnum+ , colType = pgDecodeRep atttypid+ , colSize = pgDecodeRep attlen+ , colModifier = pgDecodeRep atttypmod+ , colBinary = False+ }+ map makecol . snd <$> pgSimpleQuery pg (BSLC.fromChunks+ [ "SELECT attname, attrelid, attnum, atttypid, attlen, atttypmod, attnotnull "+ , "FROM pg_attribute "+ , "JOIN pg_class "+ , "ON attrelid = pg_class.oid "+ , "JOIN pg_namespace "+ , "ON relnamespace = pg_namespace.oid "+ , "WHERE nspname = ANY (current_schemas(false)) "+ , "AND relkind IN ('r','v','m','f') "+ , "AND relname = ", pgLiteralRep t+ , " AND attnum > 0 AND NOT attisdropped "+ , "ORDER BY attnum"+ ])++encodeRep :: (PGParameter t a, PGRep t a) => a -> PGValue+encodeRep x = PGTextValue $ pgEncode (pgTypeOf x) x++encode :: HDBC.SqlValue -> PGValue+encode (HDBC.SqlString x) = encodeRep x+encode (HDBC.SqlByteString x) = encodeRep x+encode (HDBC.SqlWord32 x) = encodeRep x+encode (HDBC.SqlWord64 x) = encodeRep (fromIntegral x :: Rational)+encode (HDBC.SqlInt32 x) = encodeRep x+encode (HDBC.SqlInt64 x) = encodeRep x+encode (HDBC.SqlInteger x) = encodeRep (fromInteger x :: Rational)+encode (HDBC.SqlChar x) = encodeRep x+encode (HDBC.SqlBool x) = encodeRep x+encode (HDBC.SqlDouble x) = encodeRep x+encode (HDBC.SqlRational x) = encodeRep x+encode (HDBC.SqlLocalDate x) = encodeRep x+encode (HDBC.SqlLocalTimeOfDay x) = encodeRep x+encode (HDBC.SqlZonedLocalTimeOfDay t z) = encodeRep (t, z)+encode (HDBC.SqlLocalTime x) = encodeRep x+encode (HDBC.SqlZonedTime x) = encodeRep (zonedTimeToUTC x)+encode (HDBC.SqlUTCTime x) = encodeRep x+encode (HDBC.SqlDiffTime x) = encodeRep (realToFrac x :: DiffTime)+encode (HDBC.SqlPOSIXTime x) = encodeRep (realToFrac x :: Rational) -- (posixSecondsToUTCTime x)+encode (HDBC.SqlEpochTime x) = encodeRep (posixSecondsToUTCTime (fromInteger x))+encode (HDBC.SqlTimeDiff x) = encodeRep (fromIntegral x :: DiffTime)+encode HDBC.SqlNull = PGNullValue++data SqlType = SqlType+ { sqlTypeId :: HDBC.SqlTypeId+ , sqlTypeDecode :: PGValue -> HDBC.SqlValue+ }++sqlType :: PGTypeEnv -> String -> SqlType+sqlType e t = SqlType+ { sqlTypeId = typeId t+ , sqlTypeDecode = decode t e+ }++typeId :: String -> HDBC.SqlTypeId+typeId "boolean" = HDBC.SqlBitT+typeId "bytea" = HDBC.SqlVarBinaryT+typeId "\"char\"" = HDBC.SqlCharT+typeId "name" = HDBC.SqlVarCharT+typeId "bigint" = HDBC.SqlBigIntT+typeId "smallint" = HDBC.SqlSmallIntT+typeId "integer" = HDBC.SqlIntegerT+typeId "text" = HDBC.SqlLongVarCharT+typeId "oid" = HDBC.SqlIntegerT+typeId "real" = HDBC.SqlFloatT+typeId "double precision" = HDBC.SqlDoubleT+typeId "abstime" = HDBC.SqlUTCDateTimeT+typeId "reltime" = HDBC.SqlIntervalT HDBC.SqlIntervalSecondT+typeId "tinterval" = HDBC.SqlIntervalT HDBC.SqlIntervalDayToSecondT+typeId "bpchar" = HDBC.SqlVarCharT+typeId "character varying" = HDBC.SqlVarCharT+typeId "date" = HDBC.SqlDateT+typeId "time without time zone" = HDBC.SqlTimeT+typeId "timestamp without time zone" = HDBC.SqlTimestampT+typeId "timestamp with time zone" = HDBC.SqlTimestampWithZoneT -- XXX really SQLUTCDateTimeT+typeId "interval" = HDBC.SqlIntervalT HDBC.SqlIntervalDayToSecondT+typeId "time with time zone" = HDBC.SqlTimeWithZoneT+typeId "numeric" = HDBC.SqlDecimalT+typeId "uuid" = HDBC.SqlGUIDT+typeId t = HDBC.SqlUnknownT t++decodeRep :: PGColumn t a => PGTypeName t -> PGTypeEnv -> (a -> HDBC.SqlValue) -> PGValue -> HDBC.SqlValue+decodeRep t e f (PGBinaryValue v) = f $ pgDecodeBinary e t v+decodeRep t _ f (PGTextValue v) = f $ pgDecode t v+decodeRep _ _ _ PGNullValue = HDBC.SqlNull++#define DECODE(T) \+ decode T e = decodeRep (PGTypeProxy :: PGTypeName T) e++decode :: String -> PGTypeEnv -> PGValue -> HDBC.SqlValue+DECODE("boolean") HDBC.SqlBool+DECODE("\"char\"") HDBC.SqlChar+DECODE("name") HDBC.SqlString+DECODE("bigint") HDBC.SqlInt64+DECODE("smallint") (HDBC.SqlInt32 . fromIntegral :: Int16 -> HDBC.SqlValue)+DECODE("integer") HDBC.SqlInt32+DECODE("text") HDBC.SqlString+DECODE("oid") HDBC.SqlWord32+DECODE("real") HDBC.SqlDouble+DECODE("double precision") HDBC.SqlDouble+DECODE("bpchar") HDBC.SqlString+DECODE("character varying") HDBC.SqlString+DECODE("date") HDBC.SqlLocalDate+DECODE("time without time zone") HDBC.SqlLocalTimeOfDay+DECODE("time with time zone") (uncurry HDBC.SqlZonedLocalTimeOfDay)+DECODE("timestamp without time zone") HDBC.SqlLocalTime+DECODE("timestamp with time zone") HDBC.SqlUTCTime+DECODE("interval") (HDBC.SqlDiffTime . realToFrac :: DiffTime -> HDBC.SqlValue)+DECODE("numeric") HDBC.SqlRational+decode _ _ = decodeRaw where+ decodeRaw (PGBinaryValue v) = HDBC.SqlByteString v+ decodeRaw (PGTextValue v) = HDBC.SqlByteString v+ decodeRaw PGNullValue = HDBC.SqlNull
− Database/PostgreSQL/Typed/Internal.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE PatternSynonyms, PatternGuards, TemplateHaskell, GADTs, KindSignatures, DataKinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-module Database.PostgreSQL.Typed.Internal- ( stringE- , pattern StringE- , SQLSplit(..)- , sqlSplitExprs- , sqlSplitParams- ) where--import Data.Char (isDigit)-import Data.String (IsString(..))-import qualified Language.Haskell.TH as TH-import Numeric (readDec)---- |@'TH.LitE' . 'TH.stringL'@-stringE :: String -> TH.Exp-stringE = TH.LitE . TH.StringL---- |Pattern match for 'stringE'.-pattern StringE s = TH.LitE (TH.StringL s)--instance IsString TH.Exp where- fromString = stringE---- |Parsed representation of a SQL statement containing placeholders.-data SQLSplit a (literal :: Bool) where- SQLLiteral :: String -> SQLSplit a 'False -> SQLSplit a 'True- SQLPlaceholder :: a -> SQLSplit a 'True -> SQLSplit a 'False- SQLSplitEnd :: SQLSplit a any--sqlCons :: Char -> SQLSplit a 'True -> SQLSplit a 'True-sqlCons c (SQLLiteral s l) = SQLLiteral (c : s) l-sqlCons c SQLSplitEnd = SQLLiteral [c] SQLSplitEnd---- |Parse a SQL stamement with ${string} placeholders into a 'SQLSplit'.-sqlSplitExprs :: String -> SQLSplit String 'True-sqlSplitExprs ('$':'$':'{':s) = sqlCons '$' $ sqlCons '{' $ sqlSplitExprs s-sqlSplitExprs ('$':'{':s)- | (e, '}':r) <- break (\c -> c == '{' || c == '}') s = SQLLiteral "" $ SQLPlaceholder e $ sqlSplitExprs r- | otherwise = error $ "Error parsing SQL: could not find end of expression: ${" ++ s-sqlSplitExprs (c:s) = sqlCons c $ sqlSplitExprs s-sqlSplitExprs [] = SQLSplitEnd---- |Parse a SQL stamement with $numeric placeholders into a 'SQLSplit'.-sqlSplitParams :: String -> SQLSplit Int 'True-sqlSplitParams ('$':'$':d:s) | isDigit d = sqlCons '$' $ sqlCons d $ sqlSplitParams s-sqlSplitParams ('$':s@(d:_)) | isDigit d, [(n, r)] <- readDec s = SQLLiteral "" $ SQLPlaceholder n $ sqlSplitParams r-sqlSplitParams (c:s) = sqlCons c $ sqlSplitParams s-sqlSplitParams [] = SQLSplitEnd-
Database/PostgreSQL/Typed/Protocol.hs view
@@ -12,7 +12,9 @@ , PGConnection , PGError(..) , pgErrorCode+ , pgConnectionDatabase , pgTypeEnv+ , pgServerVersion , pgConnect , pgDisconnect , pgReconnect@@ -27,13 +29,25 @@ , pgBegin , pgCommit , pgRollback+ , pgCommitAll+ , pgRollbackAll , pgTransaction+ -- * HDBC support+ , pgDisconnectOnce+ , pgRun+ , PGPreparedStatement+ , pgPrepare+ , pgClose+ , PGColDescription(..)+ , PGRowDescription+ , pgBind+ , pgFetch ) where #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>), (<$)) #endif-import Control.Arrow ((&&&), second)+import Control.Arrow ((&&&), first, second) import Control.Exception (Exception, throwIO, onException) import Control.Monad (void, liftM2, replicateM, when, unless) #ifdef USE_MD5@@ -57,6 +71,7 @@ #if !MIN_VERSION_base(4,8,0) import Data.Monoid (mempty) #endif+import Data.Tuple (swap) import Data.Typeable (Typeable) #if !MIN_VERSION_base(4,8,0) import Data.Word (Word)@@ -71,8 +86,7 @@ import Database.PostgreSQL.Typed.Dynamic data PGState- = StateUnknown -- no Sync- | StateCommand -- was Sync, sent command+ = StateUnsync -- no Sync | StatePending -- Sync sent -- ReadyForQuery received: | StateIdle@@ -97,6 +111,12 @@ PGDatabase h1 s1 n1 u1 p1 l1 _ _ == PGDatabase h2 s2 n2 u2 p2 l2 _ _ = h1 == h2 && s1 == s2 && n1 == n2 && u1 == u2 && p1 == p2 && l1 == l2 +newtype PGPreparedStatement = PGPreparedStatement Integer+ deriving (Eq, Show)++preparedStatementName :: PGPreparedStatement -> BS.ByteString+preparedStatementName (PGPreparedStatement n) = BSC.pack $ show n+ -- |An established connection to the PostgreSQL server. -- These objects are not thread-safe and must only be used for a single request at a time. data PGConnection = PGConnection@@ -106,20 +126,23 @@ , connKey :: !Word32 -- unused , connParameters :: Map.Map BS.ByteString BS.ByteString , connTypeEnv :: PGTypeEnv- , connPreparedStatements :: IORef (Integer, Map.Map (BS.ByteString, [OID]) Integer)+ , connPreparedStatementCount :: IORef Integer+ , connPreparedStatementMap :: IORef (Map.Map (BS.ByteString, [OID]) PGPreparedStatement) , connState :: IORef PGState , connInput :: IORef (G.Decoder PGBackendMessage) , connTransaction :: IORef Word } -data ColDescription = ColDescription+data PGColDescription = PGColDescription { colName :: BS.ByteString , colTable :: !OID , colNumber :: !Int16 , colType :: !OID+ , colSize :: !Int16 , colModifier :: !Int32 , colBinary :: !Bool } deriving (Show)+type PGRowDescription = [PGColDescription] type MessageFields = Map.Map Char BS.ByteString @@ -128,12 +151,14 @@ data PGFrontendMessage = StartupMessage [(BS.ByteString, BS.ByteString)] -- only sent first | CancelRequest !Word32 !Word32 -- sent first on separate connection- | Bind { statementName :: BS.ByteString, bindParameters :: PGValues, binaryColumns :: [Bool] }- | Close { statementName :: BS.ByteString }+ | Bind { portalName :: BS.ByteString, statementName :: BS.ByteString, bindParameters :: PGValues, binaryColumns :: [Bool] }+ | CloseStatement { statementName :: BS.ByteString }+ | ClosePortal { portalName :: BS.ByteString } -- |Describe a SQL query/statement. The SQL string can contain -- parameters ($1, $2, etc.).- | Describe { statementName :: BS.ByteString }- | Execute !Word32+ | DescribeStatement { statementName :: BS.ByteString }+ | DescribePortal { portalName :: BS.ByteString }+ | Execute { portalName :: BS.ByteString, executeRows :: !Word32 } | Flush -- |Parse SQL Destination (prepared statement) | Parse { statementName :: BS.ByteString, queryString :: BSL.ByteString, parseTypes :: [OID] }@@ -177,7 +202,7 @@ -- |A RowDescription contains the name, type, table OID, and -- column number of the resulting columns(s) of a query. The -- column number is useful for inferring nullability.- | RowDescription [ColDescription]+ | RowDescription PGRowDescription deriving (Show) -- |PGException is thrown upon encountering an 'ErrorResponse' with severity of@@ -192,8 +217,11 @@ -- |Produce a human-readable string representing the message displayMessage :: MessageFields -> String-displayMessage m = "PG" ++ f 'S' ++ " [" ++ f 'C' ++ "]: " ++ f 'M' ++ '\n' : f 'D'- where f c = BSC.unpack $ Map.findWithDefault BS.empty c m+displayMessage m = "PG" ++ f 'S' ++ (if null fC then ": " else " [" ++ fC ++ "]: ") ++ f 'M' ++ (if null fD then fD else '\n' : fD)+ where+ fC = f 'C'+ fD = f 'D'+ f c = BSC.unpack $ Map.findWithDefault BS.empty c m makeMessage :: BS.ByteString -> BS.ByteString -> MessageFields makeMessage m d = Map.fromAscList [('D', d), ('M', m)]@@ -217,9 +245,18 @@ connLogMessage :: PGConnection -> MessageFields -> IO () connLogMessage = pgDBLogMessage . connDatabase +-- |The database information for this connection.+pgConnectionDatabase :: PGConnection -> PGDatabase+pgConnectionDatabase = connDatabase++-- |The type environment for this connection. pgTypeEnv :: PGConnection -> PGTypeEnv pgTypeEnv = connTypeEnv +-- |Retrieve the \"server_version\" parameter from the connection, if any.+pgServerVersion :: PGConnection -> Maybe BS.ByteString+pgServerVersion PGConnection{ connParameters = p } = Map.lookup (BSC.pack "server_version") p+ #ifdef USE_MD5 md5 :: BS.ByteString -> BS.ByteString md5 = BA.convertToBase BA.Base16 . (Hash.hash :: BS.ByteString -> Hash.Digest Hash.MD5)@@ -241,8 +278,9 @@ <> Fold.foldMap (\(k, v) -> byteStringNul k <> byteStringNul v) kv <> nul) messageBody (CancelRequest pid key) = (Nothing, B.word32BE 80877102 <> B.word32BE pid <> B.word32BE key)-messageBody Bind{ statementName = n, bindParameters = p, binaryColumns = bc } = (Just 'B',- nul <> byteStringNul n+messageBody Bind{ portalName = d, statementName = n, bindParameters = p, binaryColumns = bc } = (Just 'B',+ byteStringNul d+ <> byteStringNul n <> (if any fmt p then B.word16BE (fromIntegral $ length p) <> Fold.foldMap (B.word16BE . fromIntegral . fromEnum . fmt) p else B.word16BE 0)@@ -256,12 +294,16 @@ val PGNullValue = B.int32BE (-1) val (PGTextValue v) = B.word32BE (fromIntegral $ BS.length v) <> B.byteString v val (PGBinaryValue v) = B.word32BE (fromIntegral $ BS.length v) <> B.byteString v-messageBody Close{ statementName = n } = (Just 'C', +messageBody CloseStatement{ statementName = n } = (Just 'C', B.char7 'S' <> byteStringNul n)-messageBody Describe{ statementName = n } = (Just 'D',+messageBody ClosePortal{ portalName = n } = (Just 'C', + B.char7 'P' <> byteStringNul n)+messageBody DescribeStatement{ statementName = n } = (Just 'D', B.char7 'S' <> byteStringNul n)-messageBody (Execute r) = (Just 'E',- nul <> B.word32BE r)+messageBody DescribePortal{ portalName = n } = (Just 'D',+ B.char7 'P' <> byteStringNul n)+messageBody Execute{ portalName = n, executeRows = r } = (Just 'E',+ byteStringNul n <> B.word32BE r) messageBody Flush = (Just 'H', mempty) messageBody Parse{ statementName = n, queryString = s, parseTypes = t } = (Just 'P', byteStringNul n <> lazyByteStringNul s@@ -285,8 +327,7 @@ state _ StateClosed = StateClosed state Sync _ = StatePending state Terminate _ = StateClosed- state _ StateUnknown = StateUnknown- state _ _ = StateCommand+ state _ _ = StateUnsync pgFlush :: PGConnection -> IO () pgFlush = hFlush . connHandle@@ -318,14 +359,15 @@ oid <- G.getWord32be -- table OID col <- G.getWord16be -- column number typ' <- G.getWord32be -- type- _ <- G.getWord16be -- type size+ siz <- G.getWord16be -- type size tmod <- G.getWord32be -- type modifier fmt <- G.getWord16be -- format code- return $ ColDescription+ return $ PGColDescription { colName = name , colTable = oid , colNumber = fromIntegral col , colType = typ'+ , colSize = fromIntegral siz , colModifier = fromIntegral tmod , colBinary = toEnum (fromIntegral fmt) }@@ -382,10 +424,8 @@ else go $ r (Just b) got :: G.Decoder PGBackendMessage -> PGBackendMessage -> PGState -> IO (Maybe PGBackendMessage) got d (NoticeResponse m) _ = connLogMessage c m >> go d- got d (ReadyForQuery _) StateCommand = go d got d m@(ReadyForQuery s) _ = Just m <$ state s d- got d m@(ErrorResponse _) _ = Just m <$ state StateUnknown d- got d m StateCommand = Just m <$ state StateUnknown d+ got d m@(ErrorResponse _) _ = Just m <$ state StateUnsync d got d m _ = Just m <$ next d -- |Receive the next message from PostgreSQL (low-level). Note that this will@@ -403,8 +443,9 @@ -- |Connect to a PostgreSQL server. pgConnect :: PGDatabase -> IO PGConnection pgConnect db = do- state <- newIORef StateUnknown- prep <- newIORef (0, Map.empty)+ state <- newIORef StateUnsync+ prepc <- newIORef 0+ prepm <- newIORef Map.empty input <- newIORef getMessage tr <- newIORef 0 h <- connectTo (pgDBHost db) (pgDBPort db)@@ -415,7 +456,8 @@ , connPid = 0 , connKey = 0 , connParameters = Map.empty- , connPreparedStatements = prep+ , connPreparedStatementCount = prepc+ , connPreparedStatementMap = prepm , connState = state , connTypeEnv = unknownPGTypeEnv , connInput = input@@ -461,6 +503,14 @@ pgSend c Terminate hClose h +-- |Disconnect cleanly from the PostgreSQL server, but only if it's still connected.+pgDisconnectOnce :: PGConnection -- ^ a handle from 'pgConnect'+ -> IO ()+pgDisconnectOnce c@PGConnection{ connState = cs } = do+ s <- readIORef cs+ unless (s == StateClosed) $+ pgDisconnect c+ -- |Possibly re-open a connection to a different database, either reusing the connection if the given database is already connected or closing it and opening a new one. -- Regardless, the input connection must not be used afterwards. pgReconnect :: PGConnection -> PGDatabase -> IO PGConnection@@ -478,7 +528,7 @@ case s of StateClosed -> fail "pgSync: operation on closed connection" StatePending -> wait True- StateUnknown -> wait False+ StateUnsync -> wait False _ -> return () where wait s = do@@ -496,6 +546,11 @@ connLogMessage c $ makeMessage (BSC.pack $ "Unexpected server message: " ++ show m) $ BSC.pack "Each statement should only contain a single query" wait s +rowDescription :: PGBackendMessage -> PGRowDescription+rowDescription (RowDescription d) = d+rowDescription NoData = []+rowDescription m = error $ "describe: unexpected response: " ++ show m+ -- |Describe a SQL statement/query. A statement description consists of 0 or -- more parameter descriptions (a PostgreSQL type) and zero or more result -- field descriptions (for queries) (consist of the name of the field, the@@ -506,20 +561,15 @@ -> IO ([OID], [(BS.ByteString, OID, Bool)]) -- ^ a list of parameter types, and a list of result field names, types, and nullability indicators. pgDescribe h sql types nulls = do pgSync h- pgSend h $ Parse{ queryString = sql, statementName = BS.empty, parseTypes = types }- pgSend h $ Describe BS.empty- pgSend h Flush+ pgSend h Parse{ queryString = sql, statementName = BS.empty, parseTypes = types }+ pgSend h DescribeStatement{ statementName = BS.empty } pgSend h Sync pgFlush h ParseComplete <- pgReceive h ParameterDescription ps <- pgReceive h- m <- pgReceive h- (,) ps <$> case m of- NoData -> return []- RowDescription r -> mapM desc r- _ -> fail $ "describeStatement: unexpected response: " ++ show m+ (,) ps <$> (mapM desc . rowDescription =<< pgReceive h) where- desc (ColDescription{ colName = name, colTable = tab, colNumber = col, colType = typ }) = do+ desc (PGColDescription{ colName = name, colTable = tab, colNumber = col, colType = typ }) = do n <- nullable tab col return (name, typ, n) -- We don't get nullability indication from PostgreSQL, at least not directly.@@ -536,12 +586,12 @@ _ -> fail $ "Failed to determine nullability of column #" ++ show col | otherwise = return True -rowsAffected :: BS.ByteString -> Int+rowsAffected :: (Integral i, Read i) => BS.ByteString -> i rowsAffected = ra . BSC.words where ra [] = -1 ra l = fromMaybe (-1) $ readMaybe $ BSC.unpack $ last l --- Do we need to use the ColDescription here always, or are the request formats okay?+-- Do we need to use the PGColDescription here always, or are the request formats okay? fixBinary :: [Bool] -> PGValues -> PGValues fixBinary (False:b) (PGBinaryValue x:r) = PGTextValue x : fixBinary b r fixBinary (True :b) (PGTextValue x:r) = PGBinaryValue x : fixBinary b r@@ -588,22 +638,23 @@ res m = fail $ "pgSimpleQueries_: unexpected response: " ++ show m pgPreparedBind :: PGConnection -> BS.ByteString -> [OID] -> PGValues -> [Bool] -> IO (IO ())-pgPreparedBind c@PGConnection{ connPreparedStatements = psr } sql types bind bc = do+pgPreparedBind c sql types bind bc = do pgSync c- (p, n) <- atomicModifyIORef' psr $ \(i, m) ->- maybe ((succ i, m), (False, i)) ((,) (i, m) . (,) True) $ Map.lookup key m- let sn = BSC.pack $ show n+ m <- readIORef (connPreparedStatementMap c)+ (p, n) <- maybe+ (atomicModifyIORef' (connPreparedStatementCount c) (succ &&& (,) False . PGPreparedStatement))+ (return . (,) True) $ Map.lookup key m unless p $- pgSend c $ Parse{ queryString = BSL.fromStrict sql, statementName = sn, parseTypes = types }- pgSend c $ Bind{ statementName = sn, bindParameters = bind, binaryColumns = bc }+ pgSend c Parse{ queryString = BSL.fromStrict sql, statementName = preparedStatementName n, parseTypes = types }+ pgSend c Bind{ portalName = BS.empty, statementName = preparedStatementName n, bindParameters = bind, binaryColumns = bc } let go = pgReceive c >>= start start ParseComplete = do- modifyIORef psr $ \(i, m) ->- (i, Map.insert key n m)+ modifyIORef (connPreparedStatementMap c) $+ Map.insert key n go start BindComplete = return ()- start m = fail $ "pgPrepared: unexpected response: " ++ show m+ start r = fail $ "pgPrepared: unexpected response: " ++ show r return go where key = (sql, types) @@ -616,8 +667,7 @@ -> IO (Int, [PGValues]) pgPreparedQuery c sql types bind bc = do start <- pgPreparedBind c sql types bind bc- pgSend c $ Execute 0- pgSend c Flush+ pgSend c Execute{ portalName = BS.empty, executeRows = 0 } pgSend c Sync pgFlush c start@@ -641,8 +691,8 @@ go id where execute = do- pgSend c $ Execute count- pgSend c $ Flush+ pgSend c Execute{ portalName = BS.empty, executeRows = count }+ pgSend c Flush pgFlush c go r = pgReceive c >>= row r row r (DataRow fs) = go (r . (fixBinary bc fs :))@@ -653,15 +703,10 @@ -- |Close a previously prepared query (if necessary). pgCloseStatement :: PGConnection -> BS.ByteString -> [OID] -> IO ()-pgCloseStatement c@PGConnection{ connPreparedStatements = psr } sql types = do- mn <- atomicModifyIORef psr $ \(i, m) ->- let (n, m') = Map.updateLookupWithKey (\_ _ -> Nothing) (sql, types) m in ((i, m'), n)- Fold.forM_ mn $ \n -> do- pgSync c- pgSend c $ Close{ statementName = BSC.pack $ show n }- pgFlush c- CloseComplete <- pgReceive c- return ()+pgCloseStatement c sql types = do+ mn <- atomicModifyIORef (connPreparedStatementMap c) $+ swap . Map.updateLookupWithKey (\_ _ -> Nothing) (sql, types)+ Fold.mapM_ (pgClose c) mn -- |Begin a new transaction. If there is already a transaction in progress (created with 'pgBegin' or 'pgTransaction') instead creates a savepoint. pgBegin :: PGConnection -> IO ()@@ -685,6 +730,18 @@ t <- atomicModifyIORef' tr predTransaction void $ pgSimpleQuery c $ BSLC.pack $ if t == 0 then "COMMIT" else "RELEASE SAVEPOINT pgt" ++ show t +-- |Rollback all active 'pgBegin's.+pgRollbackAll :: PGConnection -> IO ()+pgRollbackAll c@PGConnection{ connTransaction = tr } = do+ writeIORef tr 0+ void $ pgSimpleQuery c $ BSLC.pack "ROLLBACK"++-- |Commit all active 'pgBegin's.+pgCommitAll :: PGConnection -> IO ()+pgCommitAll c@PGConnection{ connTransaction = tr } = do+ writeIORef tr 0+ void $ pgSimpleQuery c $ BSLC.pack "COMMIT"+ -- |Wrap a computation in a 'pgBegin', 'pgCommit' block, or 'pgRollback' on exception. pgTransaction :: PGConnection -> IO a -> IO a pgTransaction c f = do@@ -694,3 +751,82 @@ pgCommit c return r) (pgRollback c)++-- |Prepare, bind, execute, and close a single (unnamed) query, and return the number of rows affected, or Nothing if there are (ignored) result rows.+pgRun :: PGConnection -> BSL.ByteString -> [OID] -> PGValues -> IO (Maybe Integer)+pgRun c sql types bind = do+ pgSync c+ pgSend c Parse{ queryString = sql, statementName = BS.empty, parseTypes = types }+ pgSend c Bind{ portalName = BS.empty, statementName = BS.empty, bindParameters = bind, binaryColumns = [] }+ pgSend c Execute{ portalName = BS.empty, executeRows = 1 } -- 0 does not mean none+ pgSend c Sync+ pgFlush c+ go where+ go = pgReceive c >>= res+ res ParseComplete = go+ res BindComplete = go+ res (DataRow _) = go+ res PortalSuspended = return Nothing+ res (CommandComplete d) = return (Just $ rowsAffected d)+ res EmptyQueryResponse = return (Just 0)+ res m = fail $ "pgRun: unexpected response: " ++ show m++-- |Prepare a single query and return its handle.+pgPrepare :: PGConnection -> BSL.ByteString -> [OID] -> IO PGPreparedStatement+pgPrepare c sql types = do+ n <- atomicModifyIORef' (connPreparedStatementCount c) (succ &&& PGPreparedStatement)+ pgSync c+ pgSend c Parse{ queryString = sql, statementName = preparedStatementName n, parseTypes = types }+ pgSend c Sync+ pgFlush c+ ParseComplete <- pgReceive c+ return n++-- |Close a previously prepared query.+pgClose :: PGConnection -> PGPreparedStatement -> IO ()+pgClose c n = do+ pgSync c+ pgSend c ClosePortal{ portalName = preparedStatementName n }+ pgSend c CloseStatement{ statementName = preparedStatementName n }+ pgSend c Sync+ pgFlush c+ CloseComplete <- pgReceive c+ CloseComplete <- pgReceive c+ return ()++-- |Bind a prepared statement, and return the row description.+-- After 'pgBind', you must either call 'pgFetch' until it completes (returns @(_, 'Just' _)@) or 'pgFinish' before calling 'pgBind' again on the same prepared statement.+pgBind :: PGConnection -> PGPreparedStatement -> PGValues -> IO PGRowDescription+pgBind c n bind = do+ pgSync c+ pgSend c ClosePortal{ portalName = sn }+ pgSend c Bind{ portalName = sn, statementName = sn, bindParameters = bind, binaryColumns = [] }+ pgSend c DescribePortal{ portalName = sn }+ pgSend c Sync+ pgFlush c+ CloseComplete <- pgReceive c+ BindComplete <- pgReceive c+ rowDescription <$> pgReceive c+ where sn = preparedStatementName n++-- |Fetch a single row from an executed prepared statement, returning the next N result rows (if any) and number of affected rows when complete.+pgFetch :: PGConnection -> PGPreparedStatement -> Word32 -- ^Maximum number of rows to return, or 0 for all+ -> IO ([PGValues], Maybe Integer)+pgFetch c n count = do+ pgSync c+ pgSend c Execute{ portalName = preparedStatementName n, executeRows = count }+ pgSend c Sync+ pgFlush c+ go where+ go = pgReceive c >>= res+ res (DataRow v) = first (v :) <$> go+ res PortalSuspended = return ([], Nothing)+ res (CommandComplete d) = do+ pgSync c+ pgSend c ClosePortal{ portalName = preparedStatementName n }+ pgSend c Sync+ pgFlush c+ CloseComplete <- pgReceive c+ return ([], Just $ rowsAffected d)+ res EmptyQueryResponse = return ([], Just 0)+ res m = fail $ "pgFetch: unexpected response: " ++ show m
Database/PostgreSQL/Typed/Query.hs view
@@ -35,11 +35,11 @@ import qualified Language.Haskell.TH as TH import Language.Haskell.TH.Quote (QuasiQuoter(..)) -import Database.PostgreSQL.Typed.Internal import Database.PostgreSQL.Typed.Types import Database.PostgreSQL.Typed.Dynamic import Database.PostgreSQL.Typed.Protocol import Database.PostgreSQL.Typed.TH+import Database.PostgreSQL.Typed.SQLToken class PGQuery q a | q -> a where -- |Execute a query and return the number of rows affected (or -1 if not known) and a list of results.@@ -126,30 +126,24 @@ PreparedQuery sql types bind bc = q e -- |Given a SQL statement with placeholders of the form @${expr}@, return a (hopefully) valid SQL statement with @$N@ placeholders and the list of expressions.--- This does not understand strings or other SQL syntax, so any literal occurrence of the string @${@ must be escaped as @$${@.--- Embedded expressions may not contain @{@ or @}@.+-- This does its best to understand SQL syntax, so placeholders are only interpreted in places postgres would understand them (i.e., not in quoted strings). Since this is not valid SQL otherwise, there is never reason to escape a literal @${@.+-- You can use @$N@ placeholders in the query otherwise to refer to the N-th index placeholder expression. sqlPlaceholders :: String -> (String, [String])-sqlPlaceholders = ssl 1 . sqlSplitExprs where- ssl :: Int -> SQLSplit String 'True -> (String, [String])- ssl n (SQLLiteral s l) = first (s ++) $ ssp n l- ssl _ SQLSplitEnd = ("", [])- ssp :: Int -> SQLSplit String 'False -> (String, [String])- ssp n (SQLPlaceholder e l) = (('$':show n) ++) *** (e :) $ ssl (succ n) l- ssp _ SQLSplitEnd = ("", [])+sqlPlaceholders = sst (1 :: Int) . sqlTokens where+ sst n (SQLExpr e : l) = (('$':show n) ++) *** (e :) $ sst (succ n) l+ sst n (t : l) = first (show t ++) $ sst n l+ sst _ [] = ("", []) -- |Given a SQL statement with placeholders of the form @$N@ and a list of TH 'ByteString' expressions, return a new 'ByteString' expression that substitutes the expressions for the placeholders.--- This does not understand strings or other SQL syntax, so any literal occurrence of a string like @$N@ must be escaped as @$$N@. sqlSubstitute :: String -> [TH.Exp] -> TH.Exp-sqlSubstitute sql exprl = TH.AppE (TH.VarE 'BS.concat) $ TH.ListE $ ssl $ sqlSplitParams sql where+sqlSubstitute sql exprl = TH.AppE (TH.VarE 'BS.concat) $ TH.ListE $ map sst $ sqlTokens sql where bnds = (1, length exprl) exprs = listArray bnds exprl expr n | inRange bnds n = exprs ! n- | otherwise = error $ "SQL placeholder '$" ++ show n ++ "' out of range (not recognized by PostgreSQL); literal occurrences may need to be escaped with '$$'"- ssl (SQLLiteral s l) = TH.VarE 'fromString `TH.AppE` stringE s : ssp l- ssl SQLSplitEnd = []- ssp (SQLPlaceholder n l) = expr n : ssl l- ssp SQLSplitEnd = []+ | otherwise = error $ "SQL placeholder '$" ++ show n ++ "' out of range (not recognized by PostgreSQL)"+ sst (SQLParam n) = expr n+ sst t = TH.VarE 'fromString `TH.AppE` TH.LitE (TH.StringL $ show t) splitCommas :: String -> [String] splitCommas = spl where@@ -180,7 +174,7 @@ makePGQuery QueryFlags{ flagQuery = False } sqle = pgSubstituteLiterals sqle makePGQuery QueryFlags{ flagNullable = nulls, flagPrepare = prep } sqle = do (pt, rt) <- TH.runIO $ tpgDescribe (fromString sqlp) (fromMaybe [] prep) (isNothing nulls)- when (length pt < length exprs) $ fail "Not all expression placeholders were recognized by PostgreSQL; literal occurrences of '${' may need to be escaped with '$${'"+ when (length pt < length exprs) $ fail "Not all expression placeholders were recognized by PostgreSQL" e <- TH.newName "_tenv" (vars, vals) <- mapAndUnzipM (\t -> do@@ -201,7 +195,7 @@ (TH.ConE 'SimpleQuery `TH.AppE` sqlSubstitute sqlp vals) (\p -> TH.ConE 'PreparedQuery- `TH.AppE` (TH.VarE 'fromString `TH.AppE` stringE sqlp)+ `TH.AppE` (TH.VarE 'fromString `TH.AppE` TH.LitE (TH.StringL sqlp)) `TH.AppE` TH.ListE (map (TH.LitE . TH.IntegerL . toInteger . tpgValueTypeOID . snd) $ zip p pt) `TH.AppE` TH.ListE vals `TH.AppE` TH.ListE @@ -250,8 +244,8 @@ -- It will be replaced by a 'PGQuery' object that can be used to perform the SQL statement. -- If there are more @$N@ placeholders than expressions, it will instead be a function accepting the additional parameters and returning a 'PGQuery'. -- --- Note that all occurrences of @$N@ or @${@ will be treated as placeholders, regardless of their context in the SQL (e.g., even within SQL strings or other places placeholders are disallowed by PostgreSQL), which may cause invalid SQL or other errors.--- If you need to pass a literal @$@ through in these contexts, you may double it to escape it as @$$N@ or @$${@.+-- Ideally, this mimics postgres' SQL parsing, so that placeholders and expressions will only be expanded when they are in valid positions (i.e., not inside quoted strings).+-- Since @${@ is not valid SQL otherwise, there should be no need to escape it. -- -- The statement may start with one of more special flags affecting the interpretation: --
Database/PostgreSQL/Typed/Range.hs view
@@ -144,7 +144,7 @@ isFull _ = False -- |Create a point range @[x,x]@-point :: Eq a => a -> Range a+point :: a -> Range a point a = Range (Lower (Bounded True a)) (Upper (Bounded True a)) -- |Extract a point: @getPoint (point x) == Just x@
+ Database/PostgreSQL/Typed/SQLToken.hs view
@@ -0,0 +1,131 @@+-- |+-- Module: Database.PostgreSQL.Typed.SQLToken+-- Copyright: 2016 Dylan Simon+-- +-- Parsing of SQL statements to safely identify placeholders.+-- Supports both dollar-placeholders and question marks for HDBC.+{-# LANGUAGE PatternGuards #-}+module Database.PostgreSQL.Typed.SQLToken+ ( SQLToken(..)+ , sqlTokens+ ) where++import Control.Arrow (first)+import Data.Char (isDigit, isAsciiUpper, isAsciiLower)+import Data.List (stripPrefix)+import Data.String (IsString(..))++-- |A parsed SQL token.+data SQLToken+ = SQLToken String -- ^Raw (non-markup) SQL string+ | SQLParam Int -- ^A \"$N\" parameter placeholder (this is the only non-string-preserving token: \"$012\" becomes \"$12\")+ | SQLExpr String -- ^A \"${expr}\" expression placeholder+ | SQLQMark Bool -- ^A possibly-escaped question-mark: False for \"?\" or True for \"\\?\"+ deriving (Eq)++-- |Produces the original SQL string+instance Show SQLToken where+ showsPrec _ (SQLToken s) = showString s+ showsPrec _ (SQLParam p) = showChar '$' . shows p+ showsPrec _ (SQLExpr e) = showString "${" . showString e . showChar '}'+ showsPrec _ (SQLQMark False) = showChar '?'+ showsPrec _ (SQLQMark True) = showString "\\?"+ showList = flip $ foldr shows++instance IsString SQLToken where+ fromString = SQLToken++type PH = String -> [SQLToken]++infixr 4 ++:, +:++(++:) :: String -> [SQLToken] -> [SQLToken]+p ++: (SQLToken q : l) = SQLToken (p ++ q) : l+p ++: l = SQLToken p : l++(+:) :: Char -> [SQLToken] -> [SQLToken]+p +: (SQLToken q : l) = SQLToken (p : q) : l+p +: l = SQLToken [p] : l++x :: PH+x ('-':'-':s) = "--" ++: comment s+x ('e':'\'':s) = "e'" ++: xe s+x ('E':'\'':s) = "E'" ++: xe s+x ('\'':s) = '\'' +: xq s+x ('$':'{':s) = expr s+x ('$':'$':s) = "$$" ++: xdolq "" s+x ('$':c:s)+ | dolqStart c+ , (t,'$':r) <- span dolqCont s+ = '$' : c : t ++: '$' +: xdolq (c:t) r+ | isDigit c+ , (i,r) <- span isDigit s+ = SQLParam (read $ c:i) : x r+x ('"':s) = '"' +: xd s+x ('/':'*':s) = "/*" ++: xc 1 s+x (c:s)+ | identStart c+ , (i,r) <- span identCont s+ = c : i ++: x r+x ('\\':'?':s) = SQLQMark True : x s+x ('?':s) = SQLQMark False : x s+x (c:s) = c +: x s+x [] = []++xthru :: (Char -> Bool) -> PH+xthru f s = case break f s of+ (p, c:r) -> p ++ [c] ++: x r+ (p, []) -> [SQLToken p]++comment :: PH+comment = xthru (\n -> '\n' == n || '\r' == n)++xe :: PH+xe ('\\':c:s) = '\\' +: c +: xe s+xe ('\'':s) = '\'' +: x s+xe (c:s) = c +: xe s+xe [] = []++xq :: PH+xq = xthru ('\'' ==)+-- no need to handle xqdouble++xd :: PH+xd = xthru ('\"' ==)+-- no need to handle xddouble++identStart, identCont, dolqStart, dolqCont :: Char -> Bool+identStart c = isAsciiUpper c || isAsciiLower c || c >= '\128' && c <= '\255' || c == '_'+dolqStart = identStart+dolqCont c = dolqStart c || isDigit c+identCont c = dolqCont c || c == '$'++xdolq :: String -> PH+xdolq t = dolq where+ dolq ('$':s)+ | Just r <- stripPrefix t' s = '$':t' ++: x r+ dolq (c:s) = c +: dolq s+ dolq [] = []+ t' = t ++ "$"++xc :: Int -> PH+xc 0 s = x s+xc n ('/':'*':s) = "/*" ++: xc (succ n) s+xc n ('*':'/':s) = "*/" ++: xc (pred n) s+xc n (c:s) = c +: xc n s+xc _ [] = []++expr :: PH+expr = pr . ex (0 :: Int) where+ pr (e, Nothing) = [SQLToken ("${" ++ e)]+ pr (e, Just r) = SQLExpr e : r+ ex 0 ('}':s) = ("", Just $ x s)+ ex n ('}':s) = first ('}':) $ ex (pred n) s+ ex n ('{':s) = first ('{':) $ ex (succ n) s+ ex n (c:s) = first (c:) $ ex n s+ ex _ [] = ("", Nothing)++-- |Parse a SQL string into a series of tokens.+-- The 'showList' implementation for 'SQLToken' inverts this sequence back to a SQL string.+sqlTokens :: String -> [SQLToken]+sqlTokens = x
Database/PostgreSQL/Typed/TH.hs view
@@ -16,6 +16,9 @@ , tpgTypeEncoder , tpgTypeDecoder , tpgTypeBinary+ -- * HDBC support+ , PGTypes+ , pgLoadTypes ) where #if !MIN_VERSION_base(4,8,0)@@ -74,13 +77,21 @@ data TPGState = TPGState { tpgConnection :: PGConnection- , tpgTypes :: IntMap.IntMap TPGType -- keyed on fromIntegral OID+ , tpgTypes :: PGTypes } +-- |Map keyed on fromIntegral OID.+type PGTypes = IntMap.IntMap TPGType++-- |Load a map of types from the database.+pgLoadTypes :: PGConnection -> IO PGTypes+pgLoadTypes c =+ IntMap.fromAscList . map (\[to, tn] -> (fromIntegral (pgDecodeRep to :: OID), pgDecodeRep tn)) .+ snd <$> pgSimpleQuery c (BSLC.pack "SELECT typ.oid, format_type(CASE WHEN typtype = 'd' THEN typbasetype ELSE typ.oid END, -1) FROM pg_catalog.pg_type typ JOIN pg_catalog.pg_namespace nsp ON typnamespace = nsp.oid WHERE nspname <> 'pg_toast' AND nspname <> 'information_schema' ORDER BY typ.oid")+ tpgLoadTypes :: TPGState -> IO TPGState tpgLoadTypes tpg = do- t <- IntMap.fromAscList . map (\[to, tn] -> (fromIntegral (pgDecodeRep to :: OID), pgDecodeRep tn)) .- snd <$> pgSimpleQuery (tpgConnection tpg) (BSLC.pack "SELECT typ.oid, format_type(CASE WHEN typtype = 'd' THEN typbasetype ELSE typ.oid END, -1) FROM pg_catalog.pg_type typ JOIN pg_catalog.pg_namespace nsp ON typnamespace = nsp.oid WHERE nspname <> 'pg_toast' AND nspname <> 'information_schema' ORDER BY typ.oid")+ t <- pgLoadTypes (tpgConnection tpg) return tpg{ tpgTypes = t } tpgInit :: PGConnection -> IO TPGState@@ -123,7 +134,7 @@ -- Error if not found. tpgType :: TPGState -> OID -> TPGType tpgType TPGState{ tpgTypes = types } t =- IntMap.findWithDefault (error $ "Unknown PostgreSQL type: " ++ show t) (fromIntegral t) types+ IntMap.findWithDefault (error $ "Unknown PostgreSQL type: " ++ show t ++ "\nYour postgresql-typed application may need to be rebuilt.") (fromIntegral t) types -- |Lookup a type OID by type name. -- This is less common and thus less efficient than going the other way.
Database/PostgreSQL/Typed/Types.hs view
@@ -40,6 +40,7 @@ #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>), (<$), (<*), (*>)) #endif+import Control.Arrow ((&&&)) #ifdef USE_AESON import qualified Data.Aeson as JSON #endif@@ -163,7 +164,6 @@ pgDecodeValue _ _ PGNullValue = Nothing pgDecodeValue e t v = Just $ pgDecodeValue e t v - -- |Final parameter encoding function used when a (nullable) parameter is passed to a prepared query. pgEncodeParameter :: PGParameter t a => PGTypeEnv -> PGTypeName t -> a -> PGValue pgEncodeParameter = pgEncodeValue@@ -233,6 +233,17 @@ #define BIN_DEC(F) #endif +instance PGType "any"+instance PGType t => PGColumn t PGValue where+ pgDecode _ = PGTextValue+ pgDecodeBinary _ _ = PGBinaryValue+ pgDecodeValue _ _ = id+instance PGParameter "any" PGValue where+ pgEncode _ (PGTextValue v) = v+ pgEncode _ PGNullValue = error "pgEncode any: NULL"+ pgEncode _ (PGBinaryValue _) = error "pgEncode any: binary"+ pgEncodeValue _ _ = id+ instance PGType "void" instance PGColumn "void" () where pgDecode _ _ = ()@@ -298,12 +309,19 @@ instance PGColumn "real" Float where pgDecode _ = read . BSC.unpack BIN_DEC(binDec BinD.float4)+instance PGColumn "real" Double where+ pgDecode _ = read . BSC.unpack+ BIN_DEC((realToFrac .) . binDec BinD.float4) instance PGType "double precision" where BIN_COL instance PGParameter "double precision" Double where pgEncode _ = BSC.pack . show pgLiteral = pgEncode BIN_ENC(BinE.float8)+instance PGParameter "double precision" Float where+ pgEncode _ = BSC.pack . show+ pgLiteral = pgEncode+ BIN_ENC(BinE.float8 . realToFrac) instance PGColumn "double precision" Double where pgDecode _ = read . BSC.unpack BIN_DEC(binDec BinD.float8)@@ -464,6 +482,16 @@ binDecDatetime _ _ PGTypeEnv{ pgIntegerDatetimes = Nothing } = error "pgDecodeBinary: unknown integer_datetimes value" #endif +-- PostgreSQL uses "[+-]HH[:MM]" timezone offsets, while "%z" uses "+HHMM" by default.+-- readTime can successfully parse both formats, but PostgreSQL needs the colon.+fixTZ :: String -> String+fixTZ "" = ""+fixTZ ['+',h1,h2] | isDigit h1 && isDigit h2 = ['+',h1,h2,':','0','0']+fixTZ ['-',h1,h2] | isDigit h1 && isDigit h2 = ['-',h1,h2,':','0','0']+fixTZ ['+',h1,h2,m1,m2] | isDigit h1 && isDigit h2 && isDigit m1 && isDigit m2 = ['+',h1,h2,':',m1,m2]+fixTZ ['-',h1,h2,m1,m2] | isDigit h1 && isDigit h2 && isDigit m1 && isDigit m2 = ['-',h1,h2,':',m1,m2]+fixTZ (c:s) = c:fixTZ s+ instance PGType "time without time zone" where pgBinaryColumn = binColDatetime instance PGParameter "time without time zone" Time.TimeOfDay where@@ -478,6 +506,20 @@ pgDecodeBinary = binDecDatetime BinD.time_int BinD.time_float #endif +instance PGType "time with time zone" where+ pgBinaryColumn = binColDatetime+instance PGParameter "time with time zone" (Time.TimeOfDay, Time.TimeZone) where+ pgEncode _ (t, z) = BSC.pack $ Time.formatTime defaultTimeLocale "%T%Q" t ++ fixTZ (Time.formatTime defaultTimeLocale "%z" z)+ pgLiteral t = pgQuoteUnsafe . pgEncode t+#ifdef USE_BINARY+ pgEncodeValue = binEncDatetime BinE.timetz_int BinE.timetz_float+#endif+instance PGColumn "time with time zone" (Time.TimeOfDay, Time.TimeZone) where+ pgDecode _ = (Time.localTimeOfDay . Time.zonedTimeToLocalTime &&& Time.zonedTimeZone) . readTime "%T%Q%z" . fixTZ . BSC.unpack+#ifdef USE_BINARY+ pgDecodeBinary = binDecDatetime BinD.timetz_int BinD.timetz_float+#endif+ instance PGType "timestamp without time zone" where pgBinaryColumn = binColDatetime instance PGParameter "timestamp without time zone" Time.LocalTime where@@ -491,16 +533,6 @@ #ifdef USE_BINARY pgDecodeBinary = binDecDatetime BinD.timestamp_int BinD.timestamp_float #endif---- PostgreSQL uses "[+-]HH[:MM]" timezone offsets, while "%z" uses "+HHMM" by default.--- readTime can successfully parse both formats, but PostgreSQL needs the colon.-fixTZ :: String -> String-fixTZ "" = ""-fixTZ ['+',h1,h2] | isDigit h1 && isDigit h2 = ['+',h1,h2,':','0','0']-fixTZ ['-',h1,h2] | isDigit h1 && isDigit h2 = ['-',h1,h2,':','0','0']-fixTZ ['+',h1,h2,m1,m2] | isDigit h1 && isDigit h2 && isDigit m1 && isDigit m2 = ['+',h1,h2,':',m1,m2]-fixTZ ['-',h1,h2,m1,m2] | isDigit h1 && isDigit h2 && isDigit m1 && isDigit m2 = ['-',h1,h2,':',m1,m2]-fixTZ (c:s) = c:fixTZ s instance PGType "timestamp with time zone" where pgBinaryColumn = binColDatetime
postgresql-typed.cabal view
@@ -1,22 +1,25 @@ Name: postgresql-typed-Version: 0.4.4+Version: 0.4.5 Cabal-Version: >= 1.8 License: BSD3 License-File: COPYING-Copyright: 2010-2013 Chris Forno, 2014-2015 Dylan Simon+Copyright: 2010-2013 Chris Forno, 2014-2016 Dylan Simon Author: Dylan Simon Maintainer: Dylan Simon <dylan-pgtyped@dylex.net>-Stability: beta+Stability: provisional Bug-Reports: https://github.com/dylex/postgresql-typed/issues Homepage: https://github.com/dylex/postgresql-typed Category: Database-Synopsis: A PostgreSQL access library with compile-time SQL type inference+Synopsis: A PostgreSQL library with compile-time SQL type inference and optional HDBC backend Description: Automatically type-check SQL statements at compile time. Uses Template Haskell and the raw PostgreSQL protocol to describe SQL statements at compile time and provide appropriate type marshalling for both parameters and results. Allows not only syntax verification of your SQL but also full type safety between your SQL and Haskell. Supports many built-in PostgreSQL types already, including arrays and ranges, and can be easily extended in user code to support any other types.+ .+ Also includes an optional HDBC backend that, since it uses the raw PostgreSQL protocol, may be more efficient than the normal libpq backend in some cases (though provides no more type safety than HDBC-postgresql when used without templates).+ . Originally based on Chris Forno's templatepg library.-Tested-With: GHC == 7.8.4, GHC == 7.10.2+Tested-With: GHC == 7.10.3, GHC == 8.0.1 Build-Type: Simple source-repository head@@ -47,9 +50,12 @@ Description: Support decoding json via aeson. Default: True +Flag HDBC+ Description: Provide an HDBC driver backend using the raw PostgreSQL protocol.+ Library Build-Depends:- base >= 4.7 && < 5,+ base >= 4.8 && < 5, array, binary, containers,@@ -73,8 +79,10 @@ Database.PostgreSQL.Typed.Inet Database.PostgreSQL.Typed.Dynamic Database.PostgreSQL.Typed.TemplatePG+ Database.PostgreSQL.Typed.SQLToken+ Database.PostgreSQL.Typed.ErrCodes Other-Modules:- Database.PostgreSQL.Typed.Internal+ Paths_postgresql_typed GHC-Options: -Wall if flag(md5) Build-Depends: cryptonite >= 0.5, memory >= 0.5@@ -95,13 +103,25 @@ if flag(aeson) Build-Depends: aeson >= 0.7 CPP-options: -DUSE_AESON+ if flag(HDBC)+ Build-Depends: HDBC >= 2.2+ Exposed-Modules:+ Database.PostgreSQL.Typed.HDBC test-suite test- build-depends: base, network, time, bytestring, postgresql-typed, QuickCheck type: exitcode-stdio-1.0+ hs-source-dirs: test main-is: Main.hs Other-Modules: Connect- buildable: True- hs-source-dirs: test Extensions: TemplateHaskell, QuasiQuotes+ build-depends: base, network, time, bytestring, postgresql-typed, QuickCheck GHC-Options: -Wall++test-suite hdbc+ type: exitcode-stdio-1.0+ hs-source-dirs: test/hdbc, test+ main-is: runtests.hs+ if flag(HDBC)+ build-depends: base, network, time, containers, convertible, postgresql-typed, HDBC, HUnit+ else+ buildable: False
test/Main.hs view
@@ -1,9 +1,11 @@ {-# LANGUAGE OverloadedStrings, FlexibleInstances, MultiParamTypeClasses, DataKinds, DeriveDataTypeable #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} -- {-# OPTIONS_GHC -ddump-splices #-} module Main (main) where import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BSC+import Data.Char (isDigit) import Data.Int (Int32) import qualified Data.Time as Time import System.Exit (exitSuccess, exitFailure)@@ -16,6 +18,7 @@ import qualified Database.PostgreSQL.Typed.Range as Range import Database.PostgreSQL.Typed.Enum import Database.PostgreSQL.Typed.Inet+import Database.PostgreSQL.Typed.SQLToken import Connect @@ -58,6 +61,14 @@ then PGInet6 <$> Q.arbitrary <*> ((`mod` 129) <$> Q.arbitrary) else PGInet <$> Q.arbitrary <*> ((`mod` 33) <$> Q.arbitrary) +instance Q.Arbitrary SQLToken where+ arbitrary = Q.oneof+ [ SQLToken <$> Q.arbitrary+ , SQLParam <$> Q.arbitrary+ , SQLExpr <$> Q.arbitrary+ , SQLQMark <$> Q.arbitrary+ ]+ newtype Str = Str { strString :: [Char] } deriving (Eq, Show) strByte :: Str -> BS.ByteString strByte = BSC.pack . strString@@ -94,11 +105,36 @@ , a Q.=== a' ] +tokenProp :: String -> Q.Property+tokenProp s =+ not (has0 s) Q.==> s Q.=== show (sqlTokens s) where+ has0 ('$':'0':c:_) | isDigit c = True+ has0 (_:r) = has0 r+ has0 [] = False+ main :: IO () main = do c <- pgConnect db - r <- Q.quickCheckResult $ selectProp c+ r <- Q.quickCheckResult+ $ selectProp c+ Q..&&. tokenProp+ Q..&&. [pgSQL|#abc ${3.14::Float} def $f$ $$ ${1} $f$${2::Int32}|] Q.=== "abc 3.14::real def $f$ $$ ${1} $f$2::integer"+ Q..&&. pgEnumValues Q.=== [(MyEnum_abc, "abc"), (MyEnum_DEF, "DEF"), (MyEnum_XX_ye, "XX_ye")]+ Q..&&. Q.conjoin (map (\(s, t) -> sqlTokens s Q.=== t)+ [ ("",+ [])+ , ( "SELECT a from b WHERE c = ?"+ , ["SELECT a from b WHERE c = ", SQLQMark False])+ , ( "INSERT INTO foo VALUES (?,?)"+ , ["INSERT INTO foo VALUES (", SQLQMark False, ",", SQLQMark False, ")"])+ , ( "INSERT INTO foo VALUES ('?','''?')"+ , ["INSERT INTO foo VALUES ('?','''?')"])+ , ( "-- really?\n-- yes'?\nINSERT INTO ? VALUES ('', ?, \"?asd\", e'?\\'?', '?''?', /* foo? */ /* foo /* bar */ ? */ ?)"+ , ["-- really?\n-- yes'?\nINSERT INTO ", SQLQMark False, " VALUES ('', ", SQLQMark False, ", \"?asd\", e'?\\'?', '?''?', /* foo? */ /* foo /* bar */ ? */ ", SQLQMark False, ")"])+ , ( "some ${things? {don't}} change$1 $1\\?"+ , ["some ", SQLExpr "things? {don't}", " change$1 ", SQLParam 1, SQLQMark True])+ ]) assert $ isSuccess r ["box"] <- simple c 603@@ -107,10 +143,6 @@ ["box"] <- preparedApply c 603 [Just "line"] <- prepared c 628 "line" ["line"] <- preparedApply c 628-- assert $ [pgSQL|#abc${3.14 :: Float}def|] == "abc3.14::realdef"-- assert $ pgEnumValues == [(MyEnum_abc, "abc"), (MyEnum_DEF, "DEF"), (MyEnum_XX_ye, "XX_ye")] pgDisconnect c exitSuccess
+ test/hdbc/runtests.hs view
@@ -0,0 +1,16 @@+{- arch-tag: Test runner+-}++module Main where ++import Test.HUnit+import System.Exit+import Tests+import TestUtils++main = do+ printDBInfo+ r <- runTestTT tests+ if errors r == 0 && failures r == 0+ then exitSuccess+ else exitFailure