Fix and fine-tune suppress_nulls.
authorChris Jaekl <cejaekl@yahoo.com>
Fri, 24 Mar 2017 10:17:41 +0000 (19:17 +0900)
committerChris Jaekl <cejaekl@yahoo.com>
Fri, 24 Mar 2017 10:17:41 +0000 (19:17 +0900)
pom.xml
src/main/java/net/jaekl/squelch/db/DbDriver.java
src/main/java/net/jaekl/squelch/db/Setting.java [new file with mode: 0644]
src/main/java/net/jaekl/squelch/stmt/PSet.java
src/main/java/net/jaekl/squelch/stmt/Tabular.java
src/test/java/net/jaekl/squelch/stmt/PSetTest.java
src/test/java/net/jaekl/squelch/stmt/TabularTest.java

diff --git a/pom.xml b/pom.xml
index 86b3db0ec0d7f5c0834f85020abe5837ca225dcb..051053c558a4188ba387264ee303fb1169783002 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   <groupId>net.jaekl.squelch</groupId>
   <artifactId>squelch</artifactId>
   <packaging>jar</packaging>
-  <version>0.1a-SNAPSHOT</version>
+  <version>0.1b-SNAPSHOT</version>
   <name>squelch</name>
   <url>http://maven.apache.org</url>
   <build>
index 72472de3c2a0992825c535f6183ccb41afb0fc50..cf116de5b8f3ba39c9c73cfb6553ed7d6a320592 100644 (file)
@@ -3,10 +3,14 @@ package net.jaekl.squelch.db;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import java.util.HashMap;
 import java.util.Locale;
 
 public abstract class DbDriver {
-       private boolean m_suppressNulls = false;
+       // Well-known setting names
+       public static final String SUPPRESS_NULLS = "suppress_nulls";
+       
+       private HashMap<String, Setting> m_settings;
        
        // Returns true iff. this DbDriver knows how to connect to the given JDBC URL
        abstract public boolean handles(String jdbcUrl);
@@ -14,13 +18,38 @@ public abstract class DbDriver {
        // Execute line as a statement of this type
        abstract String getJdbcDriverClassName();
 
+       DbDriver() {
+               m_settings = new HashMap<String, Setting>();
+               m_settings.put(SUPPRESS_NULLS, new Setting(SUPPRESS_NULLS, Boolean.class, Boolean.valueOf(false)));
+       }
+       
        // -------------------
        // Getters and setters
+       public Setting[] getSettings() 
+       {
+               return m_settings.values().toArray(new Setting[m_settings.size()]);
+       }
        
-       public boolean isSuppressNulls() { return m_suppressNulls; }
-       public void setSuppressNulls(boolean value) { m_suppressNulls = value; }
-       
-       
+       public boolean isSet(String name) 
+       {
+               Setting setting = m_settings.get(name);
+               if (null != setting) {
+                       return setting.getBoolean();
+               }
+               return false;
+       }
+       public void set(String name, Object value) 
+       {
+               String lcName = name.toLowerCase(Locale.CANADA);
+               Setting setting = m_settings.get(lcName);
+               if (null != setting) {
+                       setting.set(value);
+               }
+               else {
+                       throw new IllegalArgumentException("Setting \"" + name + "\" not found.");
+               }
+       }
+               
        // Open a new Connection to the database.  Note that the caller must close() this at some point.
        public Connection connect(String jdbcUrl, String userName, String password) throws ClassNotFoundException, SQLException 
        {
diff --git a/src/main/java/net/jaekl/squelch/db/Setting.java b/src/main/java/net/jaekl/squelch/db/Setting.java
new file mode 100644 (file)
index 0000000..85934ce
--- /dev/null
@@ -0,0 +1,61 @@
+package net.jaekl.squelch.db;
+
+import java.util.Locale;
+
+public class Setting {
+       private String m_name;
+       private Class<?> m_type;
+       private Object m_value;
+       
+       public Setting(String name, Class<?> type, Object defaultValue)
+       {
+               m_name = name;
+               m_type = type;
+               m_value = defaultValue;
+       }
+       
+       public String getName() { return m_name; }
+       
+       public boolean getBoolean() 
+       { 
+               assert(Boolean.class == m_type);
+               
+               if (m_value instanceof Boolean) {
+                       return ((Boolean)m_value).booleanValue();
+               }
+               return false;
+       }
+       
+       public void set(Object value) 
+       {
+               if (Boolean.class == m_type) {
+                       if (value instanceof String) {
+                               m_value = parseBoolean((String)value);
+                       }
+                       else if (value instanceof Boolean) {
+                               m_value = value;
+                       }
+               }
+               else {
+                       throw new IllegalArgumentException("This type not yet supported.");
+               }
+       }
+
+       private boolean parseBoolean(String value) 
+       {
+               if (null == value) {
+                       return false;
+               }
+               
+               String setting = value.trim().toLowerCase(Locale.CANADA);
+               
+               if (setting.equals("yes") || setting.equals("true")  || setting.equals("on")  || setting.equals("1")) {
+                       return true;
+               }
+               if (setting.equals("no")  || setting.equals("false") || setting.equals("off") || setting.equals("0")) {
+                       return false;
+               }
+               
+               throw new IllegalArgumentException("UnrecognizedBooleanValue:  \"" + value + "\"");
+       }
+}
index a64edc2d926f648c12ce87e0fc74d59baedf0ca2..1431ab9267d141260c168856b8438d88cf6ae011 100644 (file)
@@ -7,10 +7,9 @@ import java.sql.SQLException;
 import java.util.Locale;
 
 import net.jaekl.squelch.db.DbDriver;
+import net.jaekl.squelch.db.Setting;
 
 public class PSet extends Stmt {
-       private static final String SUPPRESS_NULLS = "suppress_nulls";
-
        @Override
        public boolean handles(String line) {
                if (null == line) {
@@ -24,72 +23,40 @@ public class PSet extends Stmt {
        public int exec(DbDriver driver, Connection conn, PrintWriter pw, String line) 
                        throws IOException, SQLException 
        {
-               String trimmed = line.substring(6).trim();
+               String trimmed = line.substring(5).trim();
 
                int equPos = trimmed.indexOf('=');
                
                if (equPos > 0) {
                        return setValue(driver, pw, trimmed, equPos);
                }
-               else if (trimmed.length() > 0) {
-                       return displayValue(driver, pw, trimmed);
-               }
                else {
-                       // TODO:  StringTable
-                       pw.println("???");
-                       return 0;       
+                       return displayValue(driver, pw, trimmed);
                }
        }
        
        private int displayValue(DbDriver driver, PrintWriter pw, String trimmed)
        {
-               String lcName = trimmed.toLowerCase(Locale.CANADA);
+               Setting[] settings = driver.getSettings();
                
-               if (SUPPRESS_NULLS.equals(lcName)) {
-                       // TODO:  StringTable
-                       pw.println(SUPPRESS_NULLS + ":  " + (driver.isSuppressNulls() ? "on" : "off"));
-               }
-               else {
-                       // TODO:  StringTable
-                       pw.println("??? Unrecognized setting:  \"" + trimmed + "\".  Ignored.");
+               for (Setting setting : settings) {
+                       String lcName = trimmed.toLowerCase(Locale.CANADA);
+                       
+                       if ("".equals(lcName) || setting.getName().equals(lcName)) {
+                               // TODO:  StringTable
+                               pw.println(setting.getName() + ":  " + (setting.getBoolean()));
+                       }
                }
                
                return 0;
        }
        
-       private boolean parseBoolean(String value) 
-       {
-               if (null == value) {
-                       return false;
-               }
-               
-               String setting = value.trim().toLowerCase(Locale.CANADA);
-               
-               if (setting.equals("yes") || setting.equals("true")  || setting.equals("on")  || setting.equals("1")) {
-                       return true;
-               }
-               if (setting.equals("no")  || setting.equals("false") || setting.equals("off") || setting.equals("0")) {
-                       return false;
-               }
-               
-               throw new IllegalArgumentException("UnrecognizedBooleanValue:  \"" + value + "\"");
-       }
-       
        private int setValue(DbDriver driver, PrintWriter pw, String trimmed, int equPos)
        {
                String name = trimmed.substring(0, equPos).trim();
                String value = trimmed.substring(equPos + 1).trim();
                
-               String lcName = name.toLowerCase(Locale.CANADA);
-                       
-               if (lcName.equals("suppress_nulls")) {
-                       driver.setSuppressNulls(parseBoolean(value));
-               }
-               else {
-                       // TODO:  Stringtable
-                       pw.println("??? Unrecognized setting name \"" + name + "\" ignored.");
-                       return 0;
-               }
+               driver.set(name, value);
                
                return 1;
        }
index eef757d9f54f0d52b9a2ad89066b1099540df738..6a060f1a2b0e94c46e77b159289f278272caa1b7 100644 (file)
@@ -69,21 +69,21 @@ abstract public class Tabular {
                if (pending > 0) {
                        writeHeader(pw, cols, colWidths, suppressed);
                        writeRowBuffer(pw, rowBuf, colWidths, suppressed);
-                       rowCount = rowBuf.getPending();
+                       rowCount = pending;
                }
                
-               if (driver.isSuppressNulls()) {
-                       // TODO:  StringTable
-                       pw.println("Row limit for suppress_nulls has been reached; output may have been truncated.");
-                       writeDivider(pw, colWidths, suppressed);
-               }
-               else {
-                       while (pending > 0) {
-                               rowBuf = bufferRows(driver, colWidths);
-                               writeRowBuffer(pw, rowBuf, colWidths, suppressed);
-                               pending = rowBuf.getPending();
-                               rowCount += pending;
+               rowBuf = bufferRows(driver, colWidths);
+               pending = rowBuf.getPending();
+               while (pending > 0) {
+                       if (driver.isSet(DbDriver.SUPPRESS_NULLS)) {
+                               writeDivider(pw, colWidths, suppressed);
+                               pw.println("Row limit for suppress_nulls has been reached; output may have been truncated.");
+                               break;
                        }
+                       writeRowBuffer(pw, rowBuf, colWidths, suppressed);
+                       rowCount += pending;
+                       rowBuf = bufferRows(driver, colWidths);
+                       pending = rowBuf.getPending();
                }
                
                if (rowCount > 0) {
@@ -164,13 +164,13 @@ abstract public class Tabular {
                                }
                        }
 
-                       if ((!allColsNull) || (!driver.isSuppressNulls())) 
+                       if ((!allColsNull) || (!driver.isSet(DbDriver.SUPPRESS_NULLS))) 
                        {
                                rowBuf.addRow(row);
 
                                // Check whether all values in this row will fit in the current column widths
                                for (int colIdx = 0; colIdx < colWidths.length; ++colIdx) {
-                                       int width = ("" + row.getValue(colIdx + 1)).length();
+                                       int width = stringify(row.getValue(colIdx + 1)).length();
                                        if (width > colWidths[colIdx]) {
                                                // Widen the column to fit this value
                                                colWidths[colIdx] = width;
@@ -307,8 +307,12 @@ abstract public class Tabular {
        {
                boolean[] result = new boolean[cols.length];
                
-               if (rowBuf.getPending() < 1) {
-                       // No data rows, so do not suppress any columns.
+               if (  !(driver.isSet(DbDriver.SUPPRESS_NULLS)) 
+                  ||  (rowBuf.getPending() < 1) )
+               {
+                       // Null-suppression is turned off, or 
+                       // there are no data rows, 
+                       // so do not suppress any columns.
                        for (int colIdx = 0; colIdx < cols.length; ++colIdx) {
                                result[colIdx] = false;
                        }
@@ -346,8 +350,10 @@ abstract public class Tabular {
                writeDivider(pw, colWidths, suppressed);
 
                for (int idx = 0; idx < cols.length; ++idx) {
-                       Column col = cols[idx];
-                       pw.print("| " + centrePad(col.getLabel(), colWidths[idx]) + " ");
+                       if (!suppressed[idx]) {
+                               Column col = cols[idx];
+                               pw.print("| " + centrePad(col.getLabel(), colWidths[idx]) + " ");
+                       }
                }
                pw.println("|");
                
@@ -362,7 +368,7 @@ abstract public class Tabular {
                                if (!suppressed[colIdx]) {
                                        Object obj = row.getValue(colIdx + 1);
                                        String value = stringify(obj);
-                                       int width = stringWidth(obj);
+                                       int width = stringWidth(value);
                                        String padding = repChar(' ', colWidths[colIdx] - width);
                                        pw.print("| " + value + padding + " ");
                                }
index c33e00a42fd4412d88bd0b194e2a41f10fdbec7f..8c17d88efcd030b54a2af98eab66c1bed33c3be6 100644 (file)
@@ -8,6 +8,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.sql.SQLException;
 
+import net.jaekl.squelch.db.DbDriver;
 import net.jaekl.squelch.db.DbDriverMock;
 import net.jaekl.squelch.sql.ConnectionMock;
 
@@ -60,23 +61,23 @@ public class PSetTest {
 
                for (String value : on) {
                        pset.exec(driver, conn, pw, "\\pset suppress_nulls=" + value);
-                       assertTrue(driver.isSuppressNulls());
+                       assertTrue(driver.isSet(DbDriver.SUPPRESS_NULLS));
                        
                        pset.exec(driver, conn, pw, "\\pset Suppress_NULLS=" + value);
-                       assertTrue(driver.isSuppressNulls());
+                       assertTrue(driver.isSet(DbDriver.SUPPRESS_NULLS));
                }
                
                for (String value : off) {
                        pset.exec(driver, conn, pw, "\\pset suppress_nulls=" + value);
-                       assertFalse(driver.isSuppressNulls());
+                       assertFalse(driver.isSet(DbDriver.SUPPRESS_NULLS));
                        
                        pset.exec(driver, conn, pw, "\\pset Suppress_NULLS=" + value);
-                       assertFalse(driver.isSuppressNulls());
+                       assertFalse(driver.isSet(DbDriver.SUPPRESS_NULLS));
                }
                
                for (String value : on) {
                        pset.exec(driver, conn, pw, "\\PSET SuPPreSS_NuLLs=" + value);
-                       assertTrue(driver.isSuppressNulls());
+                       assertTrue(driver.isSet(DbDriver.SUPPRESS_NULLS));
                }
                
                pw.close();
@@ -93,16 +94,35 @@ public class PSetTest {
                for (String cmd : cmds) {
                        DbDriverMock driver = new DbDriverMock();
 
-                       driver.setSuppressNulls(true);
+                       driver.set(DbDriver.SUPPRESS_NULLS, true);
                        String output = doExec(driver, cmd);            
-                       assertEquals("suppress_nulls:  on\n", output);
+                       assertEquals("suppress_nulls:  true\n", output);
                        
-                       driver.setSuppressNulls(false);
+                       driver.set(DbDriver.SUPPRESS_NULLS, false);
                        output = doExec(driver, cmd);
-                       assertEquals("suppress_nulls:  off\n", output);
+                       assertEquals("suppress_nulls:  false\n", output);
                }
        }
        
+       @Test
+       public void testExec_displayAll() throws IOException, SQLException
+       {
+               String[] cmds = { "\\pset", "\\pset  ", "\\pset ",
+                         "\\PsET", "\\PsET ", "\\PSET", "\\PSET  " };
+
+               for (String cmd : cmds) {
+                       DbDriverMock driver = new DbDriverMock();
+               
+                       driver.set(DbDriver.SUPPRESS_NULLS, true);
+                       String output = doExec(driver, cmd);            
+                       assertTrue(output.contains("suppress_nulls:  true\n"));
+                       
+                       driver.set(DbDriver.SUPPRESS_NULLS, false);
+                       output = doExec(driver, cmd);
+                       assertTrue(output.contains("suppress_nulls:  false\n"));
+               }               
+       }
+       
        private String doExec(DbDriverMock driver, String cmd) throws IOException, SQLException 
        {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
index ddfe3d42533b3935b622060ab6be6b42e0a5e0c7..1dfe4dbcf3d8e1aec893b840a4f79f529fde88db 100644 (file)
@@ -15,6 +15,7 @@ import javax.sql.rowset.serial.SerialException;
 
 import junit.framework.Assert;
 
+import net.jaekl.squelch.db.DbDriver;
 import net.jaekl.squelch.db.DbDriverMock;
 import net.jaekl.squelch.sql.Column;
 import net.jaekl.squelch.sql.Row;
@@ -128,6 +129,57 @@ public class TabularTest {
                }
        }
        
+       @Test
+       public void test_printTable_withNulls() throws IOException, SQLException
+       {
+               DbDriverMock driver = new DbDriverMock();
+
+               TabularMock tabular = createTableWithNulls();
+               driver.set(DbDriver.SUPPRESS_NULLS, true);
+               
+               try (
+                               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                               PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8));
+                       )
+               {
+                       tabular.printTable(driver, pw, "No rows returned.");
+                       pw.close();
+                       baos.close();
+                       String actual = baos.toString();
+                       assertEquals(  "+---------+--------+------------+\n"
+                                            + "|  EmpId  | Value1 |   Value3   |\n"
+                                            + "+---------+--------+------------+\n"
+                                            + "| 12345   | Fred   | Flintstone |\n"
+                                            + "| 7654321 | Barney | Rubble     |\n"
+                                            + "+---------+--------+------------+\n"
+                                            + "2 row(s) returned.\n",
+                                            actual);
+               }               
+               
+               tabular = createTableWithNulls();
+               driver.set(DbDriver.SUPPRESS_NULLS, false);
+               
+               try (
+                               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                               PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8));
+                       )
+               {
+                       tabular.printTable(driver, pw, "No rows returned.");
+                       pw.close();
+                       baos.close();
+                       String actual = baos.toString();
+                       assertEquals(  "+---------+--------+--------+------------+\n"
+                                            + "|  EmpId  | Value1 | Value2 |   Value3   |\n"
+                                            + "+---------+--------+--------+------------+\n"
+                                            + "| 12345   | Fred   | null   | Flintstone |\n"
+                                            + "| 7654321 | Barney | null   | Rubble     |\n"
+                                            + "+---------+--------+--------+------------+\n"
+                                            + "2 row(s) returned.\n",
+                                            actual);
+               }               
+               
+       }
+       
        @Test
        public void test_repChar() {
                Tabular tabular = new TabularMock();
@@ -210,4 +262,33 @@ public class TabularTest {
                
                return tabular;
        }
+       
+       private TabularMock createTableWithNulls()
+       {
+               TabularMock tabular = new TabularMock();
+               
+               Column[] cols = { 
+                               new Column("EmpId", Long.class, 10),
+                               new Column("Value1", String.class, 14),
+                               new Column("Value2", String.class, 14),
+                               new Column("Value3", String.class, 14)
+               };
+               tabular.mock_setCols(cols);
+               
+               Row row = new Row(cols.length);
+               row.setValue(1, Long.valueOf(12345));
+               row.setValue(2, "Fred");
+               row.setValue(3, null);
+               row.setValue(4, "Flintstone");
+               tabular.mock_addRow(row);
+               
+               row = new Row(cols.length);
+               row.setValue(1, Long.valueOf(7654321));
+               row.setValue(2, "Barney");
+               row.setValue(3, null);
+               row.setValue(4, "Rubble");
+               tabular.mock_addRow(row);
+               
+               return tabular;         
+       }
 }