Farooq Ayoade created FINERACT-2468:
---------------------------------------
Summary: Datatable not found / GET /datatables 404 on PostgreSQL
with non-public schema
Key: FINERACT-2468
URL: https://issues.apache.org/jira/browse/FINERACT-2468
Project: Apache Fineract
Issue Type: Bug
Components: Data Tables
Reporter: Farooq Ayoade
On PostgreSQL when using a *non-{{{}public{}}} schema* (e.g. tenant-specific
schema), creating a new datatable causes:
* *GET /datatables* to return *404* with "Datatable not found" for the new
datatable and break the entire list response
* Saving data to the new datatable to fail with "Datatable not found"
* Recovery only possible by deleting the problematic datatable
h2. Steps to reproduce
# Configure Fineract with PostgreSQL and a tenant that uses a
*non-{{{}public{}}} schema* (e.g. schema name = tenant identifier).
# Create a new datatable via POST /datatables
# Call *GET /datatables* (or GET /datatables/ with no filter)
h2. Root cause
In {*}{{fineract-core}}{*}, class {*}{{PostgreSQLQueryService}}{*}:
* *{{getTableColumns()}}* correctly uses *{{current_schema}}* (schema of the
current connection), so the table is found when it lives in the tenant schema.
* *{{getTableIndexes()}}* and *{{isTablePresent()}}* hardcode *{{'public'}}*
for the schema.
When listing datatables, the flow is:
# {{DatatableReadServiceImpl.retrieveDatatableNames()}} loads all permitted
datatables from {{{}x_registered_table{}}}.
# For each datatable it calls
{{{}GenericDataServiceImpl.fillResultsetColumnHeaders(datatableName){}}}.
# {{fillResultsetColumnHeaders()}} calls:
** {{getTableMetaData(tableName)}} → uses {{getTableColumns()}} → *finds the
table* (current_schema).
** {{getDatatableIndexData(tableName)}} → uses {{getTableIndexes()}} → looks
only in *{{public}}* → finds no rows → throws {{IllegalArgumentException("Table
... is not found")}} → mapped to {*}DatatableNotFoundException{*}.
So the table exists in the tenant schema, but the index query looks in
{{public}} and fails, breaking GET /datatables and any operation that needs
index metadata for that datatable.
*Stack trace (relevant part):*
!http://localhost:63342/markdownPreview/2018793464/docs?_ijt=2fh99ghqni20rs3r3bq41b8r3p!
{{org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException:
Datatable not found.
at
org.apache.fineract.infrastructure.dataqueries.service.GenericDataServiceImpl.getDatatableIndexData(GenericDataServiceImpl.java:299)
at
org.apache.fineract.infrastructure.dataqueries.service.GenericDataServiceImpl.fillResultsetColumnHeaders(GenericDataServiceImpl.java:98)
at
org.apache.fineract.infrastructure.dataqueries.service.DatatableReadServiceImpl.retrieveDatatableNames(DatatableReadServiceImpl.java:93)
at
org.apache.fineract.infrastructure.dataqueries.api.DatatablesApiResource.getDatatables(DatatablesApiResource.java:92)}}
h2. Fix
*File:*
{{fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/database/PostgreSQLQueryService.java}}
Use *{{current_schema}}* instead of *{{'public'}}* so behavior is consistent
with {{getTableColumns()}} and works with tenant/custom schemas.
h3. 1. {{getTableIndexes}}
*Before:*
!http://localhost:63342/markdownPreview/2018793464/docs?_ijt=2fh99ghqni20rs3r3bq41b8r3p!
{{String sql = "SELECT indexname FROM pg_indexes WHERE schemaname = 'public'
AND tablename = ?";}}
*After:*
!http://localhost:63342/markdownPreview/2018793464/docs?_ijt=2fh99ghqni20rs3r3bq41b8r3p!
{{// Use current_schema so tenant/schema-specific tables (e.g. datatables) are
found;
// hardcoding 'public' breaks GET /datatables and datatable operations in
multi-tenant setups.
String sql = "SELECT indexname FROM pg_indexes WHERE schemaname =
current_schema AND tablename = ?";}}
h3. 2. {{isTablePresent}}
*Before:*
!http://localhost:63342/markdownPreview/2018793464/docs?_ijt=2fh99ghqni20rs3r3bq41b8r3p!
{{Integer result = jdbcTemplate.queryForObject(
"SELECT COUNT(table_name) FROM information_schema.tables " + "WHERE
table_schema = 'public' AND table_name = ?",
Integer.class, tableName);}}
*After:*
!http://localhost:63342/markdownPreview/2018793464/docs?_ijt=2fh99ghqni20rs3r3bq41b8r3p!
{{// Use current_schema for consistency with getTableColumns/getTableIndexes
(tenant/schema-aware).
Integer result = jdbcTemplate.queryForObject(
"SELECT COUNT(table_name) FROM information_schema.tables WHERE
table_schema = current_schema AND table_name = ?",
Integer.class, tableName);}}
h2. Verification
* With PostgreSQL and a non-{{{}public{}}} schema (e.g. tenant schema):
** Create a new datatable.
** GET /datatables returns 200 and includes the new datatable.
** Saving data to the new datatable succeeds.
* With single-tenant {{public}} schema, behaviour unchanged
({{{}current_schema{}}} is {{{}public{}}}).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)