Example #1
0
 @Override
 public void close() {
   RuntimeException closeError = null;
   if (transferList != null) {
     synchronized (this) {
       for (Transfer transfer : transferList) {
         try {
           traceOperation("SESSION_CLOSE", 0);
           transfer.writeInt(SessionRemote.SESSION_CLOSE);
           done(transfer);
           transfer.close();
         } catch (RuntimeException e) {
           trace.error(e, "close");
           closeError = e;
         } catch (Exception e) {
           trace.error(e, "close");
         }
       }
     }
     transferList = null;
   }
   traceSystem.close();
   if (embedded != null) {
     embedded.close();
     embedded = null;
   }
   if (closeError != null) {
     throw closeError;
   }
 }
Example #2
0
 private void sendError(Throwable t) {
   try {
     SQLException e = DbException.convert(t).getSQLException();
     StringWriter writer = new StringWriter();
     e.printStackTrace(new PrintWriter(writer));
     String trace = writer.toString();
     String message;
     String sql;
     if (e instanceof JdbcSQLException) {
       JdbcSQLException j = (JdbcSQLException) e;
       message = j.getOriginalMessage();
       sql = j.getSQL();
     } else {
       message = e.getMessage();
       sql = null;
     }
     transfer
         .writeInt(SessionRemote.STATUS_ERROR)
         .writeString(e.getSQLState())
         .writeString(message)
         .writeString(sql)
         .writeInt(e.getErrorCode())
         .writeString(trace)
         .flush();
   } catch (Exception e2) {
     if (!transfer.isClosed()) {
       server.traceError(e2);
     }
     // if writing the error does not work, close the connection
     stop = true;
   }
 }
Example #3
0
 private void setAutoCommitSend(boolean autoCommit) {
   if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_8) {
     for (int i = 0, count = 0; i < transferList.size(); i++) {
       Transfer transfer = transferList.get(i);
       try {
         traceOperation("SESSION_SET_AUTOCOMMIT", autoCommit ? 1 : 0);
         transfer.writeInt(SessionRemote.SESSION_SET_AUTOCOMMIT).writeBoolean(autoCommit);
         done(transfer);
       } catch (IOException e) {
         removeServer(e, i--, ++count);
       }
     }
   } else {
     if (autoCommit) {
       if (autoCommitTrue == null) {
         autoCommitTrue = prepareCommand("SET AUTOCOMMIT TRUE", Integer.MAX_VALUE);
       }
       autoCommitTrue.executeUpdate();
     } else {
       if (autoCommitFalse == null) {
         autoCommitFalse = prepareCommand("SET AUTOCOMMIT FALSE", Integer.MAX_VALUE);
       }
       autoCommitFalse.executeUpdate();
     }
   }
 }
Example #4
0
 private void setParameters(Command command) throws IOException {
   int len = transfer.readInt();
   ArrayList<? extends ParameterInterface> params = command.getParameters();
   for (int i = 0; i < len; i++) {
     Parameter p = (Parameter) params.get(i);
     p.setValue(transfer.readValue());
   }
 }
Example #5
0
 @Override
 public ArrayList<String> getClusterServers() {
   ArrayList<String> serverList = new ArrayList<String>();
   for (int i = 0; i < transferList.size(); i++) {
     Transfer transfer = transferList.get(i);
     serverList.add(
         transfer.getSocket().getInetAddress().getHostAddress()
             + ":"
             + transfer.getSocket().getPort());
   }
   return serverList;
 }
Example #6
0
 @Override
 public synchronized int readLob(
     long lobId, byte[] hmac, long offset, byte[] buff, int off, int length) {
   for (int i = 0, count = 0; i < transferList.size(); i++) {
     Transfer transfer = transferList.get(i);
     try {
       traceOperation("LOB_READ", (int) lobId);
       transfer.writeInt(SessionRemote.LOB_READ);
       transfer.writeLong(lobId);
       if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_12) {
         transfer.writeBytes(hmac);
       }
       transfer.writeLong(offset);
       transfer.writeInt(length);
       done(transfer);
       length = transfer.readInt();
       if (length <= 0) {
         return length;
       }
       transfer.readBytes(buff, off, length);
       return length;
     } catch (IOException e) {
       removeServer(e, i--, ++count);
     }
   }
   return 1;
 }
Example #7
0
 private void sendRow(ResultInterface result) throws IOException {
   if (result.next()) {
     transfer.writeBoolean(true);
     Value[] v = result.currentRow();
     for (int i = 0; i < result.getVisibleColumnCount(); i++) {
       if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_12) {
         transfer.writeValue(v[i]);
       } else {
         writeValue(v[i]);
       }
     }
   } else {
     transfer.writeBoolean(false);
   }
 }
Example #8
0
 /** Calls COMMIT if the session is in cluster mode. */
 public void autoCommitIfCluster() {
   if (autoCommit && cluster) {
     // server side auto commit is off because of race conditions
     // (update set id=1 where id=0, but update set id=2 where id=0 is
     // faster)
     for (int i = 0, count = 0; i < transferList.size(); i++) {
       Transfer transfer = transferList.get(i);
       try {
         traceOperation("COMMAND_COMMIT", 0);
         transfer.writeInt(SessionRemote.COMMAND_COMMIT);
         done(transfer);
       } catch (IOException e) {
         removeServer(e, i--, ++count);
       }
     }
   }
 }
Example #9
0
 /**
  * Called to flush the output after data has been sent to the server and just before receiving
  * data. This method also reads the status code from the server and throws any exception the
  * server sent.
  *
  * @param transfer the transfer object
  * @throws DbException if the server sent an exception
  * @throws IOException if there is a communication problem between client and server
  */
 public void done(Transfer transfer) throws IOException {
   transfer.flush();
   int status = transfer.readInt();
   if (status == STATUS_ERROR) {
     String sqlstate = transfer.readString();
     String message = transfer.readString();
     String sql = transfer.readString();
     int errorCode = transfer.readInt();
     String stackTrace = transfer.readString();
     JdbcSQLException s =
         new JdbcSQLException(message, sql, sqlstate, errorCode, null, stackTrace);
     if (errorCode == ErrorCode.CONNECTION_BROKEN_1) {
       // allow re-connect
       IOException e = new IOException(s.toString(), s);
       throw e;
     }
     throw DbException.convert(s);
   } else if (status == STATUS_CLOSED) {
     transferList = null;
   } else if (status == STATUS_OK_STATE_CHANGED) {
     sessionStateChanged = true;
   } else if (status == STATUS_OK) {
     // ok
   } else {
     throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "unexpected status " + status);
   }
 }
Example #10
0
 @Override
 public boolean hasPendingTransaction() {
   if (clientVersion < Constants.TCP_PROTOCOL_VERSION_10) {
     return true;
   }
   for (int i = 0, count = 0; i < transferList.size(); i++) {
     Transfer transfer = transferList.get(i);
     try {
       traceOperation("SESSION_HAS_PENDING_TRANSACTION", 0);
       transfer.writeInt(SessionRemote.SESSION_HAS_PENDING_TRANSACTION);
       done(transfer);
       return transfer.readInt() != 0;
     } catch (IOException e) {
       removeServer(e, i--, ++count);
     }
   }
   return true;
 }
Example #11
0
 /**
  * Cancel the statement with the given id.
  *
  * @param id the statement id
  */
 public void cancelStatement(int id) {
   for (Transfer transfer : transferList) {
     try {
       Transfer trans = transfer.openNewConnection();
       trans.init();
       trans.writeInt(clientVersion);
       trans.writeInt(clientVersion);
       trans.writeString(null);
       trans.writeString(null);
       trans.writeString(sessionId);
       trans.writeInt(SessionRemote.SESSION_CANCEL_STATEMENT);
       trans.writeInt(id);
       trans.close();
     } catch (IOException e) {
       trace.debug(e, "could not cancel statement");
     }
   }
 }
Example #12
0
 private void writeValue(Value v) throws IOException {
   if (v.getType() == Value.CLOB || v.getType() == Value.BLOB) {
     if (v instanceof ValueLobDb) {
       ValueLobDb lob = (ValueLobDb) v;
       if (lob.isStored()) {
         long id = lob.getLobId();
         lobs.put(id, new CachedInputStream(null));
       }
     }
   }
   transfer.writeValue(v);
 }
Example #13
0
 /** Close a connection. */
 void close() {
   try {
     stop = true;
     closeSession();
   } catch (Exception e) {
     server.traceError(e);
   } finally {
     transfer.close();
     trace("Close");
     server.remove(this);
   }
 }
Example #14
0
 // 总共18条命令,这里包含16条
 // 下面这两条在run方法中特殊处理
 // SESSION_CANCEL_STATEMENT
 // SESSION_CHECK_KEY
 // 分三种级别,从大到小: SESSION级、COMMAND级、RESULT级
 private void process() throws IOException {
   int operation = transfer.readInt();
   switch (operation) {
     case SessionRemote.SESSION_PREPARE_READ_PARAMS:
     case SessionRemote.SESSION_PREPARE:
       {
         int id = transfer.readInt();
         String sql = transfer.readString();
         int old = session.getModificationId();
         Command command = session.prepareLocal(sql);
         boolean readonly = command.isReadOnly();
         cache.addObject(id, command);
         boolean isQuery = command.isQuery();
         ArrayList<? extends ParameterInterface> params = command.getParameters();
         transfer
             .writeInt(getState(old))
             .writeBoolean(isQuery)
             .writeBoolean(readonly)
             .writeInt(params.size());
         if (operation == SessionRemote.SESSION_PREPARE_READ_PARAMS) {
           for (ParameterInterface p : params) {
             ParameterRemote.writeMetaData(transfer, p);
           }
         }
         transfer.flush();
         break;
       }
     case SessionRemote.SESSION_CLOSE:
       {
         stop = true;
         closeSession();
         transfer.writeInt(SessionRemote.STATUS_OK).flush();
         close();
         break;
       }
     case SessionRemote.COMMAND_COMMIT:
       {
         // 并不是通过org.h2.jdbc.JdbcConnection.commit()触发,此方法是通过发送COMMIT SQL触发
         // 触发SessionRemote.COMMAND_COMMIT的是在集群环境下,通过org.h2.engine.SessionRemote.autoCommitIfCluster()触发
         if (commit == null) {
           commit = session.prepareLocal("COMMIT");
         }
         int old = session.getModificationId();
         commit.executeUpdate();
         transfer.writeInt(getState(old)).flush();
         break;
       }
     case SessionRemote.COMMAND_GET_META_DATA:
       {
         int id = transfer.readInt();
         int objectId = transfer.readInt();
         Command command = (Command) cache.getObject(id, false);
         ResultInterface result = command.getMetaData();
         cache.addObject(objectId, result);
         int columnCount = result.getVisibleColumnCount();
         transfer.writeInt(SessionRemote.STATUS_OK).writeInt(columnCount).writeInt(0);
         for (int i = 0; i < columnCount; i++) {
           ResultColumn.writeColumn(transfer, result, i);
         }
         transfer.flush();
         break;
       }
     case SessionRemote.COMMAND_EXECUTE_QUERY:
       {
         int id = transfer.readInt();
         int objectId = transfer.readInt();
         int maxRows = transfer.readInt();
         int fetchSize = transfer.readInt();
         Command command = (Command) cache.getObject(id, false);
         setParameters(command);
         int old = session.getModificationId();
         ResultInterface result;
         synchronized (session) {
           result = command.executeQuery(maxRows, false);
         }
         cache.addObject(objectId, result);
         int columnCount = result.getVisibleColumnCount();
         int state = getState(old);
         transfer.writeInt(state).writeInt(columnCount);
         int rowCount = result.getRowCount();
         transfer.writeInt(rowCount);
         for (int i = 0; i < columnCount; i++) {
           ResultColumn.writeColumn(transfer, result, i);
         }
         int fetch = Math.min(rowCount, fetchSize);
         for (int i = 0; i < fetch; i++) {
           sendRow(result);
         }
         transfer.flush();
         break;
       }
     case SessionRemote.COMMAND_EXECUTE_UPDATE:
       {
         int id = transfer.readInt();
         Command command = (Command) cache.getObject(id, false);
         // if(command!=null)throw new Error();
         setParameters(command);
         int old = session.getModificationId();
         int updateCount;
         synchronized (session) {
           updateCount = command.executeUpdate();
         }
         int status;
         if (session.isClosed()) {
           status = SessionRemote.STATUS_CLOSED;
         } else {
           status = getState(old);
         }
         transfer.writeInt(status).writeInt(updateCount).writeBoolean(session.getAutoCommit());
         transfer.flush();
         break;
       }
     case SessionRemote.COMMAND_CLOSE:
       {
         int id = transfer.readInt();
         Command command = (Command) cache.getObject(id, true);
         if (command != null) {
           command.close();
           cache.freeObject(id);
         }
         break;
       }
     case SessionRemote.RESULT_FETCH_ROWS:
       {
         int id = transfer.readInt();
         int count = transfer.readInt();
         ResultInterface result = (ResultInterface) cache.getObject(id, false);
         transfer.writeInt(SessionRemote.STATUS_OK);
         for (int i = 0; i < count; i++) {
           sendRow(result);
         }
         transfer.flush();
         break;
       }
     case SessionRemote.RESULT_RESET:
       {
         int id = transfer.readInt();
         ResultInterface result = (ResultInterface) cache.getObject(id, false);
         result.reset();
         break;
       }
     case SessionRemote.RESULT_CLOSE:
       {
         int id = transfer.readInt();
         ResultInterface result = (ResultInterface) cache.getObject(id, true);
         if (result != null) {
           result.close();
           cache.freeObject(id);
         }
         break;
       }
     case SessionRemote.CHANGE_ID:
       {
         int oldId = transfer.readInt();
         int newId = transfer.readInt();
         Object obj = cache.getObject(oldId, false);
         cache.freeObject(oldId);
         cache.addObject(newId, obj);
         break;
       }
     case SessionRemote.SESSION_SET_ID:
       {
         sessionId = transfer.readString();
         transfer.writeInt(SessionRemote.STATUS_OK).flush();
         break;
       }
     case SessionRemote.SESSION_SET_AUTOCOMMIT:
       {
         boolean autoCommit = transfer.readBoolean();
         session.setAutoCommit(autoCommit);
         transfer.writeInt(SessionRemote.STATUS_OK).flush();
         break;
       }
     case SessionRemote.SESSION_HAS_PENDING_TRANSACTION:
       {
         transfer
             .writeInt(SessionRemote.STATUS_OK)
             .writeInt(session.hasPendingTransaction() ? 1 : 0)
             .flush();
         break;
       }
     case SessionRemote.LOB_READ:
       {
         long lobId = transfer.readLong();
         byte[] hmac;
         CachedInputStream in;
         boolean verifyMac;
         if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_11) {
           if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_12) {
             hmac = transfer.readBytes();
             verifyMac = true;
           } else {
             hmac = null;
             verifyMac = false;
           }
           in = lobs.get(lobId);
           if (in == null && verifyMac) {
             in = new CachedInputStream(null);
             lobs.put(lobId, in);
           }
         } else {
           verifyMac = false;
           hmac = null;
           in = lobs.get(lobId);
         }
         long offset = transfer.readLong();
         int length = transfer.readInt();
         if (verifyMac) {
           transfer.verifyLobMac(hmac, lobId);
         }
         if (in == null) {
           throw DbException.get(ErrorCode.OBJECT_CLOSED);
         }
         if (in.getPos() != offset) {
           LobStorageInterface lobStorage = session.getDataHandler().getLobStorage();
           InputStream lobIn = lobStorage.getInputStream(lobId, hmac, -1);
           in = new CachedInputStream(lobIn);
           lobs.put(lobId, in);
           lobIn.skip(offset);
         }
         // limit the buffer size
         length = Math.min(16 * Constants.IO_BUFFER_SIZE, length);
         byte[] buff = new byte[length];
         length = IOUtils.readFully(in, buff, 0, length);
         transfer.writeInt(SessionRemote.STATUS_OK);
         transfer.writeInt(length);
         transfer.writeBytes(buff, 0, length);
         transfer.flush();
         break;
       }
     default:
       trace("Unknown operation: " + operation);
       closeSession();
       close();
   }
 }
Example #15
0
 TcpServerThread(Socket socket, TcpServer server, int id) {
   this.server = server;
   this.threadId = id;
   transfer = new Transfer(null);
   transfer.setSocket(socket);
 }
Example #16
0
  @Override
  public void run() {
    try {
      transfer.init();
      trace("Connect");
      // TODO server: should support a list of allowed databases
      // and a list of allowed clients
      try {
        // 如果没有加-tcpAllowOthers参数,那么只接受本地连接
        if (!server.allow(transfer.getSocket())) {
          throw DbException.get(ErrorCode.REMOTE_CONNECTION_NOT_ALLOWED);
        }
        int minClientVersion = transfer.readInt();
        if (minClientVersion < Constants.TCP_PROTOCOL_VERSION_6) {
          throw DbException.get(
              ErrorCode.DRIVER_VERSION_ERROR_2,
              "" + clientVersion,
              "" + Constants.TCP_PROTOCOL_VERSION_6);
        } else if (minClientVersion > Constants.TCP_PROTOCOL_VERSION_12) {
          throw DbException.get(
              ErrorCode.DRIVER_VERSION_ERROR_2,
              "" + clientVersion,
              "" + Constants.TCP_PROTOCOL_VERSION_12);
        }
        int maxClientVersion = transfer.readInt();
        if (maxClientVersion >= Constants.TCP_PROTOCOL_VERSION_12) {
          clientVersion = Constants.TCP_PROTOCOL_VERSION_12;
        } else {
          clientVersion = minClientVersion;
        }
        transfer.setVersion(clientVersion);
        String db = transfer.readString();
        String originalURL = transfer.readString();
        if (db == null && originalURL == null) {
          String targetSessionId = transfer.readString();
          int command = transfer.readInt();
          stop = true;
          if (command == SessionRemote.SESSION_CANCEL_STATEMENT) {
            // cancel a running statement
            int statementId = transfer.readInt();
            server.cancelStatement(targetSessionId, statementId);
          } else if (command == SessionRemote.SESSION_CHECK_KEY) {
            // check if this is the correct server
            db = server.checkKeyAndGetDatabaseName(targetSessionId);
            if (!targetSessionId.equals(db)) {
              transfer.writeInt(SessionRemote.STATUS_OK);
            } else {
              transfer.writeInt(SessionRemote.STATUS_ERROR);
            }
          }
        }
        // 启动TcpServer时加"-baseDir"或者像这样System.setProperty("h2.baseDir", "E:\\H2\\baseDir")
        String baseDir = server.getBaseDir();
        if (baseDir == null) {
          baseDir = SysProperties.getBaseDir();
        }
        // 例如启动TcpServer时,指定了"-key mydb mydatabase",
        // 如果db变量是mydb,那么实际上就是mydatabase,相当于做一次映射
        // 如果db变量不是mydb,那么抛错: org.h2.jdbc.JdbcSQLException: Wrong user name or password [28000-170]
        db = server.checkKeyAndGetDatabaseName(db);
        ConnectionInfo ci = new ConnectionInfo(db);

        ci.setOriginalURL(originalURL);
        ci.setUserName(transfer.readString());
        // password参数的值已经转换成userPasswordHash和filePasswordHash了,
        // 不能由userPasswordHash和filePasswordHash得到原始的password
        ci.setUserPasswordHash(transfer.readBytes());
        ci.setFilePasswordHash(transfer.readBytes()); // 只有指定"CIPHER"参数时filePasswordHash才是非null的
        int len = transfer.readInt();
        for (int i = 0; i < len; i++) {
          ci.setProperty(transfer.readString(), transfer.readString());
        }
        // override client's requested properties with server settings
        if (baseDir != null) {
          ci.setBaseDir(baseDir);
        }
        if (server.getIfExists()) {
          // 启动TcpServer时加"-ifExists",限制只有数据库存在时客户端才能连接,也就是不允许在客户端创建数据库
          ci.setProperty("IFEXISTS", "TRUE");
        }
        session = Engine.getInstance().createSession(ci);
        transfer.setSession(session);
        transfer.writeInt(SessionRemote.STATUS_OK);
        transfer.writeInt(clientVersion);
        transfer.flush();
        // 每建立一个新的Session对象时,把它保存到内存数据库management_db_9092的SESSIONS表
        server.addConnection(threadId, originalURL, ci.getUserName());
        trace("Connected");
      } catch (Throwable e) {
        sendError(e);
        stop = true;
      }
      while (!stop) {
        try {
          process();
        } catch (Throwable e) {
          sendError(e);
        }
      }
      trace("Disconnect");
    } catch (Throwable e) {
      server.traceError(e);
    } finally {
      close();
    }
  }
Example #17
0
 private Transfer initTransfer(ConnectionInfo ci, String db, String server) throws IOException {
   Socket socket = NetUtils.createSocket(server, Constants.DEFAULT_TCP_PORT, ci.isSSL());
   Transfer trans = new Transfer(this);
   trans.setSocket(socket);
   trans.setSSL(ci.isSSL());
   trans.init();
   trans.writeInt(Constants.TCP_PROTOCOL_VERSION_6);
   trans.writeInt(Constants.TCP_PROTOCOL_VERSION_15);
   trans.writeString(db);
   trans.writeString(ci.getOriginalURL());
   trans.writeString(ci.getUserName());
   trans.writeBytes(ci.getUserPasswordHash());
   trans.writeBytes(ci.getFilePasswordHash());
   String[] keys = ci.getKeys();
   trans.writeInt(keys.length);
   for (String key : keys) {
     trans.writeString(key).writeString(ci.getProperty(key));
   }
   try {
     done(trans);
     clientVersion = trans.readInt();
     trans.setVersion(clientVersion);
     if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_14) {
       if (ci.getFileEncryptionKey() != null) {
         trans.writeBytes(ci.getFileEncryptionKey());
       }
     }
     trans.writeInt(SessionRemote.SESSION_SET_ID);
     trans.writeString(sessionId);
     done(trans);
     if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_15) {
       autoCommit = trans.readBoolean();
     } else {
       autoCommit = true;
     }
     return trans;
   } catch (DbException e) {
     trans.close();
     throw e;
   }
 }