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	"2200H": "sequence_generator_limit_exceeded",
157	"22026": "string_data_length_mismatch",
158	"22001": "string_data_right_truncation",
159	"22011": "substring_error",
160	"22027": "trim_error",
161	"22024": "unterminated_c_string",
162	"2200F": "zero_length_character_string",
163	"22P01": "floating_point_exception",
164	"22P02": "invalid_text_representation",
165	"22P03": "invalid_binary_representation",
166	"22P04": "bad_copy_file_format",
167	"22P05": "untranslatable_character",
168	"2200L": "not_an_xml_document",
169	"2200M": "invalid_xml_document",
170	"2200N": "invalid_xml_content",
171	"2200S": "invalid_xml_comment",
172	"2200T": "invalid_xml_processing_instruction",
173	// Class 23 - Integrity Constraint Violation
174	"23000": "integrity_constraint_violation",
175	"23001": "restrict_violation",
176	"23502": "not_null_violation",
177	"23503": "foreign_key_violation",
178	"23505": "unique_violation",
179	"23514": "check_violation",
180	"23P01": "exclusion_violation",
181	// Class 24 - Invalid Cursor State
182	"24000": "invalid_cursor_state",
183	// Class 25 - Invalid Transaction State
184	"25000": "invalid_transaction_state",
185	"25001": "active_sql_transaction",
186	"25002": "branch_transaction_already_active",
187	"25008": "held_cursor_requires_same_isolation_level",
188	"25003": "inappropriate_access_mode_for_branch_transaction",
189	"25004": "inappropriate_isolation_level_for_branch_transaction",
190	"25005": "no_active_sql_transaction_for_branch_transaction",
191	"25006": "read_only_sql_transaction",
192	"25007": "schema_and_data_statement_mixing_not_supported",
193	"25P01": "no_active_sql_transaction",
194	"25P02": "in_failed_sql_transaction",
195	// Class 26 - Invalid SQL Statement Name
196	"26000": "invalid_sql_statement_name",
197	// Class 27 - Triggered Data Change Violation
198	"27000": "triggered_data_change_violation",
199	// Class 28 - Invalid Authorization Specification
200	"28000": "invalid_authorization_specification",
201	"28P01": "invalid_password",
202	// Class 2B - Dependent Privilege Descriptors Still Exist
203	"2B000": "dependent_privilege_descriptors_still_exist",
204	"2BP01": "dependent_objects_still_exist",
205	// Class 2D - Invalid Transaction Termination
206	"2D000": "invalid_transaction_termination",
207	// Class 2F - SQL Routine Exception
208	"2F000": "sql_routine_exception",
209	"2F005": "function_executed_no_return_statement",
210	"2F002": "modifying_sql_data_not_permitted",
211	"2F003": "prohibited_sql_statement_attempted",
212	"2F004": "reading_sql_data_not_permitted",
213	// Class 34 - Invalid Cursor Name
214	"34000": "invalid_cursor_name",
215	// Class 38 - External Routine Exception
216	"38000": "external_routine_exception",
217	"38001": "containing_sql_not_permitted",
218	"38002": "modifying_sql_data_not_permitted",
219	"38003": "prohibited_sql_statement_attempted",
220	"38004": "reading_sql_data_not_permitted",
221	// Class 39 - External Routine Invocation Exception
222	"39000": "external_routine_invocation_exception",
223	"39001": "invalid_sqlstate_returned",
224	"39004": "null_value_not_allowed",
225	"39P01": "trigger_protocol_violated",
226	"39P02": "srf_protocol_violated",
227	// Class 3B - Savepoint Exception
228	"3B000": "savepoint_exception",
229	"3B001": "invalid_savepoint_specification",
230	// Class 3D - Invalid Catalog Name
231	"3D000": "invalid_catalog_name",
232	// Class 3F - Invalid Schema Name
233	"3F000": "invalid_schema_name",
234	// Class 40 - Transaction Rollback
235	"40000": "transaction_rollback",
236	"40002": "transaction_integrity_constraint_violation",
237	"40001": "serialization_failure",
238	"40003": "statement_completion_unknown",
239	"40P01": "deadlock_detected",
240	// Class 42 - Syntax Error or Access Rule Violation
241	"42000": "syntax_error_or_access_rule_violation",
242	"42601": "syntax_error",
243	"42501": "insufficient_privilege",
244	"42846": "cannot_coerce",
245	"42803": "grouping_error",
246	"42P20": "windowing_error",
247	"42P19": "invalid_recursion",
248	"42830": "invalid_foreign_key",
249	"42602": "invalid_name",
250	"42622": "name_too_long",
251	"42939": "reserved_name",
252	"42804": "datatype_mismatch",
253	"42P18": "indeterminate_datatype",
254	"42P21": "collation_mismatch",
255	"42P22": "indeterminate_collation",
256	"42809": "wrong_object_type",
257	"42703": "undefined_column",
258	"42883": "undefined_function",
259	"42P01": "undefined_table",
260	"42P02": "undefined_parameter",
261	"42704": "undefined_object",
262	"42701": "duplicate_column",
263	"42P03": "duplicate_cursor",
264	"42P04": "duplicate_database",
265	"42723": "duplicate_function",
266	"42P05": "duplicate_prepared_statement",
267	"42P06": "duplicate_schema",
268	"42P07": "duplicate_table",
269	"42712": "duplicate_alias",
270	"42710": "duplicate_object",
271	"42702": "ambiguous_column",
272	"42725": "ambiguous_function",
273	"42P08": "ambiguous_parameter",
274	"42P09": "ambiguous_alias",
275	"42P10": "invalid_column_reference",
276	"42611": "invalid_column_definition",
277	"42P11": "invalid_cursor_definition",
278	"42P12": "invalid_database_definition",
279	"42P13": "invalid_function_definition",
280	"42P14": "invalid_prepared_statement_definition",
281	"42P15": "invalid_schema_definition",
282	"42P16": "invalid_table_definition",
283	"42P17": "invalid_object_definition",
284	// Class 44 - WITH CHECK OPTION Violation
285	"44000": "with_check_option_violation",
286	// Class 53 - Insufficient Resources
287	"53000": "insufficient_resources",
288	"53100": "disk_full",
289	"53200": "out_of_memory",
290	"53300": "too_many_connections",
291	"53400": "configuration_limit_exceeded",
292	// Class 54 - Program Limit Exceeded
293	"54000": "program_limit_exceeded",
294	"54001": "statement_too_complex",
295	"54011": "too_many_columns",
296	"54023": "too_many_arguments",
297	// Class 55 - Object Not In Prerequisite State
298	"55000": "object_not_in_prerequisite_state",
299	"55006": "object_in_use",
300	"55P02": "cant_change_runtime_param",
301	"55P03": "lock_not_available",
302	// Class 57 - Operator Intervention
303	"57000": "operator_intervention",
304	"57014": "query_canceled",
305	"57P01": "admin_shutdown",
306	"57P02": "crash_shutdown",
307	"57P03": "cannot_connect_now",
308	"57P04": "database_dropped",
309	// Class 58 - System Error (errors external to PostgreSQL itself)
310	"58000": "system_error",
311	"58030": "io_error",
312	"58P01": "undefined_file",
313	"58P02": "duplicate_file",
314	// Class F0 - Configuration File Error
315	"F0000": "config_file_error",
316	"F0001": "lock_file_exists",
317	// Class HV - Foreign Data Wrapper Error (SQL/MED)
318	"HV000": "fdw_error",
319	"HV005": "fdw_column_name_not_found",
320	"HV002": "fdw_dynamic_parameter_value_needed",
321	"HV010": "fdw_function_sequence_error",
322	"HV021": "fdw_inconsistent_descriptor_information",
323	"HV024": "fdw_invalid_attribute_value",
324	"HV007": "fdw_invalid_column_name",
325	"HV008": "fdw_invalid_column_number",
326	"HV004": "fdw_invalid_data_type",
327	"HV006": "fdw_invalid_data_type_descriptors",
328	"HV091": "fdw_invalid_descriptor_field_identifier",
329	"HV00B": "fdw_invalid_handle",
330	"HV00C": "fdw_invalid_option_index",
331	"HV00D": "fdw_invalid_option_name",
332	"HV090": "fdw_invalid_string_length_or_buffer_length",
333	"HV00A": "fdw_invalid_string_format",
334	"HV009": "fdw_invalid_use_of_null_pointer",
335	"HV014": "fdw_too_many_handles",
336	"HV001": "fdw_out_of_memory",
337	"HV00P": "fdw_no_schemas",
338	"HV00J": "fdw_option_name_not_found",
339	"HV00K": "fdw_reply_handle",
340	"HV00Q": "fdw_schema_not_found",
341	"HV00R": "fdw_table_not_found",
342	"HV00L": "fdw_unable_to_create_execution",
343	"HV00M": "fdw_unable_to_create_reply",
344	"HV00N": "fdw_unable_to_establish_connection",
345	// Class P0 - PL/pgSQL Error
346	"P0000": "plpgsql_error",
347	"P0001": "raise_exception",
348	"P0002": "no_data_found",
349	"P0003": "too_many_rows",
350	// Class XX - Internal Error
351	"XX000": "internal_error",
352	"XX001": "data_corrupted",
353	"XX002": "index_corrupted",
354}
355
356func parseError(r *readBuf) *Error {
357	err := new(Error)
358	for t := r.byte(); t != 0; t = r.byte() {
359		msg := r.string()
360		switch t {
361		case 'S':
362			err.Severity = msg
363		case 'C':
364			err.Code = ErrorCode(msg)
365		case 'M':
366			err.Message = msg
367		case 'D':
368			err.Detail = msg
369		case 'H':
370			err.Hint = msg
371		case 'P':
372			err.Position = msg
373		case 'p':
374			err.InternalPosition = msg
375		case 'q':
376			err.InternalQuery = msg
377		case 'W':
378			err.Where = msg
379		case 's':
380			err.Schema = msg
381		case 't':
382			err.Table = msg
383		case 'c':
384			err.Column = msg
385		case 'd':
386			err.DataTypeName = msg
387		case 'n':
388			err.Constraint = msg
389		case 'F':
390			err.File = msg
391		case 'L':
392			err.Line = msg
393		case 'R':
394			err.Routine = msg
395		}
396	}
397	return err
398}
399
400// Fatal returns true if the Error Severity is fatal.
401func (err *Error) Fatal() bool {
402	return err.Severity == Efatal
403}
404
405// Get implements the legacy PGError interface. New code should use the fields
406// of the Error struct directly.
407func (err *Error) Get(k byte) (v string) {
408	switch k {
409	case 'S':
410		return err.Severity
411	case 'C':
412		return string(err.Code)
413	case 'M':
414		return err.Message
415	case 'D':
416		return err.Detail
417	case 'H':
418		return err.Hint
419	case 'P':
420		return err.Position
421	case 'p':
422		return err.InternalPosition
423	case 'q':
424		return err.InternalQuery
425	case 'W':
426		return err.Where
427	case 's':
428		return err.Schema
429	case 't':
430		return err.Table
431	case 'c':
432		return err.Column
433	case 'd':
434		return err.DataTypeName
435	case 'n':
436		return err.Constraint
437	case 'F':
438		return err.File
439	case 'L':
440		return err.Line
441	case 'R':
442		return err.Routine
443	}
444	return ""
445}
446
447func (err Error) Error() string {
448	return "pq: " + err.Message
449}
450
451// PGError is an interface used by previous versions of pq. It is provided
452// only to support legacy code. New code should use the Error type.
453type PGError interface {
454	Error() string
455	Fatal() bool
456	Get(k byte) (v string)
457}
458
459func errorf(s string, args ...interface{}) {
460	panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
461}
462
463// TODO(ainar-g) Rename to errorf after removing panics.
464func fmterrorf(s string, args ...interface{}) error {
465	return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))
466}
467
468func errRecoverNoErrBadConn(err *error) {
469	e := recover()
470	if e == nil {
471		// Do nothing
472		return
473	}
474	var ok bool
475	*err, ok = e.(error)
476	if !ok {
477		*err = fmt.Errorf("pq: unexpected error: %#v", e)
478	}
479}
480
481func (cn *conn) errRecover(err *error) {
482	e := recover()
483	switch v := e.(type) {
484	case nil:
485		// Do nothing
486	case runtime.Error:
487		cn.bad = true
488		panic(v)
489	case *Error:
490		if v.Fatal() {
491			*err = driver.ErrBadConn
492		} else {
493			*err = v
494		}
495	case *net.OpError:
496		cn.bad = true
497		*err = v
498	case error:
499		if v == io.EOF || v.(error).Error() == "remote error: handshake failure" {
500			*err = driver.ErrBadConn
501		} else {
502			*err = v
503		}
504
505	default:
506		cn.bad = true
507		panic(fmt.Sprintf("unknown error: %#v", e))
508	}
509
510	// Any time we return ErrBadConn, we need to remember it since *Tx doesn't
511	// mark the connection bad in database/sql.
512	if *err == driver.ErrBadConn {
513		cn.bad = true
514	}
515}
516