1package pq
2
3import (
4	"database/sql/driver"
5	"fmt"
6	"io"
7	"net"
8	"runtime"
9)
10
11// Error severities
12const (
13	Efatal   = "FATAL"
14	Epanic   = "PANIC"
15	Ewarning = "WARNING"
16	Enotice  = "NOTICE"
17	Edebug   = "DEBUG"
18	Einfo    = "INFO"
19	Elog     = "LOG"
20)
21
22// Error represents an error communicating with the server.
23//
24// See http://www.postgresql.org/docs/current/static/protocol-error-fields.html for details of the fields
25type Error struct {
26	Severity         string
27	Code             ErrorCode
28	Message          string
29	Detail           string
30	Hint             string
31	Position         string
32	InternalPosition string
33	InternalQuery    string
34	Where            string
35	Schema           string
36	Table            string
37	Column           string
38	DataTypeName     string
39	Constraint       string
40	File             string
41	Line             string
42	Routine          string
43}
44
45// ErrorCode is a five-character error code.
46type ErrorCode string
47
48// Name returns a more human friendly rendering of the error code, namely the
49// "condition name".
50//
51// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for
52// details.
53func (ec ErrorCode) Name() string {
54	return errorCodeNames[ec]
55}
56
57// ErrorClass is only the class part of an error code.
58type ErrorClass string
59
60// Name returns the condition name of an error class.  It is equivalent to the
61// condition name of the "standard" error code (i.e. the one having the last
62// three characters "000").
63func (ec ErrorClass) Name() string {
64	return errorCodeNames[ErrorCode(ec+"000")]
65}
66
67// Class returns the error class, e.g. "28".
68//
69// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for
70// details.
71func (ec ErrorCode) Class() ErrorClass {
72	return ErrorClass(ec[0:2])
73}
74
75// errorCodeNames is a mapping between the five-character error codes and the
76// human readable "condition names". It is derived from the list at
77// http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html
78var errorCodeNames = map[ErrorCode]string{
79	// Class 00 - Successful Completion
80	"00000": "successful_completion",
81	// Class 01 - Warning
82	"01000": "warning",
83	"0100C": "dynamic_result_sets_returned",
84	"01008": "implicit_zero_bit_padding",
85	"01003": "null_value_eliminated_in_set_function",
86	"01007": "privilege_not_granted",
87	"01006": "privilege_not_revoked",
88	"01004": "string_data_right_truncation",
89	"01P01": "deprecated_feature",
90	// Class 02 - No Data (this is also a warning class per the SQL standard)
91	"02000": "no_data",
92	"02001": "no_additional_dynamic_result_sets_returned",
93	// Class 03 - SQL Statement Not Yet Complete
94	"03000": "sql_statement_not_yet_complete",
95	// Class 08 - Connection Exception
96	"08000": "connection_exception",
97	"08003": "connection_does_not_exist",
98	"08006": "connection_failure",
99	"08001": "sqlclient_unable_to_establish_sqlconnection",
100	"08004": "sqlserver_rejected_establishment_of_sqlconnection",
101	"08007": "transaction_resolution_unknown",
102	"08P01": "protocol_violation",
103	// Class 09 - Triggered Action Exception
104	"09000": "triggered_action_exception",
105	// Class 0A - Feature Not Supported
106	"0A000": "feature_not_supported",
107	// Class 0B - Invalid Transaction Initiation
108	"0B000": "invalid_transaction_initiation",
109	// Class 0F - Locator Exception
110	"0F000": "locator_exception",
111	"0F001": "invalid_locator_specification",
112	// Class 0L - Invalid Grantor
113	"0L000": "invalid_grantor",
114	"0LP01": "invalid_grant_operation",
115	// Class 0P - Invalid Role Specification
116	"0P000": "invalid_role_specification",
117	// Class 0Z - Diagnostics Exception
118	"0Z000": "diagnostics_exception",
119	"0Z002": "stacked_diagnostics_accessed_without_active_handler",
120	// Class 20 - Case Not Found
121	"20000": "case_not_found",
122	// Class 21 - Cardinality Violation
123	"21000": "cardinality_violation",
124	// Class 22 - Data Exception
125	"22000": "data_exception",
126	"2202E": "array_subscript_error",
127	"22021": "character_not_in_repertoire",
128	"22008": "datetime_field_overflow",
129	"22012": "division_by_zero",
130	"22005": "error_in_assignment",
131	"2200B": "escape_character_conflict",
132	"22022": "indicator_overflow",
133	"22015": "interval_field_overflow",
134	"2201E": "invalid_argument_for_logarithm",
135	"22014": "invalid_argument_for_ntile_function",
136	"22016": "invalid_argument_for_nth_value_function",
137	"2201F": "invalid_argument_for_power_function",
138	"2201G": "invalid_argument_for_width_bucket_function",
139	"22018": "invalid_character_value_for_cast",
140	"22007": "invalid_datetime_format",
141	"22019": "invalid_escape_character",
142	"2200D": "invalid_escape_octet",
143	"22025": "invalid_escape_sequence",
144	"22P06": "nonstandard_use_of_escape_character",
145	"22010": "invalid_indicator_parameter_value",
146	"22023": "invalid_parameter_value",
147	"2201B": "invalid_regular_expression",
148	"2201W": "invalid_row_count_in_limit_clause",
149	"2201X": "invalid_row_count_in_result_offset_clause",
150	"22009": "invalid_time_zone_displacement_value",
151	"2200C": "invalid_use_of_escape_character",
152	"2200G": "most_specific_type_mismatch",
153	"22004": "null_value_not_allowed",
154	"22002": "null_value_no_indicator_parameter",
155	"22003": "numeric_value_out_of_range",
156	"22026": "string_data_length_mismatch",
157	"22001": "string_data_right_truncation",
158	"22011": "substring_error",
159	"22027": "trim_error",
160	"22024": "unterminated_c_string",
161	"2200F": "zero_length_character_string",
162	"22P01": "floating_point_exception",
163	"22P02": "invalid_text_representation",
164	"22P03": "invalid_binary_representation",
165	"22P04": "bad_copy_file_format",
166	"22P05": "untranslatable_character",
167	"2200L": "not_an_xml_document",
168	"2200M": "invalid_xml_document",
169	"2200N": "invalid_xml_content",
170	"2200S": "invalid_xml_comment",
171	"2200T": "invalid_xml_processing_instruction",
172	// Class 23 - Integrity Constraint Violation
173	"23000": "integrity_constraint_violation",
174	"23001": "restrict_violation",
175	"23502": "not_null_violation",
176	"23503": "foreign_key_violation",
177	"23505": "unique_violation",
178	"23514": "check_violation",
179	"23P01": "exclusion_violation",
180	// Class 24 - Invalid Cursor State
181	"24000": "invalid_cursor_state",
182	// Class 25 - Invalid Transaction State
183	"25000": "invalid_transaction_state",
184	"25001": "active_sql_transaction",
185	"25002": "branch_transaction_already_active",
186	"25008": "held_cursor_requires_same_isolation_level",
187	"25003": "inappropriate_access_mode_for_branch_transaction",
188	"25004": "inappropriate_isolation_level_for_branch_transaction",
189	"25005": "no_active_sql_transaction_for_branch_transaction",
190	"25006": "read_only_sql_transaction",
191	"25007": "schema_and_data_statement_mixing_not_supported",
192	"25P01": "no_active_sql_transaction",
193	"25P02": "in_failed_sql_transaction",
194	// Class 26 - Invalid SQL Statement Name
195	"26000": "invalid_sql_statement_name",
196	// Class 27 - Triggered Data Change Violation
197	"27000": "triggered_data_change_violation",
198	// Class 28 - Invalid Authorization Specification
199	"28000": "invalid_authorization_specification",
200	"28P01": "invalid_password",
201	// Class 2B - Dependent Privilege Descriptors Still Exist
202	"2B000": "dependent_privilege_descriptors_still_exist",
203	"2BP01": "dependent_objects_still_exist",
204	// Class 2D - Invalid Transaction Termination
205	"2D000": "invalid_transaction_termination",
206	// Class 2F - SQL Routine Exception
207	"2F000": "sql_routine_exception",
208	"2F005": "function_executed_no_return_statement",
209	"2F002": "modifying_sql_data_not_permitted",
210	"2F003": "prohibited_sql_statement_attempted",
211	"2F004": "reading_sql_data_not_permitted",
212	// Class 34 - Invalid Cursor Name
213	"34000": "invalid_cursor_name",
214	// Class 38 - External Routine Exception
215	"38000": "external_routine_exception",
216	"38001": "containing_sql_not_permitted",
217	"38002": "modifying_sql_data_not_permitted",
218	"38003": "prohibited_sql_statement_attempted",
219	"38004": "reading_sql_data_not_permitted",
220	// Class 39 - External Routine Invocation Exception
221	"39000": "external_routine_invocation_exception",
222	"39001": "invalid_sqlstate_returned",
223	"39004": "null_value_not_allowed",
224	"39P01": "trigger_protocol_violated",
225	"39P02": "srf_protocol_violated",
226	// Class 3B - Savepoint Exception
227	"3B000": "savepoint_exception",
228	"3B001": "invalid_savepoint_specification",
229	// Class 3D - Invalid Catalog Name
230	"3D000": "invalid_catalog_name",
231	// Class 3F - Invalid Schema Name
232	"3F000": "invalid_schema_name",
233	// Class 40 - Transaction Rollback
234	"40000": "transaction_rollback",
235	"40002": "transaction_integrity_constraint_violation",
236	"40001": "serialization_failure",
237	"40003": "statement_completion_unknown",
238	"40P01": "deadlock_detected",
239	// Class 42 - Syntax Error or Access Rule Violation
240	"42000": "syntax_error_or_access_rule_violation",
241	"42601": "syntax_error",
242	"42501": "insufficient_privilege",
243	"42846": "cannot_coerce",
244	"42803": "grouping_error",
245	"42P20": "windowing_error",
246	"42P19": "invalid_recursion",
247	"42830": "invalid_foreign_key",
248	"42602": "invalid_name",
249	"42622": "name_too_long",
250	"42939": "reserved_name",
251	"42804": "datatype_mismatch",
252	"42P18": "indeterminate_datatype",
253	"42P21": "collation_mismatch",
254	"42P22": "indeterminate_collation",
255	"42809": "wrong_object_type",
256	"42703": "undefined_column",
257	"42883": "undefined_function",
258	"42P01": "undefined_table",
259	"42P02": "undefined_parameter",
260	"42704": "undefined_object",
261	"42701": "duplicate_column",
262	"42P03": "duplicate_cursor",
263	"42P04": "duplicate_database",
264	"42723": "duplicate_function",
265	"42P05": "duplicate_prepared_statement",
266	"42P06": "duplicate_schema",
267	"42P07": "duplicate_table",
268	"42712": "duplicate_alias",
269	"42710": "duplicate_object",
270	"42702": "ambiguous_column",
271	"42725": "ambiguous_function",
272	"42P08": "ambiguous_parameter",
273	"42P09": "ambiguous_alias",
274	"42P10": "invalid_column_reference",
275	"42611": "invalid_column_definition",
276	"42P11": "invalid_cursor_definition",
277	"42P12": "invalid_database_definition",
278	"42P13": "invalid_function_definition",
279	"42P14": "invalid_prepared_statement_definition",
280	"42P15": "invalid_schema_definition",
281	"42P16": "invalid_table_definition",
282	"42P17": "invalid_object_definition",
283	// Class 44 - WITH CHECK OPTION Violation
284	"44000": "with_check_option_violation",
285	// Class 53 - Insufficient Resources
286	"53000": "insufficient_resources",
287	"53100": "disk_full",
288	"53200": "out_of_memory",
289	"53300": "too_many_connections",
290	"53400": "configuration_limit_exceeded",
291	// Class 54 - Program Limit Exceeded
292	"54000": "program_limit_exceeded",
293	"54001": "statement_too_complex",
294	"54011": "too_many_columns",
295	"54023": "too_many_arguments",
296	// Class 55 - Object Not In Prerequisite State
297	"55000": "object_not_in_prerequisite_state",
298	"55006": "object_in_use",
299	"55P02": "cant_change_runtime_param",
300	"55P03": "lock_not_available",
301	// Class 57 - Operator Intervention
302	"57000": "operator_intervention",
303	"57014": "query_canceled",
304	"57P01": "admin_shutdown",
305	"57P02": "crash_shutdown",
306	"57P03": "cannot_connect_now",
307	"57P04": "database_dropped",
308	// Class 58 - System Error (errors external to PostgreSQL itself)
309	"58000": "system_error",
310	"58030": "io_error",
311	"58P01": "undefined_file",
312	"58P02": "duplicate_file",
313	// Class F0 - Configuration File Error
314	"F0000": "config_file_error",
315	"F0001": "lock_file_exists",
316	// Class HV - Foreign Data Wrapper Error (SQL/MED)
317	"HV000": "fdw_error",
318	"HV005": "fdw_column_name_not_found",
319	"HV002": "fdw_dynamic_parameter_value_needed",
320	"HV010": "fdw_function_sequence_error",
321	"HV021": "fdw_inconsistent_descriptor_information",
322	"HV024": "fdw_invalid_attribute_value",
323	"HV007": "fdw_invalid_column_name",
324	"HV008": "fdw_invalid_column_number",
325	"HV004": "fdw_invalid_data_type",
326	"HV006": "fdw_invalid_data_type_descriptors",
327	"HV091": "fdw_invalid_descriptor_field_identifier",
328	"HV00B": "fdw_invalid_handle",
329	"HV00C": "fdw_invalid_option_index",
330	"HV00D": "fdw_invalid_option_name",
331	"HV090": "fdw_invalid_string_length_or_buffer_length",
332	"HV00A": "fdw_invalid_string_format",
333	"HV009": "fdw_invalid_use_of_null_pointer",
334	"HV014": "fdw_too_many_handles",
335	"HV001": "fdw_out_of_memory",
336	"HV00P": "fdw_no_schemas",
337	"HV00J": "fdw_option_name_not_found",
338	"HV00K": "fdw_reply_handle",
339	"HV00Q": "fdw_schema_not_found",
340	"HV00R": "fdw_table_not_found",
341	"HV00L": "fdw_unable_to_create_execution",
342	"HV00M": "fdw_unable_to_create_reply",
343	"HV00N": "fdw_unable_to_establish_connection",
344	// Class P0 - PL/pgSQL Error
345	"P0000": "plpgsql_error",
346	"P0001": "raise_exception",
347	"P0002": "no_data_found",
348	"P0003": "too_many_rows",
349	// Class XX - Internal Error
350	"XX000": "internal_error",
351	"XX001": "data_corrupted",
352	"XX002": "index_corrupted",
353}
354
355func parseError(r *readBuf) *Error {
356	err := new(Error)
357	for t := r.byte(); t != 0; t = r.byte() {
358		msg := r.string()
359		switch t {
360		case 'S':
361			err.Severity = msg
362		case 'C':
363			err.Code = ErrorCode(msg)
364		case 'M':
365			err.Message = msg
366		case 'D':
367			err.Detail = msg
368		case 'H':
369			err.Hint = msg
370		case 'P':
371			err.Position = msg
372		case 'p':
373			err.InternalPosition = msg
374		case 'q':
375			err.InternalQuery = msg
376		case 'W':
377			err.Where = msg
378		case 's':
379			err.Schema = msg
380		case 't':
381			err.Table = msg
382		case 'c':
383			err.Column = msg
384		case 'd':
385			err.DataTypeName = msg
386		case 'n':
387			err.Constraint = msg
388		case 'F':
389			err.File = msg
390		case 'L':
391			err.Line = msg
392		case 'R':
393			err.Routine = msg
394		}
395	}
396	return err
397}
398
399// Fatal returns true if the Error Severity is fatal.
400func (err *Error) Fatal() bool {
401	return err.Severity == Efatal
402}
403
404// Get implements the legacy PGError interface. New code should use the fields
405// of the Error struct directly.
406func (err *Error) Get(k byte) (v string) {
407	switch k {
408	case 'S':
409		return err.Severity
410	case 'C':
411		return string(err.Code)
412	case 'M':
413		return err.Message
414	case 'D':
415		return err.Detail
416	case 'H':
417		return err.Hint
418	case 'P':
419		return err.Position
420	case 'p':
421		return err.InternalPosition
422	case 'q':
423		return err.InternalQuery
424	case 'W':
425		return err.Where
426	case 's':
427		return err.Schema
428	case 't':
429		return err.Table
430	case 'c':
431		return err.Column
432	case 'd':
433		return err.DataTypeName
434	case 'n':
435		return err.Constraint
436	case 'F':
437		return err.File
438	case 'L':
439		return err.Line
440	case 'R':
441		return err.Routine
442	}
443	return ""
444}
445
446func (err Error) Error() string {
447	return "pq: " + err.Message
448}
449
450// PGError is an interface used by previous versions of pq. It is provided
451// only to support legacy code. New code should use the Error type.
452type PGError interface {
453	Error() string
454	Fatal() bool
455	Get(k byte) (v string)
456}
457
458func errorf(s string, args ...interface{}) {
459	panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
460}
461
462func errRecoverNoErrBadConn(err *error) {
463	e := recover()
464	if e == nil {
465		// Do nothing
466		return
467	}
468	var ok bool
469	*err, ok = e.(error)
470	if !ok {
471		*err = fmt.Errorf("pq: unexpected error: %#v", e)
472	}
473}
474
475func (c *conn) errRecover(err *error) {
476	e := recover()
477	switch v := e.(type) {
478	case nil:
479		// Do nothing
480	case runtime.Error:
481		c.bad = true
482		panic(v)
483	case *Error:
484		if v.Fatal() {
485			*err = driver.ErrBadConn
486		} else {
487			*err = v
488		}
489	case *net.OpError:
490		*err = driver.ErrBadConn
491	case error:
492		if v == io.EOF || v.(error).Error() == "remote error: handshake failure" {
493			*err = driver.ErrBadConn
494		} else {
495			*err = v
496		}
497
498	default:
499		c.bad = true
500		panic(fmt.Sprintf("unknown error: %#v", e))
501	}
502
503	// Any time we return ErrBadConn, we need to remember it since *Tx doesn't
504	// mark the connection bad in database/sql.
505	if *err == driver.ErrBadConn {
506		c.bad = true
507	}
508}
509