当 table 和列存在时,为什么 uCanAccess 无法执行查询并出现错误“用户缺乏权限或找不到对象”?

Why does uCanAccess fail to execute query with error `user lacks privilege or object not found` when table and column exist?

我有一个数据库,里面有很多table个,如下三个:

Controllers_Readers
-------------------
ControllerID: Number (Long Integer), Default 0, Indexed (Y, no Duplicated)
ReaderID: Number (Long Integer), Default 0, Indexed (Y, No Duplicates)

Controllers
-----------
ControllerID: Number (Long Integer), Default 0, Indexed (Y, No Duplicates)
Description: Short Text (32)
Name: Short Text (32)
...

Readers
-------
ReaderID: Number (Long Integer), Default 0, Indexed (Y, No Duplicates)
Direction: Number (Long Integer)
Description: Short Text (32)
Name: Short Text (32)
...

我有以下 Java 代码来检查 table 是否存在以及它是否包含特定列,基于 :

/* Use the metadata to check if a table exists and has a specific column */
  public static boolean tableHasColumn(Connection con, String tableName, String colName)
    throws ClassNotFoundException, SQLException, InstantiationException,
    IllegalAccessException 
  {
    boolean exists = false, hasCol = false;

    ResultSet rs = null, r = null;
    Statement s = null;

    try {
      DatabaseMetaData dbm = con.getMetaData();
      rs = dbm.getTables(null, null, tableName, null);
      if (rs.next() && rs.getRow() > -1) {
        exists = true;
        s = con.createStatement();
        r = s.executeQuery("SELECT * FROM " + tableName + " LIMIT 1");
        if (r.next()) {
          ResultSetMetaData rsmd = r.getMetaData();
          for (int col = 1; col < rsmd.getColumnCount(); col++) {
            String name = rsmd.getColumnName(col);
            logger.debug("Found column \"" + name + "\" in \"" + tableName + "\".");
            if (name.equals(colName)) {
              hasCol = true;
              break;
            }
          }
        }
      }
    } finally {
      if (null != rs) {
        try {
          rs.close();
        } catch (SQLException ex) {
          logger.warn(
            "Failed to close Resultset to DB while checking if table exists!"
          );
        }
      }
    }
    logger.debug(
      "Table (" + tableName + ") Exists: " + String.valueOf(exists).toUpperCase()
      + "\tHas Column (" + colName + "): " + String.valueOf(hasCol).toUpperCase()
    );

    return (exists && hasCol);
  }

分别为 tableNamecolName 提供 "Controllers_Readers""ControllerID" 的值,导致 return 值为 true。但是,当我 运行 以下查询时,我收到一条错误消息 org.hsqldb.HsqlException: user lacks privilege or object not found: CONTROLLERS_READERS.CONTROLLERID :

SELECT C.Description AS cName, C.ControllerID AS CID,
  D.DirectionText as dName, D.Direction AS dirNum, R.Description AS rName,
  R.ReaderID AS RID, AP.Name AS aName, AP.Description as aDescrip, AP.PointID
FROM Controllers AS C, Controllers_Readers AS CR, Readers AS R,
  Directions AS D, AccessPoints AS AP, Points_Controllers as PC
WHERE Controllers_Readers.ControllerID = Controllers.ControllerID 
  AND Readers.ReaderID = Controllers_Readers.ReaderID
  AND Directions.Direction = Readers.Direction AND 
  Points_Controllers.ControllerID = Controllers.ControllerID
  AND AccessPoints.PointID = Points_Controllers.PointID
GROUP BY Controllers.Description, Controllers.ControllerID, 
  Directions.DirectionText, Directions.Direction, Readers.Name, 
  Readers.Description, Readers.ReaderID,  AccessPoints.Name, 
  AccessPoints.Description, AccessPoints.PointID 
ORDER BY Controllers.Description, Controllers.ControllerID, 
  Directions.DirectionText, Directions.Direction, Readers.Name, 
  Readers.Description, Readers.ReaderID,  AccessPoints.Name,
  AccessPoints.Description, AccessPoints.PointID

相关日志输出如下:

2018-08-30 14:24:35 [DEBUG] db.Locations:35 - Location: LOCAL   DB Path: \sentinel.domain\TempStorage\Me\dbs\Redacted.mdb
2018-08-30 14:24:35 [DEBUG] db.Digger:767 - Connect to DB on path: \sentinel.domain\TempStorage\Me\dbs\Redacted.mdb
2018-08-30 14:24:35 [INFO ] db.Digger:790 - Connecting to jdbc:ucanaccess:////sentinel.domain/TempStorage/Me/dbs//Redacted.mdb;openExclusive=false;concatNulls=false;ignoreCase=true
2018-08-30 14:24:37 [DEBUG] impl.DatabaseImpl:887 - Finished reading system catalog.  Tables: [AccessNumbers, AccessNumbers_Controllers, AccessNumbers_Groups, AccessNumbers_Readers, AccessPoints, Areas, Areas_Controllers, Areas_Points, Areas_Timezones, Controllers, Controllers_Expanders, Controllers_Readers, Directions, Events, Expanders_Readers, Groups, Groups_Areas, Groups_Controllers, Groups_Timezones, Holidays, Points_Controllers, Points_Readers, Points_Timezones, ReaderExpanders, Readers, SelectedAreas, SelectedDates, Sites, Sites_Areas, Status, Storage, Timezones, Transactions, UserInformation, Users] (Db=Redacted.mdb)
2018-08-30 14:25:10 [DEBUG] db.Digger:884 - Found column "ControllerID" in "Controllers_Readers".
2018-08-30 14:25:10 [DEBUG] db.Digger:901 - Table (Controllers_Readers) Exists: TRUE    Has Column: TRUE
2018-08-30 14:25:10 [ERROR] db.Digger:1180 - [UcanaccessSQLException]: UCAExc:::4.0.2 user lacks privilege or object not found: CONTROLLERS_READERS.CONTROLLERID
    net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::4.0.2 user lacks privilege or object not found: CONTROLLERS_READERS.CONTROLLERID
    at net.ucanaccess.jdbc.UcanaccessStatement.executeQuery(UcanaccessStatement.java:210)
    at db.Digger.loadAllControllerReaders(Digger.java:947)
    at db.Digger.main(Digger.java:1177)
Caused by: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: CONTROLLERS_READERS.CONTROLLERID
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.executeQuery(Unknown Source)
    at net.ucanaccess.jdbc.UcanaccessStatement.executeQuery(UcanaccessStatement.java:208)
    ... 2 more
Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: CONTROLLERS_READERS.CONTROLLERID
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.ExpressionColumn.checkColumnsResolved(Unknown Source)
    at org.hsqldb.QueryExpression.resolve(Unknown Source)
    at org.hsqldb.ParserDQL.compileCursorSpecification(Unknown Source)
    at org.hsqldb.ParserCommand.compilePart(Unknown Source)
    at org.hsqldb.ParserCommand.compileStatements(Unknown Source)
    at org.hsqldb.Session.executeDirectStatement(Unknown Source)
    at org.hsqldb.Session.execute(Unknown Source)

注意: db.Diggerdb.Locations 在我的申请中是 类。 loadAllControllerReaders 是执行 SQL 查询的方法。

运行 通过 MS Access (Office 365) 对数据库进行的相同查询为我提供了一个在列中包含值的结果集。为什么 uCanAccess/HSQLDB 无法执行相同操作(未能在 Controllers_Readers 中找到 ControllerID 列)?我如何让它识别出该列存在于 table?

我能够在 HSQLDB 本身(版本 2.4.1)下重现您的问题。您在 FROM 子句

中为您的 table 名称添加了别名
... FROM Controllers AS C, Controllers_Readers AS CR, ...

但是您的 WHERE 子句使用未别名的 table 名称而不是别名

... WHERE Controllers_Readers.ControllerID = Controllers.ControllerID ...

所以实际的 table 名字没有被识别。这可以通过

确认
Statement st = conn.createStatement();
st.execute("CREATE TABLE MY_TABLE (ID INT PRIMARY KEY, DT DATETIME)");
st.execute("INSERT INTO MY_TABLE (ID, DT) VALUES (1, '2018-12-23 00:11:22')");
ResultSet rs = st.executeQuery("SELECT X.DT FROM MY_TABLE AS X WHERE MY_TABLE.ID=1");

这也会产生

java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: MY_TABLE.ID
...
Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: MY_TABLE.ID

您还需要在其余子句(WHERE、GROUP BY、ORDER BY)中使用适当的别名。