adds support for null suppression
[squelch.git] / src / main / java / net / jaekl / squelch / stmt / Tabular.java
index 582b26ad1df1a6eee18dd4a2bcc5bf1ff449470e..eef757d9f54f0d52b9a2ad89066b1099540df738 100644 (file)
@@ -11,6 +11,7 @@ import java.sql.Types;
 
 import javax.xml.bind.DatatypeConverter;
 
+import net.jaekl.squelch.db.DbDriver;
 import net.jaekl.squelch.sql.Column;
 import net.jaekl.squelch.sql.Row;
 
@@ -50,7 +51,7 @@ abstract public class Tabular {
        abstract Row getNext() throws SQLException;
        
        // Returns the number of (data) rows that were output
-       public int printTable(PrintWriter pw, String noRowsMessage) 
+       public int printTable(DbDriver driver, PrintWriter pw, String noRowsMessage) 
                throws SQLException 
        {
                int rowCount = 0;
@@ -61,25 +62,33 @@ abstract public class Tabular {
                int[] colWidths = initColWidthsFromColNames(cols);
                
                // Examine and buffer up to ROW_BUF_SIZE rows, adjusting (widening) colWidths where needed
-               rowBuf = bufferRows(colWidths);
+               rowBuf = bufferRows(driver, colWidths);
+               boolean[] suppressed = suppressNulls(driver, rowBuf, cols);
                
                int pending = rowBuf.getPending();
                if (pending > 0) {
-                       writeHeader(pw, cols, colWidths);
-                       writeRowBuffer(pw, rowBuf, colWidths);
+                       writeHeader(pw, cols, colWidths, suppressed);
+                       writeRowBuffer(pw, rowBuf, colWidths, suppressed);
                        rowCount = rowBuf.getPending();
                }
                
-               while (pending > 0) {
-                       rowBuf = bufferRows(colWidths);
-                       writeRowBuffer(pw, rowBuf, colWidths);
-                       pending = 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;
+                       }
                }
                
                if (rowCount > 0) {
-                       writeDivider(pw, colWidths);
-                       // TODO:  Implement a String table for i18n
+                       writeDivider(pw, colWidths, suppressed);
+                       // TODO:  Implement a StringTable for i18n
                        pw.println("" + rowCount + " row(s) returned.");
                }
                else {
@@ -137,7 +146,7 @@ abstract public class Tabular {
        
        // Examine and buffer up to rowBuf.length rows.
        // Returns the number of actual rows that were buffered (zero if no more rows are available).
-       RowBuffer bufferRows(int[] colWidths) throws SQLException
+       RowBuffer bufferRows(DbDriver driver, int[] colWidths) throws SQLException
        {
                RowBuffer rowBuf = new RowBuffer();
                
@@ -147,14 +156,25 @@ abstract public class Tabular {
                                // No more rows available
                                return rowBuf;
                        }
-                       rowBuf.addRow(row);
+                       
+                       boolean allColsNull = true;
+                       for (int idx = 1; idx <= colWidths.length; ++idx) {
+                               if (null != row.getValue(idx)) {
+                                       allColsNull = false;
+                               }
+                       }
 
-                       // 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();
-                               if (width > colWidths[colIdx]) {
-                                       // Widen the column to fit this value
-                                       colWidths[colIdx] = width;
+                       if ((!allColsNull) || (!driver.isSuppressNulls())) 
+                       {
+                               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();
+                                       if (width > colWidths[colIdx]) {
+                                               // Widen the column to fit this value
+                                               colWidths[colIdx] = width;
+                                       }
                                }
                        }
                }
@@ -283,15 +303,47 @@ abstract public class Tabular {
                return ("" + obj).length();
        }
        
-       void writeDivider(PrintWriter pw, int[] colWidths) {
+       boolean[] suppressNulls(DbDriver driver, RowBuffer rowBuf, Column[] cols)
+       {
+               boolean[] result = new boolean[cols.length];
+               
+               if (rowBuf.getPending() < 1) {
+                       // No data rows, so do not suppress any columns.
+                       for (int colIdx = 0; colIdx < cols.length; ++colIdx) {
+                               result[colIdx] = false;
+                       }
+                       return result;
+               }
+               
+               // Start with the assumption that we'll suppress all columns
+               for (int colIdx = 0; colIdx < cols.length; ++colIdx) {
+                       result[colIdx] = true;
+               }
+               
+               for (int rowIdx = 0; rowIdx < rowBuf.getPending(); ++rowIdx) {
+                       Row row = rowBuf.getRow(rowIdx);
+                       for (int colIdx = 1; colIdx <= cols.length; ++colIdx) {
+                               if (null != row.getValue(colIdx)) {
+                                       // This column has data, so do not suppress it
+                                       result[colIdx - 1] = false;
+                               }
+                       }
+               }
+               
+               return result;
+       }
+       
+       void writeDivider(PrintWriter pw, int[] colWidths, boolean[] suppressed) {
                for (int idx = 0; idx < colWidths.length; ++idx) {
-                       pw.print("+" + repChar('-', colWidths[idx] + 2));
+                       if (!suppressed[idx]) {
+                               pw.print("+" + repChar('-', colWidths[idx] + 2));
+                       }
                }
                pw.println("+");
        }
        
-       void writeHeader(PrintWriter pw, Column[] cols, int[] colWidths) {
-               writeDivider(pw, colWidths);
+       void writeHeader(PrintWriter pw, Column[] cols, int[] colWidths, boolean[] suppressed) {
+               writeDivider(pw, colWidths, suppressed);
 
                for (int idx = 0; idx < cols.length; ++idx) {
                        Column col = cols[idx];
@@ -299,19 +351,21 @@ abstract public class Tabular {
                }
                pw.println("|");
                
-               writeDivider(pw, colWidths);
+               writeDivider(pw, colWidths, suppressed);
        }
        
-       void writeRowBuffer(PrintWriter pw, RowBuffer rowBuf, int[] colWidths) throws SQLException {
+       void writeRowBuffer(PrintWriter pw, RowBuffer rowBuf, int[] colWidths, boolean[] suppressed) throws SQLException {
                
                for (int rowIdx = 0; rowIdx < rowBuf.getPending(); ++rowIdx) {
                        Row row = rowBuf.getRow(rowIdx);
                        for (int colIdx = 0; colIdx < colWidths.length; ++colIdx) {
-                               Object obj = row.getValue(colIdx + 1);
-                               String value = stringify(obj);
-                               int width = stringWidth(obj);
-                               String padding = repChar(' ', colWidths[colIdx] - width);
-                               pw.print("| " + value + padding + " ");
+                               if (!suppressed[colIdx]) {
+                                       Object obj = row.getValue(colIdx + 1);
+                                       String value = stringify(obj);
+                                       int width = stringWidth(obj);
+                                       String padding = repChar(' ', colWidths[colIdx] - width);
+                                       pw.print("| " + value + padding + " ");
+                               }
                        }
                        pw.println("|");
                }