0

场景:
使用 ADO Connection.Execute 方法通过 PostgreSQL OLEDB 提供程序从 Visual Basic 6 应用程序执行 SQL 命令到 PostgreSQL 9.2 数据库。

查询:
这是一个简单的EXECUTE prepared_statement_name (x, y, z),虽然它涉及 PostGIS 几何类型,因此它变成了这样的东西:

EXECUTE prepared_statement_name (1, ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))', 900001));

问题:
当几何是包含许多顶点的巨大而复杂的 MULTIPOLYGON 时,查询会变得非常冗长(几千个字符)并且该Connection.Execute方法会导致错误 28:“堆栈空间不足”。

该过程中不涉及递归或嵌套循环,很明显错误是由于查询的长度过长造成的。

如果我在执行之前将“块”中的巨大查询传递给提供者,我想我可以避免该错误,但这只是一个想法,我不知道它是否可能以及如何。

我不知道,任何帮助表示赞赏。

4

1 回答 1

2

由于这听起来像是一个 VB6 级别的问题,而且您已经在使用当前的 Pg 版本,我担心您可能不得不使用一些特别难看的解决方法。

如果可能,尝试找到增加 VB6 查询缓冲区大小的方法,通过 VB6 ODBC 接口以块的形式发送查询等。考虑以下绝对是最后的手段。

也许这会给你一些更理智的线索。我不会说 VB6(谢天谢地)所以我无法评估它:http ://www.mrexcel.com/forum/excel-questions/61340-error-28-out-stack-space.html

如果所有其他方法都失败了,请仅将以下方法用作最后的手段

  • 创建一个TEMPORARYCREATE TEMPORARY TABLE my_query(id integer, text querychunk).

  • INSERT INTO临时表您的语句,逐块使用参数化查询以避免引用问题。

  • 创建一个包装 PL/PgSQL 函数,该函数执行 a RETURN QUERY EXECUTE format('EXECUTE stm_name(...)',将string_agg临时表的作为参数传递。是的,这非常丑陋。

这是一个演示,一些我写过的最可怕的代码:

CREATE TABLE real_table (blah text);

PREPARE test_stm2(text) AS INSERT INTO real_table VALUES ($1);

CREATE TEMPORARY TABLE data_chunks(datord integer, datchunk text);

PREPARE chunk_insert(integer, text) AS INSERT INTO data_chunks(datord,datchunk) VALUES ($1,$2);

-- You'll really want to do this via proper parameterised statements
-- to avoid quoting nightmares; I'm using dollar-quoting as a workaround
EXECUTE chunk_insert(0, $val$POLYGON((0 0, 0 1, 1 1,$val$);
EXECUTE chunk_insert(1, $val$ 1, 1 0, 0 0))$val$);

DO
$$
BEGIN
    EXECUTE 'EXECUTE test_stm2($1);'
        USING 
        (SELECT string_agg(datchunk,'' ORDER BY datord) FROM data_chunks);
END;
$$ LANGUAGE plpgsql;

结果:

regress=> SELECT * FROM real_table ;
                 blah                  
---------------------------------------
 POLYGON((0 0, 0 1, 1 1, 1, 1 0, 0 0))
(1 row)

类似的方法是可能的SELECT。您将RETURN QUERY EXECUTE在由 as 定义的函数中使用,CREATE OR REPLACE FUNCTION因为DO块无法返回结果。例如,对于返回 a 的查询,SETOF INTEGER您可以编写:

CREATE OR REPLACE FUNCTION test_wrapper_func() RETURNS SETOF integer AS $$
BEGIN
    RETURN QUERY EXECUTE format('EXECUTE test_stm(%L);', (SELECT string_agg(datchunk,'' ORDER BY datord) FROM data_chunks));
END;
$$ LANGUAGE plpgsql;

您会注意到两级EXECUTE. 这是因为 PL/PgSQLEXECUTE与 SQL 级别的语句完全不同EXECUTE。PL/PgSQLEXECUTE将字符串作为动态 SQL 运行,而 SQLEXECUTE运行准备好的语句。在这里,我们通过动态 SQL 运行准备好的语句。伊克。

想知道我为什么要使用 PL/PgSQL?因为您不能使用子查询作为EXECUTE参数。如果不将查询作为准备好的语句运行,则可以避免查询的 PL/PgSQL 包装器。

regress=> EXECUTE test_stm2( (SELECT string_agg(datchunk,'' ORDER BY datord) FROM data_chunks) );
ERROR:  cannot use subquery in EXECUTE parameter
于 2013-06-04T13:26:02.900 回答