Repository: xerial/sqlite-jdbc (java)

Issue:
Generated columns with `stored` in SQLite are not marked as generated
**Description**
Generated columns are not reported as such by database metadata.

**To Reproduce**
Create the following table with SQLite :

```sql
create table foo (
  id integer primary key,
  bar int not null generated always as (id + 1) stored
);
```

On the `bar` column `IS_GENERATEDCOLUMN` is `NO` with `DatabaseMetaData.getColumns`. Without the stored keyword, it is `YES`.

**Expected Behavior**
On the `bar` column `IS_GENERATEDCOLUMN` should be `YES` with `DatabaseMetaData.getColumns`.


**Additional Context**
See [JDBC3DatabaseMetaData](https://github.com/xerial/sqlite-jdbc/blob/99aa8d9e41113d6bec2f77e0084a328cacbc98c7/src/main/java/org/sqlite/jdbc3/JDBC3DatabaseMetaData.java#L1081). It only checks for a value of "2", when according to the [SQLite documentation](https://sqlite.org/pragma.html#pragma_table_xinfo:~:text=a%20dynamic%20or%20stored%20generated%20column%20%282%20or%203%29), it should be checking for both 2 and 3.


Pull request description:
fix(jdbc): generated columns with stored in SQLite are not marked as generated
Fixes #1132 - Generated columns with stored in SQLite are not marked as generated

Patch:
diff --git a/src/main/java/org/sqlite/jdbc3/JDBC3DatabaseMetaData.java b/src/main/java/org/sqlite/jdbc3/JDBC3DatabaseMetaData.java
index 6277ba8a..1a2229c7 100644
--- a/src/main/java/org/sqlite/jdbc3/JDBC3DatabaseMetaData.java
+++ b/src/main/java/org/sqlite/jdbc3/JDBC3DatabaseMetaData.java
@@ -1078,7 +1078,10 @@ public abstract class JDBC3DatabaseMetaData extends CoreDatabaseMetaData {
                             colType = colType.substring(0, iStartOfDimension).trim();
                         }
 
-                        int colGenerated = "2".equals(colHidden) ? 1 : 0;
+                        int colGenerated = 0;
+                        if ("2".equals(colHidden) || "3".equals(colHidden)) {
+                            colGenerated = 1;
+                        }
 
                         sql.append("select ")
                                 .append(i + 1)


Test patch:
diff --git a/src/test/java/org/sqlite/DBMetaDataTest.java b/src/test/java/org/sqlite/DBMetaDataTest.java
index 03c7a2b9..31af5813 100644
--- a/src/test/java/org/sqlite/DBMetaDataTest.java
+++ b/src/test/java/org/sqlite/DBMetaDataTest.java
@@ -18,6 +18,7 @@ import java.util.Map;
 import java.util.Properties;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledInNativeImage;
@@ -490,6 +491,29 @@ public class DBMetaDataTest {
         assertThat(rs.next()).isFalse();
     }
 
+    @Test
+    @DisplayName(
+            "Issue #1132 - Generated columns with stored in SQLite are not marked as generated")
+    public void getColumnsIncludingGeneratedStored() throws SQLException {
+        stat.executeUpdate(
+                "create table foo("
+                        + "\n"
+                        + "  id integer primary key,"
+                        + "\n"
+                        + "  bar int not null generated always as (id + 1) stored"
+                        + "\n"
+                        + ");");
+
+        ResultSet rs = meta.getColumns(null, null, "foo", "%");
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString(4)).as("first column is named 'id'").isEqualTo("id");
+        assertThat(rs.getString(24)).as("first column is generated").isEqualTo("NO");
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString(4)).as("second column is named 'bar'").isEqualTo("bar");
+        assertThat(rs.getString(24)).as("second column is generated").isEqualTo("YES");
+        assertThat(rs.next()).isFalse();
+    }
+
     @Test
     public void getColumnsWithEscape() throws SQLException {
         stat.executeUpdate("create table wildcard(col1 integer, co_1 integer, 'co%1' integer)");