📄 monetconnection.java
字号:
* Response look like: * <pre> * &1 1 28 2 10 * # name, value # name * # varchar, varchar # type * </pre> * there the first line consists out of<br /> * <tt>&"qt" "id" "tc" "cc" "rc"</tt>. */ // {{{ ResultSetResponse class implementation class ResultSetResponse implements Response { /** The number of columns in this result */ public final int columncount; /** The total number of rows this result set has */ public final int tuplecount; /** The numbers of rows to retrieve per DataBlockResponse */ private int cacheSize; /** The table ID of this result */ public final int id; /** The names of the columns in this result */ private String[] name; /** The types of the columns in this result */ private String[] type; /** The max string length for each column in this result */ private int[] columnLengths; /** The table for each column in this result */ private String[] tableNames; /** The query sequence number */ private final int seqnr; /** A List of result blocks (chunks of size fetchSize/cacheSize) */ private DataBlockResponse[] resultBlocks; /** A bitmap telling whether the headers are set or not */ private boolean[] isSet; /** Whether this Response is closed */ private boolean closed; /** The Connection that we should use when requesting a new block */ private MonetConnection.ResponseList parent; /** Whether the fetchSize was explitly set by the user */ private boolean cacheSizeSetExplicitly = false; /** Whether we should send an Xclose command to the server * if we close this Response */ private boolean destroyOnClose; /** the offset to be used on Xexport queries */ private int blockOffset = 0; private final static int NAMES = 0; private final static int TYPES = 1; private final static int TABLES = 2; private final static int LENS = 3; /** * Sole constructor, which requires a MonetConnection parent to * be given. * * @param id the ID of the result set * @param tuplecount the total number of tuples in the result set * @param columncount the number of columns in the result set * @param rowcount the number of rows in the current block * @param parent the parent that created this Response and will * supply new result blocks when necessary * @param seq the query sequence number */ ResultSetResponse( int id, int tuplecount, int columncount, int rowcount, MonetConnection.ResponseList parent, int seq) throws SQLException { isSet = new boolean[7]; this.parent = parent; if (parent.cachesize == 0) { cacheSize = MonetConnection.DEF_FETCHSIZE; cacheSizeSetExplicitly = false; } else { cacheSize = parent.cachesize; cacheSizeSetExplicitly = true; } seqnr = seq; closed = false; destroyOnClose = false; this.id = id; this.tuplecount = tuplecount; this.columncount = columncount; this.resultBlocks = new DataBlockResponse[(tuplecount / cacheSize) + 1]; resultBlocks[0] = new DataBlockResponse( rowcount, parent.rstype == ResultSet.TYPE_FORWARD_ONLY ); } /** * Parses the given string and changes the value of the matching * header appropriately, or passes it on to the underlying * DataResponse. * * @param tmpLine the string that contains the header * @return a non-null String if the header cannot be parsed or * is unknown */ // {{{ addLine public String addLine(String tmpLine, int linetype) { if (isSet[LENS] && isSet[TYPES] && isSet[TABLES] && isSet[NAMES]) { return(resultBlocks[0].addLine(tmpLine, linetype)); } if (linetype != MonetSocketBlockMode.HEADER) return("header expected, got: " + tmpLine); char[] chrLine = tmpLine.toCharArray(); int len = chrLine.length; int pos = 0; boolean foundChar = false; boolean nameFound = false; // find header name for (int i = len - 1; i >= 0; i--) { switch (chrLine[i]) { case ' ': case '\n': case '\t': case '\r': if (!foundChar) { len = i - 1; } else { pos = i + 1; } break; case '#': // found! nameFound = true; if (pos == 0) pos = i + 1; i = 0; // force the loop to terminate break; default: foundChar = true; pos = 0; break; } } if (!nameFound) return("illegal header: " + tmpLine); // depending on the name of the header, we continue switch (chrLine[pos]) { default: return("protocol violation: unknown header: " + (new String(chrLine, pos, len - pos))); case 'n': if (len - pos == 4 && tmpLine.regionMatches(pos + 1, "name", 1, 3)) { name = getValues(chrLine, 2, pos - 3); isSet[NAMES] = true; } else { return("protocol violation: unknown header: " + (new String(chrLine, pos, len - pos))); } break; case 'l': if (len - pos == 6 && tmpLine.regionMatches(pos + 1, "length", 1, 5)) { try { columnLengths = getIntValues(chrLine, 2, pos - 3); isSet[LENS] = true; } catch (SQLException e) { return(e.getMessage()); } } else { return("protocol violation: unknown header: " + (new String(chrLine, pos, len - pos))); } break; case 't': if (len - pos == 4 && tmpLine.regionMatches(pos + 1, "type", 1, 3)) { type = getValues(chrLine, 2, pos - 3); isSet[TYPES] = true; } else if (len - pos == 10 && tmpLine.regionMatches(pos + 1, "table_name", 1, 9)) { tableNames = getValues(chrLine, 2, pos - 3); isSet[TABLES] = true; } else { return("protocol violation: unknown header: " + (new String(chrLine, pos, len - pos))); } break; } // all is well return(null); } // }}} /** * Returns whether this ResultSetResponse needs more lines. * This method returns true if not all headers are set, or the * first DataBlockResponse reports to want more. */ public boolean wantsMore() { if (isSet[LENS] && isSet[TYPES] && isSet[TABLES] && isSet[NAMES]) { return(resultBlocks[0].wantsMore()); } else { return(true); } } /** * Returns an array of Strings containing the values between * ',\t' separators. * * @param chrLine a character array holding the input data * @param start where the relevant data starts * @param stop where the relevant data stops * @return an array of Strings */ final private String[] getValues(char[] chrLine, int start, int stop) { int elem = 0; String[] values = new String[columncount]; for (int i = start; i < stop; i++) { if (chrLine[i] == '\t' && chrLine[i - 1] == ',') { values[elem++] = new String(chrLine, start, i - 1 - start); start = i + 1; } } // at the left over part values[elem++] = new String(chrLine, start, stop - start); return(values); } /** * Returns an array of ints containing the values between * ',\t' separators. * * @param chrLine a character array holding the input data * @param start where the relevant data starts * @param stop where the relevant data stops * @return an array of ints */ final private int[] getIntValues( char[] chrLine, int start, int stop ) throws SQLException { int elem = 0; int tmp = 0; int[] values = new int[columncount]; try { for (int i = start; i < stop; i++) { if (chrLine[i] == ',' && chrLine[i + 1] == '\t') { values[elem++] = tmp; tmp = 0; start = ++i; } else { tmp *= 10; tmp += MonetResultSet.getIntrinsicValue(chrLine[i], i); } } // at the left over part values[elem++] = tmp; } catch (java.text.ParseException e) { throw new SQLException(e.getMessage() + " found: '" + chrLine[e.getErrorOffset()] + "'" + " in: " + new String(chrLine) + " at pos: " + e.getErrorOffset()); } return(values); } /** * Returns an the first String that appears before the first * occurrence of the ',\t' separator. * * @param chrLine a character array holding the input data * @param start where the relevant data starts * @param stop where the relevant data stops * @return the first String found */ private final String getValue(char[] chrLine, int start, int stop) { for (int i = start; i < stop; i++) { if (chrLine[i] == '\t' && chrLine[i - 1] == ',') { return(new String(chrLine, start, i - 1 - start)); } } return(new String(chrLine, start, stop - start)); } /** * Adds the given DataBlockResponse to this ResultSetResponse at * the given block position. * * @param offset the offset number of rows for this block * @param rr the DataBlockResponse to add */ void addDataBlockResponse(int offset, DataBlockResponse rr) { int block = (offset - blockOffset) / cacheSize; resultBlocks[block] = rr; } /** * Marks this Response as being completed. A complete Response * needs to be consistent with regard to its internal data. * * @throws SQLException if the data currently in this Response is not * sufficient to be consistant */ public void complete() throws SQLException { String error = ""; if (!isSet[NAMES]) error += "name header missing\n"; if (!isSet[TYPES]) error += "type header missing\n"; if (!isSet[TABLES]) error += "table name header missing\n"; if (!isSet[LENS]) error += "column width header missing\n"; if (error != "") throw new SQLException(error); } /** * Returns the names of the columns * * @return the names of the columns */ String[] getNames() { return(name); } /** * Returns the types of the columns * * @return the types of the columns */ String[] getTypes() { return(type); } /** * Returns the tables of the columns * * @return the tables of the columns */ String[] getTableNames() { return(tableNames); } /** * Returns the lengths of the columns * * @return the lengths of the columns */ int[] getColumnLengths() { return(columnLengths); } /** * Returns the cache size used within this Response * * @return the cache size */ int getCacheSize() { return(cacheSize); } /** * Returns the current block offset * * @return the current block offset */ int getBlockOffset() { return(blockOffset); } /** * Returns the ResultSet type, FORWARD_ONLY or not. * * @return the ResultSet type */ int getRSType() { return(parent.rstype); } /** * Returns the concurrency of the ResultSet. * * @return the ResultSet concurrency */ int getRSConcur() { return(parent.rsconcur); } /** * Returns a line from the cache. If the line is already present in the * cache, it is returned, if not apropriate actions are taken to make * sure the right block is being fetched and as soon as the requested * line is fetched it is returned. * * @param row the row in the result set to return
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -