/* * Copyright (c) 2004, PostgreSQL Global Development Group * See the LICENSE file in the project root for more information. */ package com.amazon.redshift.util; import com.amazon.redshift.core.EncodingPredictor; import com.amazon.redshift.logger.RedshiftLogger; import java.io.Serializable; import java.util.HashMap; import java.util.Map; public class ServerErrorMessage implements Serializable { private static final Character SEVERITY = 'S'; private static final Character MESSAGE = 'M'; private static final Character DETAIL = 'D'; private static final Character HINT = 'H'; private static final Character POSITION = 'P'; private static final Character WHERE = 'W'; private static final Character FILE = 'F'; private static final Character LINE = 'L'; private static final Character ROUTINE = 'R'; private static final Character SQLSTATE = 'C'; private static final Character INTERNAL_POSITION = 'p'; private static final Character INTERNAL_QUERY = 'q'; private static final Character SCHEMA = 's'; private static final Character TABLE = 't'; private static final Character COLUMN = 'c'; private static final Character DATATYPE = 'd'; private static final Character CONSTRAINT = 'n'; private final Map mesgParts = new HashMap(); public ServerErrorMessage(EncodingPredictor.DecodeResult serverError) { this(serverError.result); if (serverError.encoding != null) { mesgParts.put(MESSAGE, mesgParts.get(MESSAGE) + GT.tr(" (pgjdbc: autodetected server-encoding to be {0}, if the message is not readable, please check database logs and/or host, port, dbname, user, password, pg_hba.conf)", serverError.encoding) ); } } public ServerErrorMessage(String serverError) { char[] chars = serverError.toCharArray(); int pos = 0; int length = chars.length; while (pos < length) { char mesgType = chars[pos]; if (mesgType != '\0') { pos++; int startString = pos; // order here is important position must be checked before accessing the array while (pos < length && chars[pos] != '\0') { pos++; } String mesgPart = new String(chars, startString, pos - startString); mesgParts.put(mesgType, mesgPart); } pos++; } } public String getSQLState() { return mesgParts.get(SQLSTATE); } public String getMessage() { return mesgParts.get(MESSAGE); } public String getSeverity() { return mesgParts.get(SEVERITY); } public String getDetail() { return mesgParts.get(DETAIL); } public String getHint() { return mesgParts.get(HINT); } public int getPosition() { return getIntegerPart(POSITION); } public String getWhere() { return mesgParts.get(WHERE); } public String getSchema() { return mesgParts.get(SCHEMA); } public String getTable() { return mesgParts.get(TABLE); } public String getColumn() { return mesgParts.get(COLUMN); } public String getDatatype() { return mesgParts.get(DATATYPE); } public String getConstraint() { return mesgParts.get(CONSTRAINT); } public String getFile() { return mesgParts.get(FILE); } public int getLine() { return getIntegerPart(LINE); } public String getRoutine() { return mesgParts.get(ROUTINE); } public String getInternalQuery() { return mesgParts.get(INTERNAL_QUERY); } public int getInternalPosition() { return getIntegerPart(INTERNAL_POSITION); } private int getIntegerPart(Character c) { String s = mesgParts.get(c); if (s == null) { return 0; } return Integer.parseInt(s); } String getNonSensitiveErrorMessage() { StringBuilder totalMessage = new StringBuilder(); String message = mesgParts.get(SEVERITY); if (message != null) { totalMessage.append(message).append(": "); } message = mesgParts.get(MESSAGE); if (message != null) { totalMessage.append(message); } return totalMessage.toString(); } String getExternalErrorMessage() { // Now construct the message from what the server sent // The general format is: // SEVERITY: Message \n // Detail: \n // Hint: \n // Position: \n // Where: \n // StringBuilder totalMessage = new StringBuilder(); String message = mesgParts.get(SEVERITY); if (message != null) { totalMessage.append(message).append(": "); } message = mesgParts.get(MESSAGE); if (message != null) { totalMessage.append(message); } message = mesgParts.get(DETAIL); if (message != null) { totalMessage.append("\n ").append(GT.tr("Detail: {0}", message)); } message = mesgParts.get(HINT); if (message != null) { totalMessage.append("\n ").append(GT.tr("Hint: {0}", message)); } message = mesgParts.get(POSITION); if (message != null) { totalMessage.append("\n ").append(GT.tr("Position: {0}", message)); } message = mesgParts.get(WHERE); if (message != null) { totalMessage.append("\n ").append(GT.tr("Where: {0}", message)); } return totalMessage.toString(); } public String toString() { // Now construct the message from what the server sent // The general format is: // SEVERITY: Message \n // Detail: \n // Hint: \n // Position: \n // Where: \n // Internal Query: \n // Internal Position: \n // Location: File:Line:Routine \n // SQLState: \n // // Normally only the message and detail is included. // If INFO level logging is enabled then detail, hint, position and where are // included. If DEBUG level logging is enabled then all information // is included. StringBuilder totalMessage = new StringBuilder(); String message = mesgParts.get(SEVERITY); if (message != null) { totalMessage.append(message).append(": "); } message = mesgParts.get(MESSAGE); if (message != null) { totalMessage.append(message); } message = mesgParts.get(DETAIL); if (message != null) { totalMessage.append("\n ").append(GT.tr("Detail: {0}", message)); } message = mesgParts.get(HINT); if (message != null) { totalMessage.append("\n ").append(GT.tr("Hint: {0}", message)); } message = mesgParts.get(POSITION); if (message != null) { totalMessage.append("\n ").append(GT.tr("Position: {0}", message)); } message = mesgParts.get(WHERE); if (message != null) { totalMessage.append("\n ").append(GT.tr("Where: {0}", message)); } if (RedshiftLogger.isEnable()) { String internalQuery = mesgParts.get(INTERNAL_QUERY); if (internalQuery != null) { totalMessage.append("\n ").append(GT.tr("Internal Query: {0}", internalQuery)); } String internalPosition = mesgParts.get(INTERNAL_POSITION); if (internalPosition != null) { totalMessage.append("\n ").append(GT.tr("Internal Position: {0}", internalPosition)); } String file = mesgParts.get(FILE); String line = mesgParts.get(LINE); String routine = mesgParts.get(ROUTINE); if (file != null || line != null || routine != null) { totalMessage.append("\n ").append(GT.tr("Location: File: {0}, Routine: {1}, Line: {2}", file, routine, line)); } message = mesgParts.get(SQLSTATE); if (message != null) { totalMessage.append("\n ").append(GT.tr("Server SQLState: {0}", message)); } } return totalMessage.toString(); } }