{"record":{"id":"6108a240e0f7cb5e","repo":"risingwavelabs/risingwave","slug":"postgres-query-function-is-not-supported-in-stream","errorCode":null,"errorMessage":"postgres_query function is not supported in streaming mode","messagePattern":"postgres_query function is not supported in streaming mode","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/frontend/src/optimizer/plan_node/logical_postgres_query.rs","lineNumber":113,"sourceCode":"        _ctx: &mut PredicatePushdownContext,\n    ) -> PlanRef {\n        // No pushdown.\n        LogicalFilter::create(self.clone().into(), predicate)\n    }\n}\n\nimpl ToBatch for LogicalPostgresQuery {\n    fn to_batch(&self) -> Result<crate::optimizer::plan_node::BatchPlanRef> {\n        Ok(BatchPostgresQuery::new(self.core.clone()).into())\n    }\n}\n\nimpl ToStream for LogicalPostgresQuery {\n    fn to_stream(\n        &self,\n        _ctx: &mut ToStreamContext,\n    ) -> Result<crate::optimizer::plan_node::StreamPlanRef> {\n        bail!(\"postgres_query function is not supported in streaming mode\")\n    }\n\n    fn logical_rewrite_for_stream(\n        &self,\n        _ctx: &mut RewriteStreamContext,\n    ) -> Result<(PlanRef, ColIndexMapping)> {\n        bail!(\"postgres_query function is not supported in streaming mode\")\n    }\n}\n","sourceCodeStart":95,"sourceCodeEnd":123,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/frontend/src/optimizer/plan_node/logical_postgres_query.rs#L95-L123","documentation":"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.","triggerScenarios":"Building a streaming plan (materialized view, source, MV refresh) containing a postgres_query(...) table function, causing to_stream to be called on the node.","commonSituations":"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.","solutions":["Keep postgres_query in batch SELECT queries only; never reference it in MVs or streaming definitions","Use RisingWave's Postgres CDC connector to stream the external table into RisingWave","Persist batch results into a table via scheduled ingestion, then build MVs on that table","Restructure so external reads occur at batch query time, not in streaming pipelines"],"exampleFix":"-- before (fails)\nCREATE MATERIALIZED VIEW mv AS SELECT * FROM postgres_query('conn_name', 'SELECT * FROM t');\n-- after: batch query only, or CDC source\nSELECT * FROM postgres_query('conn_name', 'SELECT * FROM t');\n-- streaming alternative: Postgres CDC source + MV over the source","handlingStrategy":"validation","validationCode":"-- Pre-check that streaming definitions do not use postgres_query\n-- if /\\bpostgres_query\\s*\\(/i.test(sql) && isStreamingDdl(sql) reject();","typeGuard":null,"tryCatchPattern":"try {\n  await conn.query('CREATE MATERIALIZED VIEW mv AS SELECT * FROM postgres_query(...)');\n} catch (e) {\n  if (String(e.message).includes('postgres_query function is not supported in streaming mode')) {\n    // fall back to CDC source setup or batch persistence\n  }\n  throw e;\n}","preventionTips":["Never reference postgres_query in MVs, indexes, or sources","Use Postgres CDC for streaming replication","Keep postgres_query limited to ad-hoc batch queries"],"tags":["rust","streaming","postgres","external-source"],"backgroundTag":"unsupported-operation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}