risingwavelabs/risingwave · error

postgres_query function is not supported in streaming mode

Error message

postgres_query function is not supported in streaming mode

What it means

LogicalPostgresQuery represents a query executed via the postgres_query table function, evaluated only in batch mode by delegating to the external Postgres source. Streaming execution cannot continuously maintain such results, so to_stream intentionally returns an error.

Solutions

  1. Keep postgres_query in batch SELECT queries only; never reference it in MVs or streaming definitions
  2. Use RisingWave's Postgres CDC connector to stream the external table into RisingWave
  3. Persist batch results into a table via scheduled ingestion, then build MVs on that table
  4. Restructure so external reads occur at batch query time, not in streaming pipelines

Example fix

-- before (fails)
CREATE MATERIALIZED VIEW mv AS SELECT * FROM postgres_query('conn_name', 'SELECT * FROM t');
-- after: batch query only, or CDC source
SELECT * FROM postgres_query('conn_name', 'SELECT * FROM t');
-- streaming alternative: Postgres CDC source + MV over the source
Defensive patterns

Strategy: validation

Validate before calling

-- Pre-check that streaming definitions do not use postgres_query
-- if /\bpostgres_query\s*\(/i.test(sql) && isStreamingDdl(sql) reject();

Try / catch

try {
  await conn.query('CREATE MATERIALIZED VIEW mv AS SELECT * FROM postgres_query(...)');
} catch (e) {
  if (String(e.message).includes('postgres_query function is not supported in streaming mode')) {
    // fall back to CDC source setup or batch persistence
  }
  throw e;
}

Prevention

When it happens

Trigger: Building a streaming plan (materialized view, source, MV refresh) containing a postgres_query(...) table function, causing to_stream to be called on the node.

Common situations: Users attempt CREATE MATERIALIZED VIEW AS SELECT ... FROM postgres_query(...) expecting live external-table streaming; assumptions that the function behaves like a native table in streaming contexts.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/6108a240e0f7cb5e. Report an issue: GitHub.

Appendix: source

Thrown at src/frontend/src/optimizer/plan_node/logical_postgres_query.rs:113

        _ctx: &mut PredicatePushdownContext,
    ) -> PlanRef {
        // No pushdown.
        LogicalFilter::create(self.clone().into(), predicate)
    }
}

impl ToBatch for LogicalPostgresQuery {
    fn to_batch(&self) -> Result<crate::optimizer::plan_node::BatchPlanRef> {
        Ok(BatchPostgresQuery::new(self.core.clone()).into())
    }
}

impl ToStream for LogicalPostgresQuery {
    fn to_stream(
        &self,
        _ctx: &mut ToStreamContext,
    ) -> Result<crate::optimizer::plan_node::StreamPlanRef> {
        bail!("postgres_query function is not supported in streaming mode")
    }

    fn logical_rewrite_for_stream(
        &self,
        _ctx: &mut RewriteStreamContext,
    ) -> Result<(PlanRef, ColIndexMapping)> {
        bail!("postgres_query function is not supported in streaming mode")
    }
}

View on GitHub (pinned to 6469eb736d)