情境:
使用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:“超出堆栈空间”。
过程中没有涉及递归或嵌套循环,很明显错误是由于查询的长度过长。
我认为如果我在执行它之前将“chunks”中的巨大查询传递给提供程序,我可以避免错误,但这只是一个想法,我不知道它是否可能以及如何。
我不知道,任何帮助都表示赞赏。
答案 0 :(得分:2)
因为听起来这是一个VB6级别的问题,并且你已经使用了当前的Pg版本,我担心你可能不得不使用一些非常丑陋的解决方法。
如果可能的话,尝试找到一种方法来增加VB6查询缓冲区大小,通过VB6 ODBC接口以块的形式发送查询等。请考虑以下绝对的最后手段。
也许这会给你一些更健全的线索。我不会说VB6(谢天谢地)所以我无法评价它:http://www.mrexcel.com/forum/excel-questions/61340-error-28-out-stack-space.html
如果所有其他方法都失败,请仅将以下操作作为最后的手段:
创建TEMPORARY
表格,如CREATE TEMPORARY TABLE my_query(id integer, text querychunk)
。
INSERT INTO
临时表是你的语句,按块查询,使用参数化查询来避免引用问题。
创建一个执行RETURN QUERY EXECUTE format('EXECUTE stm_name(...)'
的包装器PL / PgSQL函数,将临时表的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
定义的函数中使用CREATE OR REPLACE FUNCTION
,因为DO
块无法返回结果。例如,对于返回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 / PgSQL EXECUTE
与SQL级EXECUTE
完全不同。 PL / PgSQL EXECUTE
运行一个字符串作为动态SQL,而SQL EXECUTE
运行一个预准备语句。这里我们通过动态SQL运行一个准备好的语句。 ICK。
想知道我为什么要使用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