package net.sourceforge.mayfly; import net.sourceforge.mayfly.parser.Location; /** * When providing exceptions via Mayfly-specific methods, * mayfly will generally throw them as MayflyException. * This is a RuntimeException. * If you prefer checked exceptions, call {@link #asSqlException()}. * * @internal * For errors which we don't think will * make it out of mayfly itself, we can use this exception, * {@link MayflyInternalException}, * RuntimeException, IllegalArgumentException, etc. * * Otherwise, MayflyException turns into SQLException. */ public class MayflyException extends RuntimeException { private final MayflySqlException sqlException; /** * @internal * We keep track of where the error occurred. It, of * course, is available to Java code which explicitly * checks for {@link MayflySqlException}. But should * it be provided in another way as well? * Maybe the start line number * (not columns or end line number) in the message? * Or put it in the message * only if it is not one (or only if the input is * more than one line)? * It isn't clear how to address both the desire * to be informative, but also the desire to * avoid clutter in the (many) cases in which the * line number won't be helpful. */ protected final Location location; public MayflyException(String message) { this(message, Location.UNKNOWN); } public MayflyException(String message, Location location) { super(message); this.location = location; sqlException = new MayflySqlException(this); } public MayflyException(String message, Throwable cause) { super(message, cause); this.location = Location.UNKNOWN; sqlException = new MayflySqlException(this); } public MayflyException(Throwable cause) { super(cause); this.location = Location.UNKNOWN; sqlException = new MayflySqlException(this); } /** * Provide an exception which is similar to this one, * but which is a checked exception. This * method and {@link MayflySqlException#asRuntimeException()} * can go back and forth between runtime and checked * exceptions without wrapping. */ public MayflySqlException asSqlException() { return sqlException; } public Location location() { return location; } /** * Starting line number of the SQL which caused the problem, * or -1 if the location is not known. * An unknown location reflects a missing feature in Mayfly; * our eventual intention is to provide a location with all * exceptions. */ public int startLineNumber() { return location.startLineNumber; } /** * The column of the start of the text being * flagged. This is 1-based. For example, * if the whole line is "foo bar baz" and * the error is on "bar", this method will * return 5 and {@link #endColumn()} will * return 8. */ public int startColumn() { return location.startColumn; } /** * Ending line number of the SQL which caused the problem. * A value of -1 indicates that the end location is not * known. It is possible for the start location to be * known and the end location not to be known, or vice * versa. */ public int endLineNumber() { return location.endLineNumber; } /** * Ending column of the SQL which caused the problem. * For example, if the input SQL was " x " and the * text "x" was the problem, the start column would * be 2 and the end column would be 3. */ public int endColumn() { return location.endColumn; } /** * The SQL command in which there was a problem, or null * if not known. */ public String failingCommand() { return location.command; } }