[teiid-commits] teiid SVN: r4653 - in branches/7.7.x/runtime/src: test/java and 1 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Tue Aug 26 09:46:27 EDT 2014


Author: jolee
Date: 2014-08-26 09:46:27 -0400 (Tue, 26 Aug 2014)
New Revision: 4653

Added:
   branches/7.7.x/runtime/src/test/java/TestScriptReader/
   branches/7.7.x/runtime/src/test/java/TestScriptReader/TestScriptReader.java
Modified:
   branches/7.7.x/runtime/src/main/java/org/teiid/odbc/ScriptReader.java
Log:
TEIID-2985 allowing the script reader to ignore extra statement
delimiters

Modified: branches/7.7.x/runtime/src/main/java/org/teiid/odbc/ScriptReader.java
===================================================================
--- branches/7.7.x/runtime/src/main/java/org/teiid/odbc/ScriptReader.java	2014-08-26 13:46:21 UTC (rev 4652)
+++ branches/7.7.x/runtime/src/main/java/org/teiid/odbc/ScriptReader.java	2014-08-26 13:46:27 UTC (rev 4653)
@@ -8,7 +8,7 @@
 
 import java.io.IOException;
 import java.io.Reader;
-import java.util.Arrays;
+import java.io.StringReader;
 
 /**
  * This class can split SQL scripts to single SQL statements.
@@ -17,17 +17,13 @@
  */
 public class ScriptReader {
     private Reader reader;
-    private char[] buffer;
-    private int bufferPos;
-    private int bufferStart = -1;
-    private int bufferEnd;
+    private StringBuilder builder;
     private boolean endOfFile;
     private boolean insideRemark;
     private boolean blockRemark;
-    private boolean skipRemarks;
-    private int remarkStart;
-
-    private static int IO_BUFFER_SIZE = 4096;
+    private boolean rewrite;
+    private int expressionStart=-1;
+    private int expressionEnd=-1;
     
     /**
      * Create a new SQL script reader from the given reader
@@ -36,9 +32,14 @@
      */
     public ScriptReader(Reader reader) {
         this.reader = reader;
-        buffer = new char[IO_BUFFER_SIZE * 2];
+        this.builder = new StringBuilder(1<<13);
     }
-
+    
+    public ScriptReader(String string) {
+    	this.reader = new StringReader(string);
+        this.builder = new StringBuilder(string.length());
+    }
+    
     /**
      * Close the underlying reader.
      */
@@ -56,26 +57,29 @@
         if (endOfFile) {
             return null;
         }
-        return readStatementLoop();
+        while (true) {
+        	String result = readStatementLoop();
+        	if (result != null || endOfFile) {
+        		return result;
+        	}
+        }
+        
     }
 
     private String readStatementLoop() throws IOException {
-        bufferStart = bufferPos;
         int c = read();
         while (true) {
             if (c < 0) {
                 endOfFile = true;
-                if (bufferPos - 1 == bufferStart) {
-                    return null;
-                }
                 break;
             } else if (c == ';') {
+            	builder.setLength(builder.length()-1);
                 break;
             }
             switch (c) {
             case '$': {
                 c = read();
-                if (c == '$' && (bufferPos - bufferStart < 3 || buffer[bufferPos - 3] <= ' ')) {
+                if (c == '$' && (builder.length() < 3 || builder.charAt(builder.length() - 3) <= ' ')) {
                     // dollar quoted string
                     while (true) {
                         c = read();
@@ -97,15 +101,18 @@
                 break;
             }
             case '\'':
+            	//TODO: in rewrite mode could handle the E' logic here rather than in the parser
+            	//however the parser now uses E' with like to detect pg specific handling
+            	if (expressionEnd != builder.length() - 1) {
+            		expressionStart = builder.length() - 1;
+            	}
                 while (true) {
                     c = read();
-                    if (c < 0) {
+                    if (c < 0 || c == '\'') {
                         break;
                     }
-                    if (c == '\'') {
-                        break;
-                    }
                 }
+                expressionEnd = builder.length();
                 c = read();
                 break;
             case '"':
@@ -133,7 +140,6 @@
                         if (c == '*') {
                             c = read();
                             if (c < 0) {
-                                clearRemark();
                                 break;
                             }
                             if (c == '/') {
@@ -149,7 +155,6 @@
                     while (true) {
                         c = read();
                         if (c < 0) {
-                            clearRemark();
                             break;
                         }
                         if (c == '\r' || c == '\n') {
@@ -169,7 +174,6 @@
                     while (true) {
                         c = read();
                         if (c < 0) {
-                            clearRemark();
                             break;
                         }
                         if (c == '\r' || c == '\n') {
@@ -181,67 +185,122 @@
                 }
                 break;
             }
+            case ':': {
+            	if (rewrite) {
+                	int start = builder.length();
+                	c = read();
+                	if (c == ':') {
+                        while (true) {
+                            c = read();
+                            if (c < 0 || !Character.isLetterOrDigit(c)) {
+                            	String type = builder.substring(start+1, builder.length() - (c<0?0:1));
+                            	builder.setLength(start-1);
+                            	if (expressionStart != -1 && expressionEnd == start -1) {
+                            		//special handling for regclass cast - it won't always work
+                            		if ("regclass".equalsIgnoreCase(type)) { //$NON-NLS-1$
+                            			String name = builder.substring(expressionStart);
+                        				if (name.startsWith("'\"") && name.length() > 4) { //$NON-NLS-1$ 
+                            				name = name.substring(2, name.length()-2);
+                            				name = '\''+ name + '\'';
+                            			}
+                        				if (name.startsWith("'")) { //$NON-NLS-1$ 
+                        					builder.setLength(expressionStart);
+                            				builder.append(name.toUpperCase());
+                        				}
+                            			builder.insert(expressionStart, "(SELECT oid FROM pg_class WHERE upper(relname) = "); //$NON-NLS-1$
+                            			builder.append(")"); //$NON-NLS-1$ 
+                            		} else if ("regproc".equalsIgnoreCase(type)) {
+                            			String name = builder.substring(expressionStart);
+                        				if (name.startsWith("'\"") && name.length() > 4) { //$NON-NLS-1$ 
+                            				name = name.substring(2, name.length()-2);
+                            				name = '\''+ name + '\'';
+                            			}
+                        				if (name.startsWith("'")) { //$NON-NLS-1$ 
+                        					builder.setLength(expressionStart);
+                            				builder.append(name.toUpperCase());
+                        				}
+                            			builder.insert(expressionStart, "(SELECT oid FROM pg_proc WHERE upper(proname) = "); //$NON-NLS-1$
+                            			builder.append(")"); //$NON-NLS-1$
+                            		} else {
+	                            		builder.insert(expressionStart, "cast("); //$NON-NLS-1$
+	                                	builder.append(" AS ").append(type).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+                            		}
+                            	}
+                            	if (c != -1) {
+                            		builder.append((char)c);
+                            	}
+                            	break;
+                            }
+                        }
+                	}
+                	break;
+            	}
+            	c = read();
+            	break;
+            }
+            case '~': {
+            	if (rewrite) {
+            		int start = builder.length() - 1;
+            		boolean not = false;
+            		if (start > 0 && builder.charAt(start - 1) == '!') {
+        				not = true;
+        				start -= 1;
+            		}
+            		c = read();
+            		boolean like = false;
+            		if (c == '~') {
+            			like = true;
+            			c = read();
+            		}
+            		if (c == '*') {
+            			break; //can't handle
+            		}
+            		builder.setLength(start);
+            		if (not) {
+            			builder.append(" NOT"); //$NON-NLS-1$
+            		}
+            		if (like) {
+            			builder.append(" LIKE "); //$NON-NLS-1$
+            		} else {
+            			builder.append(" LIKE_REGEX "); //$NON-NLS-1$
+            		}
+            		if (c != -1) {
+                		builder.append((char)c);
+                	}
+            	}
+            	c = read();
+            	break;
+            }
             default: {
                 c = read();
             }
             }
         }
-        return new String(buffer, bufferStart, bufferPos - 1 - bufferStart);
+        String result = builder.toString();
+        builder.setLength(0);
+        if (result.length() == 0) {
+        	return null;
+        }
+        return result;
     }
 
     private void startRemark(boolean block) {
         blockRemark = block;
-        remarkStart = bufferPos - 2;
         insideRemark = true;
     }
 
     private void endRemark() {
-        clearRemark();
         insideRemark = false;
     }
 
-    private void clearRemark() {
-        if (skipRemarks) {
-            Arrays.fill(buffer, remarkStart, bufferPos, ' ');
-        }
-    }
-
     private int read() throws IOException {
-        if (bufferPos >= bufferEnd) {
-            return readBuffer();
-        }
-        return buffer[bufferPos++];
+       int c = reader.read();
+       if (c != -1) {
+    	   builder.append((char)c);
+       }
+       return c;
     }
 
-    private int readBuffer() throws IOException {
-        if (endOfFile) {
-            return -1;
-        }
-        int keep = bufferPos - bufferStart;
-        if (keep > 0) {
-            char[] src = buffer;
-            if (keep + IO_BUFFER_SIZE > src.length) {
-                buffer = new char[src.length * 2];
-            }
-            System.arraycopy(src, bufferStart, buffer, 0, keep);
-        }
-        remarkStart -= bufferStart;
-        bufferStart = 0;
-        bufferPos = keep;
-        int len = reader.read(buffer, keep, IO_BUFFER_SIZE);
-        if (len == -1) {
-            // ensure bufferPos > bufferEnd
-            bufferEnd = -1024;
-            endOfFile = true;
-            // ensure the right number of characters are read
-            // in case the input buffer is still used
-            bufferPos++;
-            return -1;
-        }
-        bufferEnd = keep + len;
-        return buffer[bufferPos++];
-    }
-
     /**
      * Check if this is the last statement, and if the single line or block
      * comment is not finished yet.
@@ -262,13 +321,8 @@
         return blockRemark;
     }
 
-    /**
-     * If comments should be skipped completely by this reader.
-     *
-     * @param skipRemarks true if comments should be skipped
-     */
-    public void setSkipRemarks(boolean skipRemarks) {
-        this.skipRemarks = skipRemarks;
-    }
+    public void setRewrite(boolean rewrite) {
+		this.rewrite = rewrite;
+	}
 
 }

Added: branches/7.7.x/runtime/src/test/java/TestScriptReader/TestScriptReader.java
===================================================================
--- branches/7.7.x/runtime/src/test/java/TestScriptReader/TestScriptReader.java	                        (rev 0)
+++ branches/7.7.x/runtime/src/test/java/TestScriptReader/TestScriptReader.java	2014-08-26 13:46:27 UTC (rev 4653)
@@ -0,0 +1,95 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Licensed to Red Hat, Inc. under one or more contributor 
+ * license agreements.  See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package TestScriptReader;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.teiid.odbc.ScriptReader;
+
+ at SuppressWarnings("nls")
+public class TestScriptReader {
+
+	@Test public void testRewrite() throws Exception {
+		ScriptReader sr = new ScriptReader("select 'a'::b from foo");
+		sr.setRewrite(true);
+		String result = sr.readStatement();
+		assertEquals("select cast('a' AS b) from foo", result);
+	}
+	
+	@Test public void testRewriteComplexLiteral() throws Exception {
+		ScriptReader sr = new ScriptReader("select 'a''c'::b");
+		sr.setRewrite(true);
+		String result = sr.readStatement();
+		assertEquals("select cast('a''c' AS b)", result);
+	}
+	
+	@Test public void testRewrite1() throws Exception {
+		ScriptReader sr = new ScriptReader("select a~b, a!~~c from foo");
+		sr.setRewrite(true);
+		String result = sr.readStatement();
+		assertEquals("select a LIKE_REGEX b, a NOT LIKE c from foo", result);
+	}
+	
+	@Test public void testRewrite2() throws Exception {
+		ScriptReader sr = new ScriptReader("select a~");
+		sr.setRewrite(true);
+		String result = sr.readStatement();
+		assertEquals("select a LIKE_REGEX ", result);
+	}
+	
+	@Test public void testRewrite3() throws Exception {
+		ScriptReader sr = new ScriptReader("select a::b");
+		sr.setRewrite(true);
+		String result = sr.readStatement();
+		assertEquals("select a", result);
+	}
+	
+	@Test public void testDelimited() throws Exception {
+		ScriptReader sr = new ScriptReader("set foo 'bar'; set foo1 'bar1'");
+		String result = sr.readStatement();
+		assertEquals("set foo 'bar'", result);
+		result = sr.readStatement();
+		assertEquals(" set foo1 'bar1'", result);
+	}
+	
+	@Test public void testRegClassCast() throws Exception {
+		ScriptReader sr = new ScriptReader("where oid='\"a\"'::regclass");
+		sr.setRewrite(true);;
+		String result = sr.readStatement();
+		assertEquals("where oid=(SELECT oid FROM pg_class WHERE upper(relname) = 'A')", result);
+	}
+	
+	@Test public void testExtraDelim() throws Exception {
+		ScriptReader sr = new ScriptReader("BEGIN;declare \"SQL_CUR0x1e4ba50\" cursor with hold for select * from pg_proc;;fetch 1 in \"SQL_CUR0x1e4ba50\"");
+		String result = sr.readStatement();
+		assertEquals("BEGIN", result);
+		result = sr.readStatement();
+		assertEquals("declare \"SQL_CUR0x1e4ba50\" cursor with hold for select * from pg_proc", result);
+		result = sr.readStatement();
+		assertEquals("fetch 1 in \"SQL_CUR0x1e4ba50\"", result);
+		assertNull(sr.readStatement());
+	}
+	
+}



More information about the teiid-commits mailing list