You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pig.apache.org by da...@apache.org on 2013/09/09 19:39:04 UTC

svn commit: r1521216 - in /pig/trunk: ./ src/org/apache/pig/ src/org/apache/pig/impl/ src/org/apache/pig/impl/logicalLayer/ src/org/apache/pig/parser/ src/org/apache/pig/tools/parameters/ src/org/apache/pig/tools/pigstats/ test/org/apache/pig/ test/org...

Author: daijy
Date: Mon Sep  9 17:39:03 2013
New Revision: 1521216

URL: http://svn.apache.org/r1521216
Log:
PIG-3431: Return more information for parsing related exceptions.

Modified:
    pig/trunk/CHANGES.txt
    pig/trunk/src/org/apache/pig/Main.java
    pig/trunk/src/org/apache/pig/PigException.java
    pig/trunk/src/org/apache/pig/PigServer.java
    pig/trunk/src/org/apache/pig/impl/PigContext.java
    pig/trunk/src/org/apache/pig/impl/logicalLayer/FrontendException.java
    pig/trunk/src/org/apache/pig/parser/ParserException.java
    pig/trunk/src/org/apache/pig/parser/QueryParserDriver.java
    pig/trunk/src/org/apache/pig/tools/parameters/PreprocessorContext.java
    pig/trunk/src/org/apache/pig/tools/pigstats/PigStats.java
    pig/trunk/src/org/apache/pig/tools/pigstats/PigStatsUtil.java
    pig/trunk/test/org/apache/pig/TestMain.java
    pig/trunk/test/org/apache/pig/test/TestParamSubPreproc.java

Modified: pig/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/pig/trunk/CHANGES.txt?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/CHANGES.txt (original)
+++ pig/trunk/CHANGES.txt Mon Sep  9 17:39:03 2013
@@ -30,6 +30,8 @@ PIG-3174: Remove rpm and deb artifacts f
 
 IMPROVEMENTS
 
+PIG-3431: Return more information for parsing related exceptions. (jeremykarn via daijy)
+
 PIG-3430: Add xml format for explaining MapReduce Plan. (jeremykarn via daijy)
 
 PIG-3048: Add mapreduce workflow information to job configuration (billie.rinaldi via daijy)

Modified: pig/trunk/src/org/apache/pig/Main.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/Main.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/Main.java (original)
+++ pig/trunk/src/org/apache/pig/Main.java Mon Sep  9 17:39:03 2013
@@ -606,10 +606,12 @@ static int run(String args[], PigProgres
         usage();
         rc = ReturnCode.PARSE_EXCEPTION;
         PigStatsUtil.setErrorMessage(e.getMessage());
+        PigStatsUtil.setErrorThrowable(e);
     } catch (org.apache.pig.tools.parameters.ParseException e) {
        // usage();
         rc = ReturnCode.PARSE_EXCEPTION;
         PigStatsUtil.setErrorMessage(e.getMessage());
+        PigStatsUtil.setErrorThrowable(e);
     } catch (IOException e) {
         if (e instanceof PigException) {
             PigException pe = (PigException)e;
@@ -621,6 +623,7 @@ static int run(String args[], PigProgres
             rc = ReturnCode.IO_EXCEPTION;
             PigStatsUtil.setErrorMessage(e.getMessage());
         }
+        PigStatsUtil.setErrorThrowable(e);
 
         if(!gruntCalled) {
             LogUtils.writeLog(e, logFileName, log, verbose, "Error before Pig is launched");
@@ -628,6 +631,8 @@ static int run(String args[], PigProgres
     } catch (Throwable e) {
         rc = ReturnCode.THROWABLE_EXCEPTION;
         PigStatsUtil.setErrorMessage(e.getMessage());
+        PigStatsUtil.setErrorThrowable(e);
+
         if(!gruntCalled) {
             LogUtils.writeLog(e, logFileName, log, verbose, "Error before Pig is launched");
         }

Modified: pig/trunk/src/org/apache/pig/PigException.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/PigException.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/PigException.java (original)
+++ pig/trunk/src/org/apache/pig/PigException.java Mon Sep  9 17:39:03 2013
@@ -19,6 +19,8 @@ package org.apache.pig;
 
 import java.io.IOException;
 
+import org.apache.pig.parser.SourceLocation;
+
 /**
  * All exceptions in Pig are encapsulated in the <code>PigException</code>
  * class. Details such as the source of the error, error message, error
@@ -28,6 +30,7 @@ import java.io.IOException;
  * errorCode = 0
  * retriable = false
  * detailedMessage = null
+ * location = null
  */
 public class PigException extends IOException {
 
@@ -112,6 +115,8 @@ public class PigException extends IOExce
     protected boolean retriable = false;
     protected String detailedMessage = null;
     protected boolean markedAsShowToUser = false;
+    protected SourceLocation sourceLocation = null;
+
 
     /**
      * Create a new PigException with null as the error message.
@@ -130,6 +135,17 @@ public class PigException extends IOExce
     }
     
     /**
+     * Create a new PigException with the specified message.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param location - The <link>SourceLocation</link> that generated this error.
+     */
+    public PigException(String message, SourceLocation location) {
+        super(message);
+        sourceLocation = location;
+    }
+    
+    /**
      * Create a new PigException with the specified cause.
      *
      * @param cause - The cause (which is saved for later retrieval by the <link>Throwable.getCause()</link> method) indicating the source of this exception. A null value is permitted, and indicates that the cause is nonexistent or unknown.
@@ -158,6 +174,18 @@ public class PigException extends IOExce
         this(message);
         errorCode = errCode;
     }
+    
+    /**
+     * Create a new PigException with the specified message and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
+     * @param location - The <link>SourceLocation</link> that generated this error.
+     */
+    public PigException (String message, int errCode, SourceLocation location) {
+        this(message, location);
+        errorCode = errCode;
+    }
 
     /**
      * Create a new PigException with the specified message and cause.
@@ -170,6 +198,20 @@ public class PigException extends IOExce
         this(message, cause);
         errorCode = errCode;
     }
+    
+    /**
+     * Create a new PigException with the specified message and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
+     * @param cause - The cause (which is saved for later retrieval by the <link>Throwable.getCause()</link> method) indicating the source of this exception. A null value is permitted, and indicates that the cause is nonexistent or unknown. 
+     * @param location - The <link>SourceLocation</link> that generated this error.
+     */
+    public PigException (String message, int errCode, Throwable cause, SourceLocation location) {
+        this(message, cause);
+        errorCode = errCode;
+        sourceLocation = location;
+    }
 
     /**
      * Create a new PigException with the specified message and cause.
@@ -182,6 +224,20 @@ public class PigException extends IOExce
         this(message, errCode);
         errorSource = errSrc;
     }
+    
+    
+    /**
+     * Create a new PigException with the specified message and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
+     * @param errSrc - The error source 
+     * @param location - The <link>SourceLocation</link> that generated this error.
+     */
+    public PigException (String message, int errCode, byte errSrc, SourceLocation location) {
+        this(message, errCode, location);
+        errorSource = errSrc;
+    }
 
     /**
      * Create a new PigException with the specified message and cause.
@@ -194,6 +250,19 @@ public class PigException extends IOExce
     public PigException (String message, int errCode, byte errSrc, Throwable cause) {
         this(message, errCode, errSrc, false, null, cause);
     }
+    
+    /**
+     * Create a new PigException with the specified message and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
+     * @param errSrc - The error source
+     * @param cause - The cause (which is saved for later retrieval by the <link>Throwable.getCause()</link> method) indicating the source of this exception. A null value is permitted, and indicates that the cause is nonexistent or unknown. 
+     * @param location - The <link>SourceLocation</link> that generated this error.
+     */
+    public PigException (String message, int errCode, byte errSrc, Throwable cause, SourceLocation location) {
+        this(message, errCode, errSrc, false, null, cause, location);
+    }
 
     /**
      * Create a new PigException with the specified message and cause.
@@ -233,6 +302,21 @@ public class PigException extends IOExce
         this(message, errCode, errSrc, retry);
         detailedMessage = detailedMsg;
     }
+    
+    /**
+     * Create a new PigException with the specified message and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
+     * @param errSrc - The error source 
+     * @param retry - If the exception is retriable or not
+     * @param detailedMsg - The detailed message shown to the developer 
+     */
+    public PigException (String message, int errCode, byte errSrc, boolean retry, String detailedMsg, SourceLocation location) {
+        this(message, errCode, errSrc, retry);
+        detailedMessage = detailedMsg;
+        sourceLocation = location;
+    }
 
     /**
      * Create a new PigException with the specified message, error code, error source, retriable or not, detalied message for the developer and cause.
@@ -253,6 +337,26 @@ public class PigException extends IOExce
     }    
     
     /**
+     * Create a new PigException with the specified message, error code, error source, retriable or not, detalied message for the developer and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
+     * @param errSrc - The error source 
+     * @param retry - If the exception is retriable or not
+     * @param detailedMsg - The detailed message shown to the developer 
+     * @param cause - The cause (which is saved for later retrieval by the <link>Throwable.getCause()</link> method) indicating the source of this exception. A null value is permitted, and indicates that the cause is nonexistent or unknown.
+     * @param location - The <link>SourceLocation</link> that generated this error.
+     */
+    public PigException (String message, int errCode, byte errSrc, boolean retry, String detailedMsg, Throwable cause, SourceLocation location) {
+        super(message, cause);
+        errorCode = errCode;
+        errorSource = errSrc;
+        retriable = retry;
+        detailedMessage = detailedMsg;
+        sourceLocation = location;
+    }    
+    
+    /**
      * Checks if the exception is retriable.
      * @return if the exception is retriable or not
      */
@@ -337,6 +441,17 @@ public class PigException extends IOExce
     }
     
     /**
+     * Return the location in the source that generated the exception.
+     */
+    public SourceLocation getSourceLocation() {
+        return sourceLocation;
+    }
+    
+    public void setSourceLocation(SourceLocation location) {
+        sourceLocation = location;
+    }
+    
+    /**
      * Returns a short description of this throwable.
      * The result is the concatenation of:
      * <ul>

Modified: pig/trunk/src/org/apache/pig/PigServer.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/PigServer.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/PigServer.java (original)
+++ pig/trunk/src/org/apache/pig/PigServer.java Mon Sep  9 17:39:03 2013
@@ -1637,7 +1637,12 @@ public class PigServer {
                 int errCode = 1000;
                 String msg = "Error during parsing. "
                         + (pe == null ? ex.getMessage() : pe.getMessage());
-                throw new FrontendException (msg, errCode, PigException.INPUT , ex );
+                log.error("exception during parsing: " + msg, ex);
+                if (null == pe) {
+                    throw new FrontendException (msg, errCode, PigException.INPUT , ex);
+                } else {
+                    throw new FrontendException (msg, errCode, PigException.INPUT , ex, pe.getSourceLocation() );
+                }
             }
         }
 

Modified: pig/trunk/src/org/apache/pig/impl/PigContext.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/impl/PigContext.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/impl/PigContext.java (original)
+++ pig/trunk/src/org/apache/pig/impl/PigContext.java Mon Sep  9 17:39:03 2013
@@ -399,7 +399,7 @@ public class PigContext implements Seria
             return writer.toString();
         } catch (ParseException e) {
             log.error(e.getLocalizedMessage());
-            throw new IOException(e.getCause());
+            throw new IOException(e);
         }
     }
 
@@ -424,7 +424,7 @@ public class PigContext implements Seria
             return new BufferedReader(new FileReader(outputFilePath));
         } catch (ParseException e) {
             log.error(e.getLocalizedMessage());
-            throw new IOException(e.getCause());
+            throw new IOException(e);
         } catch (FileNotFoundException e) {
             throw new IOException("Could not find file to substitute parameters for: " + outputFilePath);
         }

Modified: pig/trunk/src/org/apache/pig/impl/logicalLayer/FrontendException.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/impl/logicalLayer/FrontendException.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/impl/logicalLayer/FrontendException.java (original)
+++ pig/trunk/src/org/apache/pig/impl/logicalLayer/FrontendException.java Mon Sep  9 17:39:03 2013
@@ -20,6 +20,7 @@ package org.apache.pig.impl.logicalLayer
 
 import org.apache.pig.PigException;
 import org.apache.pig.newplan.Operator;
+import org.apache.pig.parser.SourceLocation;
 
 public class FrontendException extends PigException {
 
@@ -66,6 +67,17 @@ public class FrontendException extends P
      *
      * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
      * @param errCode - The error code shown to the user 
+     * @param location - The location of the exception.
+     */
+    public FrontendException(String message, int errCode, SourceLocation location) {
+        super(message, errCode, location);
+    }
+    
+    /**
+     * Create a new FrontendException with the specified message and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
      */
     public FrontendException(String message, int errCode) {
         super(message, errCode);
@@ -101,11 +113,23 @@ public class FrontendException extends P
      * @param errSrc - The error source
      * @param cause - The cause (which is saved for later retrieval by the <link>Throwable.getCause()</link> method) indicating the source of this exception. A null value is permitted, and indicates that the cause is nonexistent or unknown. 
      */
-    public FrontendException(String message, int errCode, byte errSrc,
-            Throwable cause) {
+    public FrontendException(String message, int errCode, byte errSrc, Throwable cause) {
         super(message, errCode, errSrc, cause);
     }
-
+    
+    /**
+     * Create a new FrontendException with the specified message and cause.
+     *
+     * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
+     * @param errCode - The error code shown to the user 
+     * @param errSrc - The error source
+     * @param cause - The cause (which is saved for later retrieval by the <link>Throwable.getCause()</link> method) indicating the source of this exception. A null value is permitted, and indicates that the cause is nonexistent or unknown. 
+     * @param location - The location of the exception.
+     */
+    public FrontendException(String message, int errCode, byte errSrc, Throwable cause, SourceLocation location) {
+        super(message, errCode, errSrc, cause, location);
+    }
+    
     /**
      * Create a new FrontendException with the specified message and cause.
      *
@@ -166,7 +190,7 @@ public class FrontendException extends P
      * @param message - The error message (which is saved for later retrieval by the <link>Throwable.getMessage()</link> method) shown to the user 
      */
     public FrontendException(Operator op, String message) {
-        this( op.getLocation() + message );
+        super( op.getLocation() + message, op.getLocation() );
     }
 
     /**
@@ -177,7 +201,7 @@ public class FrontendException extends P
      * @param errCode - The error code shown to the user 
      */
     public FrontendException(Operator op, String message, int errCode) {
-        this( op.getLocation() + message, errCode );
+        this( op.getLocation() + message, errCode, op.getLocation() );
     }
 
     /**
@@ -190,7 +214,7 @@ public class FrontendException extends P
      */
     public FrontendException(Operator op, String message, int errCode,
             byte errSrc) {
-        this( op.getLocation() + message, errCode );
+        this( op.getLocation() + message, errCode, op.getLocation() );
     }
 
     /**
@@ -204,7 +228,7 @@ public class FrontendException extends P
      */
     public FrontendException(Operator op, String message, int errCode,
             byte errSrc, Throwable cause) {
-        this( op.getLocation() + message, errCode, errSrc, cause );
+        this( op.getLocation() + message, errCode, errSrc, cause, op.getLocation() );
     }
 
     /**
@@ -216,7 +240,7 @@ public class FrontendException extends P
      * @param cause - The cause (which is saved for later retrieval by the <link>Throwable.getCause()</link> method) indicating the source of this exception. A null value is permitted, and indicates that the cause is nonexistent or unknown. 
      */
     public FrontendException(Operator op, String message, int errCode, Throwable cause) {
-        this( op.getLocation() + message, errCode, cause );
+        super( op.getLocation() + message, errCode, cause, op.getLocation() );
     }
 
     /**
@@ -232,7 +256,7 @@ public class FrontendException extends P
      */
     public FrontendException(Operator op, String message, int errCode, byte errSrc,
             boolean retry, String detailedMsg, Throwable cause) {
-        super(op.getLocation() + message, errCode, errSrc, retry, detailedMsg, cause);
+        super(op.getLocation() + message, errCode, errSrc, retry, detailedMsg, cause, op.getLocation() );
     }
 
 }

Modified: pig/trunk/src/org/apache/pig/parser/ParserException.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/parser/ParserException.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/parser/ParserException.java (original)
+++ pig/trunk/src/org/apache/pig/parser/ParserException.java Mon Sep  9 17:39:03 2013
@@ -33,6 +33,10 @@ public class ParserException extends Fro
 	public ParserException(String msg) {
 		super( msg, errorCode );
 	}
+	
+	public ParserException(String msg, SourceLocation location) {
+	    super(msg, errorCode, location);
+	}
 
 	public ParserException(String msg, Throwable cause) {
 	    super( msg, errorCode, cause );

Modified: pig/trunk/src/org/apache/pig/parser/QueryParserDriver.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/parser/QueryParserDriver.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/parser/QueryParserDriver.java (original)
+++ pig/trunk/src/org/apache/pig/parser/QueryParserDriver.java Mon Sep  9 17:39:03 2013
@@ -237,7 +237,8 @@ public class QueryParserDriver {
         } catch (RecognitionException e) {
             String msg = parser.getErrorHeader(e) + " "
                     + parser.getErrorMessage(e, parser.getTokenNames());
-            throw new ParserException(msg);
+            SourceLocation location = new SourceLocation(null, e.line,e.charPositionInLine);
+            throw new ParserException(msg, location);
         } catch(RuntimeException ex) {
             throw new ParserException( ex.getMessage() );
         }

Modified: pig/trunk/src/org/apache/pig/tools/parameters/PreprocessorContext.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/tools/parameters/PreprocessorContext.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/tools/parameters/PreprocessorContext.java (original)
+++ pig/trunk/src/org/apache/pig/tools/parameters/PreprocessorContext.java Mon Sep  9 17:39:03 2013
@@ -75,7 +75,7 @@ public class PreprocessorContext {
      * @param key - parameter name
      * @param val - string containing command to be executed
      */
-    public  void processShellCmd(String key, String val) {
+    public  void processShellCmd(String key, String val)  throws ParameterSubstitutionException {
         processShellCmd(key, val, true);
     }
 
@@ -86,7 +86,7 @@ public class PreprocessorContext {
      * @param key - parameter name
      * @param val - value supplied for the key
      */
-    public  void processOrdLine(String key, String val) {
+    public  void processOrdLine(String key, String val)  throws ParameterSubstitutionException {
         processOrdLine(key, val, true);
     }
 
@@ -111,7 +111,7 @@ public class PreprocessorContext {
      * @param key - parameter name
      * @param val - string containing command to be executed
      */
-    public  void processShellCmd(String key, String val, Boolean overwrite) {
+    public  void processShellCmd(String key, String val, Boolean overwrite)  throws ParameterSubstitutionException {
 
         if (param_val.containsKey(key)) {
             if (param_source.get(key).equals(val) || !overwrite) {
@@ -137,7 +137,7 @@ public class PreprocessorContext {
      * @param val - value supplied for the key
      * @param overwrite - specifies whether the value should be replaced if it already exists
      */
-    public  void processOrdLine(String key, String val, Boolean overwrite) {
+    public  void processOrdLine(String key, String val, Boolean overwrite)  throws ParameterSubstitutionException {
 
         if (param_val.containsKey(key)) {
             if (param_source.get(key).equals(val) || !overwrite) {
@@ -149,7 +149,7 @@ public class PreprocessorContext {
 
         param_source.put(key, val);
 
-        String sub_val = substitute(val);
+        String sub_val = substitute(val, key);
         param_val.put(key, sub_val);
     }
 
@@ -258,10 +258,14 @@ public class PreprocessorContext {
     private Pattern bracketIdPattern = Pattern.compile("\\$\\{([_]*[a-zA-Z][a-zA-Z_0-9]*)\\}");
     private Pattern id_pattern = Pattern.compile("\\$([_]*[a-zA-Z][a-zA-Z_0-9]*)");
 
-    public  String substitute(String line) {
+    public String substitute(String line) throws ParameterSubstitutionException {
+        return substitute(line, null);
+    }
 
+    public  String substitute(String line, String parentKey) throws ParameterSubstitutionException {
         int index = line.indexOf('$');
-        if (index == -1)	return line;
+        if (index == -1)
+            return line;
 
         String replaced_line = line;
 
@@ -274,7 +278,13 @@ public class PreprocessorContext {
             if ( (bracketKeyMatcher.start() == 0) || (line.charAt( bracketKeyMatcher.start() - 1)) != '\\' ) {
                 key = bracketKeyMatcher.group(1);
                 if (!(param_val.containsKey(key))) {
-                    throw new RuntimeException("Undefined parameter : "+key);
+                    String message;
+                    if (parentKey == null) {
+                        message = "Undefined parameter : " + key;
+                    } else {
+                        message = "Undefined parameter : " + key + " found when trying to find the value of " + parentKey + "."; 
+                    }
+                    throw new ParameterSubstitutionException(message);
                 }
                 val = param_val.get(key);
                 if (val.contains("$")) {
@@ -295,7 +305,13 @@ public class PreprocessorContext {
             if ( (keyMatcher.start() == 0) || (line.charAt( keyMatcher.start() - 1)) != '\\' ) {
                 key = keyMatcher.group(1);
                 if (!(param_val.containsKey(key))) {
-                    throw new RuntimeException("Undefined parameter : "+key);
+                    String message;
+                    if (parentKey == null) {
+                        message = "Undefined parameter : " + key;
+                    } else {
+                        message = "Undefined parameter : " + key + " found when trying to find the value of " + parentKey + "."; 
+                    }
+                    throw new ParameterSubstitutionException(message);
                 }
                 val = param_val.get(key);
                 if (val.contains("$")) {

Modified: pig/trunk/src/org/apache/pig/tools/pigstats/PigStats.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/tools/pigstats/PigStats.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/tools/pigstats/PigStats.java (original)
+++ pig/trunk/src/org/apache/pig/tools/pigstats/PigStats.java Mon Sep  9 17:39:03 2013
@@ -60,6 +60,7 @@ public abstract class PigStats {
     
     private String errorMessage;
     private int errorCode = -1;
+    private Throwable errorThrowable = null;
     
     public static PigStats get() {
         if (tps.get() == null) {
@@ -98,6 +99,13 @@ public abstract class PigStats {
     public int getErrorCode() {
         return errorCode;
     }
+    
+    /**
+     * Returns the error code of {@link PigException}
+     */
+    public Throwable getErrorThrowable() {
+        return errorThrowable;
+    }
 
     public abstract JobClient getJobClient();
 
@@ -205,7 +213,10 @@ public abstract class PigStats {
     void setErrorCode(int errorCode) {
         this.errorCode = errorCode;
     } 
-
+    
+    void setErrorThrowable(Throwable t) {
+        this.errorThrowable = t;
+    }
     
     /**
      * This class prints a JobGraph

Modified: pig/trunk/src/org/apache/pig/tools/pigstats/PigStatsUtil.java
URL: http://svn.apache.org/viewvc/pig/trunk/src/org/apache/pig/tools/pigstats/PigStatsUtil.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/src/org/apache/pig/tools/pigstats/PigStatsUtil.java (original)
+++ pig/trunk/src/org/apache/pig/tools/pigstats/PigStatsUtil.java Mon Sep  9 17:39:03 2013
@@ -66,7 +66,11 @@ public class PigStatsUtil {
     public static void setErrorCode(int code) {
         PigStats.get().setErrorCode(code);
     }
- 
+    
+    public static void setErrorThrowable(Throwable t) {
+        PigStats.get().setErrorThrowable(t);
+    }
+    
     private static Pattern pattern = Pattern.compile("tmp(-)?[\\d]{1,10}$");
     
     public static boolean isTempFile(String fileName) {

Modified: pig/trunk/test/org/apache/pig/TestMain.java
URL: http://svn.apache.org/viewvc/pig/trunk/test/org/apache/pig/TestMain.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/test/org/apache/pig/TestMain.java (original)
+++ pig/trunk/test/org/apache/pig/TestMain.java Mon Sep  9 17:39:03 2013
@@ -18,14 +18,29 @@
 
 package org.apache.pig;
 
-import static org.junit.Assert.*;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
 import java.util.Properties;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pig.impl.logicalLayer.FrontendException;
+import org.apache.pig.parser.ParserException;
+import org.apache.pig.parser.SourceLocation;
 import org.apache.pig.test.TestPigRunner.TestNotificationListener;
+import org.apache.pig.tools.parameters.ParameterSubstitutionException;
+import org.apache.pig.tools.pigstats.PigStats;
 import org.junit.Test;
 
 public class TestMain {
+    private Log log = LogFactory.getLog(TestMain.class);
 
     @Test
     public void testCustomListener() {
@@ -41,6 +56,75 @@ public class TestMain {
         assertTrue(listener.hadArgs);
 
     }
+    
+    @Test
+    public void testRun_setsErrorThrowableOnPigStats() {
+        File outputFile = null;
+        try {
+            String filename = this.getClass().getSimpleName() + "_" + "testRun_setsErrorThrowableOnPigStats";
+            outputFile = File.createTempFile(filename, ".out");
+            outputFile.delete();
+            
+            File scriptFile = File.createTempFile(filename, ".pig");
+            BufferedWriter bw = new BufferedWriter(new FileWriter(scriptFile));
+            bw.write("a = load 'test/org/apache/pig/test/data/passwd';\n");
+            bw.write("b = group a by $0\n");
+            bw.write("c = foreach b generate group, COUNT(a) as cnt;\n");
+            bw.write("store c into 'out'\n");
+            bw.close();
+            
+            Main.run(new String[]{"-x", "local", scriptFile.getAbsolutePath()}, null);
+            PigStats stats = PigStats.get();
+            
+            Throwable t = stats.getErrorThrowable();
+            assertTrue(t instanceof FrontendException);
+            
+            FrontendException fe = (FrontendException) t;
+            SourceLocation sl = fe.getSourceLocation();
+            assertEquals(2, sl.line());
+            assertEquals(15, sl.offset());
+            
+            Throwable cause = fe.getCause();
+            assertTrue(cause instanceof ParserException);
+            
+        } catch (Exception e) {
+            log.error("Encountered exception", e);
+            fail("Encountered Exception");
+        }
+    }
+    
+    @Test
+    public void testRun_setsErrorThrowableForParamSubstitution() {
+        File outputFile = null;
+        try {
+            String filename = this.getClass().getSimpleName() + "_" + "testRun_setsErrorThrowableForParamSubstitution";
+            outputFile = File.createTempFile(filename, ".out");
+            outputFile.delete();
+
+            File scriptFile = File.createTempFile(filename, ".pig");
+            BufferedWriter bw = new BufferedWriter(new FileWriter(scriptFile));
+            bw.write("a = load '$NOEXIST';\n");
+            bw.write("b = group a by $0\n");
+            bw.write("c = foreach b generate group, COUNT(a) as cnt;\n");
+            bw.write("store c into 'out'\n");
+            bw.close();
+            
+            Main.run(new String[]{"-x", "local", scriptFile.getAbsolutePath()}, null);
+            PigStats stats = PigStats.get();
+            
+            Throwable t = stats.getErrorThrowable();
+            assertTrue(t instanceof IOException);
+            
+            Throwable cause = t.getCause();
+            assertTrue(cause instanceof ParameterSubstitutionException);
+
+            ParameterSubstitutionException pse = (ParameterSubstitutionException) cause;
+            assertTrue(pse.getMessage().contains("NOEXIST"));
+        } catch (Exception e) {
+            log.error("Encountered exception", e);
+            fail("Encountered Exception");
+        }
+    }
 
     public static class TestNotificationListener2 extends TestNotificationListener {
         protected boolean hadArgs = false;

Modified: pig/trunk/test/org/apache/pig/test/TestParamSubPreproc.java
URL: http://svn.apache.org/viewvc/pig/trunk/test/org/apache/pig/test/TestParamSubPreproc.java?rev=1521216&r1=1521215&r2=1521216&view=diff
==============================================================================
--- pig/trunk/test/org/apache/pig/test/TestParamSubPreproc.java (original)
+++ pig/trunk/test/org/apache/pig/test/TestParamSubPreproc.java Mon Sep  9 17:39:03 2013
@@ -205,7 +205,7 @@ public class TestParamSubPreproc {
         try {
             ps.genSubstitutedFile(pigIStream , pigOStream , arg , argFiles);
             fail ("Should have thrown an Undefined parameter exception");
-        } catch (RuntimeException e) {
+        } catch (ParseException e) {
             assertEquals(e.getMessage(), "Undefined parameter : param");
         }
         log.info("Done");