Beispiel #1
0
  private static void installJar(String urlString, String jarName, boolean deploy, byte[] image)
      throws SQLException {
    assertJarName(jarName);

    if (getJarId(jarName, null) >= 0)
      throw new SQLException("A jar named '" + jarName + "' already exists", "46002");

    PreparedStatement stmt =
        SQLUtils.getDefaultConnection()
            .prepareStatement(
                "INSERT INTO sqlj.jar_repository(jarName, jarOrigin, jarOwner) VALUES(?, ?, ?)");
    try {
      stmt.setString(1, jarName);
      stmt.setString(2, urlString);
      stmt.setString(3, AclId.getSessionUser().getName());
      if (stmt.executeUpdate() != 1)
        throw new SQLException("Jar repository insert did not insert 1 row");
    } finally {
      SQLUtils.close(stmt);
    }

    AclId[] ownerRet = new AclId[1];
    int jarId = getJarId(jarName, ownerRet);
    if (jarId < 0) throw new SQLException("Unable to obtain id of '" + jarName + "'");

    if (image == null) Backend.addClassImages(jarId, urlString);
    else {
      InputStream imageStream = new ByteArrayInputStream(image);
      addClassImages(jarId, imageStream, image.length);
    }
    Loader.clearSchemaLoaders();
    if (deploy) deployInstall(jarId, jarName);
  }
Beispiel #2
0
  /**
   * Return the classpath that has been defined for the schema named <code>schemaName</code> This
   * method is exposed in SQL as <code>sqlj.get_classpath(VARCHAR)</code>.
   *
   * @param schemaName Name of the schema for which this path is valid.
   * @return The defined classpath or <code>null</code> if this schema has no classpath.
   * @throws SQLException
   */
  public static String getClassPath(String schemaName) throws SQLException {
    ResultSet rs = null;
    PreparedStatement stmt = null;
    try {
      if (schemaName == null || schemaName.length() == 0) schemaName = "public";
      else schemaName = schemaName.toLowerCase();

      stmt =
          SQLUtils.getDefaultConnection()
              .prepareStatement(
                  "SELECT r.jarName"
                      + " FROM sqlj.jar_repository r INNER JOIN sqlj.classpath_entry c ON r.jarId = c.jarId"
                      + " WHERE c.schemaName = ? ORDER BY c.ordinal");

      stmt.setString(1, schemaName);
      rs = stmt.executeQuery();
      StringBuffer buf = null;
      while (rs.next()) {
        if (buf == null) buf = new StringBuffer();
        else buf.append(':');
        buf.append(rs.getString(1));
      }
      return (buf == null) ? null : buf.toString();
    } finally {
      SQLUtils.close(rs);
      SQLUtils.close(stmt);
    }
  }
Beispiel #3
0
 private static SQLDeploymentDescriptor[] getDeploymentDescriptors(int jarId) throws SQLException {
   ResultSet rs = null;
   PreparedStatement stmt =
       SQLUtils.getDefaultConnection()
           .prepareStatement(
               "SELECT e.entryImage"
                   + " FROM sqlj.jar_descriptor d INNER JOIN sqlj.jar_entry e"
                   + "   ON d.entryId = e.entryId"
                   + " WHERE d.jarId = ?"
                   + " ORDER BY d.ordinal");
   try {
     stmt.setInt(1, jarId);
     rs = stmt.executeQuery();
     ArrayList<SQLDeploymentDescriptor> sdds = new ArrayList<SQLDeploymentDescriptor>();
     while (rs.next()) {
       byte[] bytes = rs.getBytes(1);
       // According to the SQLJ standard, this entry must be
       // UTF8 encoded.
       //
       sdds.add(new SQLDeploymentDescriptor(new String(bytes, "UTF8"), "postgresql"));
     }
     return sdds.toArray(new SQLDeploymentDescriptor[sdds.size()]);
   } catch (UnsupportedEncodingException e) {
     // Excuse me? No UTF8 encoding?
     //
     throw new SQLException("JVM does not support UTF8!!");
   } catch (ParseException e) {
     throw new SQLException(e.getMessage() + " at " + e.getErrorOffset());
   } finally {
     SQLUtils.close(rs);
     SQLUtils.close(stmt);
   }
 }
Beispiel #4
0
  /**
   * Removes the jar named <code>jarName</code> from the database jar repository. Class path entries
   * that references this jar will also be removed (just the entry, not the whole path). This method
   * is exposed in SQL as <code>sqlj.remove_jar(VARCHAR, BOOLEAN)</code>.
   *
   * @param jarName The name by which the system referes this jar.
   * @param undeploy If set, execute remove commands found in the deployment descriptor of the jar.
   * @throws SQLException if the named jar cannot be found in the repository.
   */
  public static void removeJar(String jarName, boolean undeploy) throws SQLException {
    assertJarName(jarName);
    AclId[] ownerRet = new AclId[1];
    int jarId = getJarId(jarName, ownerRet);
    if (jarId < 0)
      throw new SQLException("No Jar named '" + jarName + "' is known to the system", "4600B");

    AclId user = AclId.getSessionUser();
    if (!(user.isSuperuser() || user.equals(ownerRet[0])))
      throw new SecurityException("Only super user or owner can remove a jar");

    if (undeploy) deployRemove(jarId, jarName);

    PreparedStatement stmt =
        SQLUtils.getDefaultConnection()
            .prepareStatement("DELETE FROM sqlj.jar_repository WHERE jarId = ?");
    try {
      stmt.setInt(1, jarId);
      if (stmt.executeUpdate() != 1)
        throw new SQLException("Jar repository update did not update 1 row");
    } finally {
      SQLUtils.close(stmt);
    }
    Loader.clearSchemaLoaders();
  }
Beispiel #5
0
 /**
  * Returns the primary key identifier for the given Jar.
  *
  * @param conn The connection to use for the query.
  * @param jarName The name of the jar.
  * @return The primary key value of the given jar or <code>-1</code> if no such jar is found.
  * @throws SQLException
  */
 private static int getJarId(String jarName, AclId[] ownerRet) throws SQLException {
   PreparedStatement stmt =
       SQLUtils.getDefaultConnection()
           .prepareStatement("SELECT jarId, jarOwner FROM sqlj.jar_repository WHERE jarName = ?");
   try {
     return getJarId(stmt, jarName, ownerRet);
   } finally {
     SQLUtils.close(stmt);
   }
 }
Beispiel #6
0
 public static String getCurrentSchema() throws SQLException {
   Statement stmt = SQLUtils.getDefaultConnection().createStatement();
   ResultSet rs = null;
   try {
     rs = stmt.executeQuery("SELECT current_schema()");
     if (!rs.next()) throw new SQLException("Unable to obtain current schema");
     return rs.getString(1);
   } finally {
     SQLUtils.close(rs);
     SQLUtils.close(stmt);
   }
 }
Beispiel #7
0
 /**
  * Drops the mapping between an SQL type and a Java class.
  *
  * @param sqlTypeName The name of the SQL type. The name can be qualified with a schema
  *     (namespace). If the schema is omitted, it will be resolved according to the current setting
  *     of the <code>search_path</code>.
  * @throws SQLException
  */
 public static void dropTypeMapping(String sqlTypeName) throws SQLException {
   PreparedStatement stmt = null;
   try {
     sqlTypeName = getFullSqlName(sqlTypeName);
     stmt =
         SQLUtils.getDefaultConnection()
             .prepareStatement("DELETE FROM sqlj.typemap_entry WHERE sqlName = ?");
     stmt.setString(1, sqlTypeName);
     stmt.executeUpdate();
   } finally {
     SQLUtils.close(stmt);
   }
   Loader.clearSchemaLoaders();
 }
Beispiel #8
0
 /**
  * Returns the Oid for the given Schema.
  *
  * @param conn The connection to use for the query.
  * @param schemaName The name of the schema.
  * @return The Oid of the given schema or <code>null</code> if no such schema is found.
  * @throws SQLException
  */
 private static Oid getSchemaId(String schemaName) throws SQLException {
   ResultSet rs = null;
   PreparedStatement stmt =
       SQLUtils.getDefaultConnection()
           .prepareStatement("SELECT oid FROM pg_namespace WHERE nspname = ?");
   try {
     stmt.setString(1, schemaName);
     rs = stmt.executeQuery();
     if (!rs.next()) return null;
     return (Oid) rs.getObject(1);
   } finally {
     SQLUtils.close(rs);
     SQLUtils.close(stmt);
   }
 }
Beispiel #9
0
  private static void deployRemove(int jarId, String jarName) throws SQLException {
    SQLDeploymentDescriptor[] depDesc = getDeploymentDescriptors(jarId);

    String[] originalSchemaAndPath = new String[2];
    boolean classpathChanged = assertInPath(jarName, originalSchemaAndPath);
    for (int i = depDesc.length; i-- > 0; ) depDesc[i].remove(SQLUtils.getDefaultConnection());
    if (classpathChanged) setClassPath(originalSchemaAndPath[0], originalSchemaAndPath[1]);
  }
Beispiel #10
0
  private static void deployInstall(int jarId, String jarName) throws SQLException {
    SQLDeploymentDescriptor[] depDesc = getDeploymentDescriptors(jarId);

    String[] originalSchemaAndPath = new String[2];
    boolean classpathChanged = assertInPath(jarName, originalSchemaAndPath);
    for (SQLDeploymentDescriptor dd : depDesc) dd.install(SQLUtils.getDefaultConnection());
    if (classpathChanged) setClassPath(originalSchemaAndPath[0], originalSchemaAndPath[1]);
  }
Beispiel #11
0
  private static void replaceJar(String urlString, String jarName, boolean redeploy, byte[] image)
      throws SQLException {
    AclId[] ownerRet = new AclId[1];
    int jarId = getJarId(jarName, ownerRet);
    if (jarId < 0)
      throw new SQLException("No Jar named '" + jarName + "' is known to the system", "4600A");

    AclId user = AclId.getSessionUser();
    if (!(user.isSuperuser() || user.equals(ownerRet[0])))
      throw new SecurityException("Only super user or owner can replace a jar");

    if (redeploy) deployRemove(jarId, jarName);

    PreparedStatement stmt =
        SQLUtils.getDefaultConnection()
            .prepareStatement(
                "UPDATE sqlj.jar_repository "
                    + "SET jarOrigin = ?, jarOwner = ?, jarManifest = NULL "
                    + "WHERE jarId = ?");
    try {
      stmt.setString(1, urlString);
      stmt.setString(2, user.getName());
      stmt.setInt(3, jarId);
      if (stmt.executeUpdate() != 1)
        throw new SQLException("Jar repository update did not update 1 row");
    } finally {
      SQLUtils.close(stmt);
    }

    stmt =
        SQLUtils.getDefaultConnection()
            .prepareStatement("DELETE FROM sqlj.jar_entry WHERE jarId = ?");
    try {
      stmt.setInt(1, jarId);
      stmt.executeUpdate();
    } finally {
      SQLUtils.close(stmt);
    }
    if (image == null) Backend.addClassImages(jarId, urlString);
    else {
      InputStream imageStream = new ByteArrayInputStream(image);
      addClassImages(jarId, imageStream, image.length);
    }
    Loader.clearSchemaLoaders();
    if (redeploy) deployInstall(jarId, jarName);
  }
Beispiel #12
0
  private static String getFullSqlName(String sqlTypeName) throws SQLException {
    Oid typeId = Oid.forTypeName(sqlTypeName);
    s_logger.info("Type id = " + typeId.toString());

    ResultSet rs = null;
    PreparedStatement stmt =
        SQLUtils.getDefaultConnection()
            .prepareStatement(
                "SELECT n.nspname, t.typname FROM pg_type t, pg_namespace n"
                    + " WHERE t.oid = ? AND n.oid = t.typnamespace");

    try {
      stmt.setObject(1, typeId);
      rs = stmt.executeQuery();
      if (!rs.next()) throw new SQLException("Unable to obtain type info for " + typeId);

      return rs.getString(1) + '.' + rs.getString(2);
    } finally {
      SQLUtils.close(rs);
      SQLUtils.close(stmt);
    }
  }
Beispiel #13
0
  /**
   * Defines the mapping between an SQL type and a Java class.
   *
   * @param sqlTypeName The name of the SQL type. The name can be qualified with a schema
   *     (namespace). If the schema is omitted, it will be resolved according to the current setting
   *     of the <code>search_path</code>.
   * @param javaClassName The name of the class. The class must be found in the classpath in effect
   *     for the current schema
   * @throws SQLException
   */
  public static void addTypeMapping(String sqlTypeName, String javaClassName) throws SQLException {
    PreparedStatement stmt = null;
    try {
      ClassLoader loader = Loader.getCurrentLoader();
      Class cls = loader.loadClass(javaClassName);
      if (!SQLData.class.isAssignableFrom(cls))
        throw new SQLException("Class " + javaClassName + " does not implement java.sql.SQLData");

      sqlTypeName = getFullSqlName(sqlTypeName);
      stmt =
          SQLUtils.getDefaultConnection()
              .prepareStatement("INSERT INTO sqlj.typemap_entry(javaName, sqlName) VALUES(?,?)");
      stmt.setString(1, javaClassName);
      stmt.setString(2, sqlTypeName);
      stmt.executeUpdate();
    } catch (ClassNotFoundException e) {
      throw new SQLException("No such class: " + javaClassName);
    } finally {
      SQLUtils.close(stmt);
    }
    Loader.clearSchemaLoaders();
  }
Beispiel #14
0
 private static int getJarId(PreparedStatement stmt, String jarName, AclId[] ownerRet)
     throws SQLException {
   stmt.setString(1, jarName);
   ResultSet rs = stmt.executeQuery();
   try {
     if (!rs.next()) return -1;
     int id = rs.getInt(1);
     if (ownerRet != null) {
       String ownerName = rs.getString(2);
       ownerRet[0] = AclId.fromName(ownerName);
     }
     return id;
   } finally {
     SQLUtils.close(rs);
   }
 }
Beispiel #15
0
  /**
   * Define the class path to use for Java functions, triggers, and procedures that are created in
   * the schema named <code>schemaName</code> This method is exposed in SQL as <code>
   * sqlj.set_classpath(VARCHAR, VARCHAR)</code>.
   *
   * @param schemaName Name of the schema for which this path is valid.
   * @param path Colon separated list of names. Each name must denote the name of a jar that is
   *     present in the jar repository.
   * @throws SQLException If no schema can be found with the givene name, or if one or several names
   *     of the path denotes a nonexistant jar file.
   */
  public static void setClassPath(String schemaName, String path) throws SQLException {
    if (schemaName == null || schemaName.length() == 0) schemaName = "public";

    if ("public".equals(schemaName)) {
      if (!AclId.getSessionUser().isSuperuser())
        throw new SQLException(
            "Permission denied. Only a super user can set the classpath of the public schema");
    } else {
      schemaName = schemaName.toLowerCase();
      Oid schemaId = getSchemaId(schemaName);
      if (schemaId == null) throw new SQLException("No such schema: " + schemaName);
      if (!AclId.getSessionUser().hasSchemaCreatePermission(schemaId))
        throw new SQLException(
            "Permission denied. User must have create permission on the target schema in order to set the classpath");
    }

    PreparedStatement stmt;
    ArrayList entries = null;
    if (path != null && path.length() > 0) {
      // Collect and verify that all entries in the path represents a
      // valid jar
      //
      entries = new ArrayList();
      stmt =
          SQLUtils.getDefaultConnection()
              .prepareStatement("SELECT jarId FROM sqlj.jar_repository WHERE jarName = ?");
      try {
        for (; ; ) {
          int colon = path.indexOf(':');
          String jarName;
          if (colon >= 0) {
            jarName = path.substring(0, colon);
            path = path.substring(colon + 1);
          } else jarName = path;

          int jarId = getJarId(stmt, jarName, null);
          if (jarId < 0) throw new SQLException("No such jar: " + jarName);

          entries.add(new Integer(jarId));
          if (colon < 0) break;
        }
      } finally {
        SQLUtils.close(stmt);
      }
    }

    // Delete the old classpath
    //
    stmt =
        SQLUtils.getDefaultConnection()
            .prepareStatement("DELETE FROM sqlj.classpath_entry WHERE schemaName = ?");
    try {
      stmt.setString(1, schemaName);
      stmt.executeUpdate();
    } finally {
      SQLUtils.close(stmt);
    }

    if (entries != null) {
      // Insert the new path.
      //
      stmt =
          SQLUtils.getDefaultConnection()
              .prepareStatement(
                  "INSERT INTO sqlj.classpath_entry(schemaName, ordinal, jarId) VALUES(?, ?, ?)");
      try {
        int top = entries.size();
        for (int idx = 0; idx < top; ++idx) {
          int jarId = ((Integer) entries.get(idx)).intValue();
          stmt.setString(1, schemaName);
          stmt.setInt(2, idx + 1);
          stmt.setInt(3, jarId);
          stmt.executeUpdate();
        }
      } finally {
        SQLUtils.close(stmt);
      }
    }
    Loader.clearSchemaLoaders();
  }
Beispiel #16
0
  /**
   * Reads the jar found at the specified URL and stores the entries in the jar_entry table.
   *
   * @param jarId The id used for the foreign key to the jar_repository table
   * @param urlStream An InputStream (opened on what may have been a URL)
   * @param sz The expected size of the stream, used as a worst-case mark/reset limit. The caller
   *     might pass -1 if the URLConnection can't determine a size in advance (a generous guess will
   *     be made in that case).
   * @throws SQLException
   */
  public static void addClassImages(int jarId, InputStream urlStream, int sz) throws SQLException {
    PreparedStatement stmt = null;
    PreparedStatement descIdFetchStmt = null;
    PreparedStatement descIdStoreStmt = null;
    ResultSet rs = null;

    try {
      byte[] buf = new byte[1024];
      ByteArrayOutputStream img = new ByteArrayOutputStream();
      stmt =
          SQLUtils.getDefaultConnection()
              .prepareStatement(
                  "INSERT INTO sqlj.jar_entry(entryName, jarId, entryImage) VALUES(?, ?, ?)");

      BufferedInputStream bis = new BufferedInputStream(urlStream);
      String manifest = rawManifest(bis, sz);
      JarInputStream jis = new JarInputStream(bis);
      if (manifest != null) {
        PreparedStatement us =
            SQLUtils.getDefaultConnection()
                .prepareStatement("UPDATE sqlj.jar_repository SET jarManifest = ? WHERE jarId = ?");
        try {
          us.setString(1, manifest);
          us.setInt(2, jarId);
          if (us.executeUpdate() != 1)
            throw new SQLException("Jar repository update did not update 1 row");
        } finally {
          SQLUtils.close(us);
        }
      }

      for (; ; ) {
        JarEntry je = jis.getNextJarEntry();
        if (je == null) break;

        if (je.isDirectory()) continue;

        String entryName = je.getName();

        int nBytes;
        img.reset();
        while ((nBytes = jis.read(buf)) > 0) img.write(buf, 0, nBytes);
        jis.closeEntry();

        stmt.setString(1, entryName);
        stmt.setInt(2, jarId);
        stmt.setBytes(3, img.toByteArray());
        if (stmt.executeUpdate() != 1)
          throw new SQLException("Jar entry insert did not insert 1 row");
      }

      Matcher ddr = ddrSection.matcher(null != manifest ? manifest : "");
      Matcher cnt = mfCont.matcher("");
      for (int ordinal = 0; ddr.find(); ++ordinal) {
        String entryName = cnt.reset(ddr.group(1)).replaceAll("");
        if (descIdFetchStmt == null)
          descIdFetchStmt =
              SQLUtils.getDefaultConnection()
                  .prepareStatement(
                      "SELECT entryId FROM sqlj.jar_entry" + " WHERE jarId = ? AND entryName = ?");
        descIdFetchStmt.setInt(1, jarId);
        descIdFetchStmt.setString(2, entryName);
        rs = descIdFetchStmt.executeQuery();
        if (!rs.next()) throw new SQLException("Failed to refetch row in sqlj.jar_entry");

        int deployImageId = rs.getInt(1);

        if (descIdStoreStmt == null)
          descIdStoreStmt =
              SQLUtils.getDefaultConnection()
                  .prepareStatement(
                      "INSERT INTO sqlj.jar_descriptor"
                          + " (jarId, entryId, ordinal) VALUES"
                          + " ( ?, ?, ? )");
        descIdStoreStmt.setInt(1, jarId);
        descIdStoreStmt.setInt(2, deployImageId);
        descIdStoreStmt.setInt(3, ordinal);
        if (descIdStoreStmt.executeUpdate() != 1)
          throw new SQLException("Jar deployment descriptor insert did not insert " + "1 row");
      }
    } catch (IOException e) {
      throw new SQLException("I/O exception reading jar file: " + e.getMessage());
    } finally {
      SQLUtils.close(rs);
      SQLUtils.close(descIdStoreStmt);
      SQLUtils.close(descIdFetchStmt);
      SQLUtils.close(stmt);
    }
  }