User Documentation
 All Files Functions Groups
compatibility.sql_in
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------- *//**
2  *
3  * @file compatibility.sql_in
4  *
5  * @brief Compatibility SQL functions
6  *
7  * @sa For a brief overview of compatibility functions, see the
8  * module description \ref grp_compatibility.
9  *
10  *//* ----------------------------------------------------------------------- */
11 
12 m4_include(`SQLCommon.m4')
13 m4_changequote(<!,!>)
14 
15 
16 /**
17 @addtogroup grp_compatibility
18 
19 @about
20 
21 The compatibility module replicates standard SQL functionality that cannot be
22 used on all platforms supported by MADlib -- be it due to incomplete
23 implementation of the SQL standard or bugs.
24 
25 This module contains workarounds for the following issues:
26 
27 - <tt>CREATE TABLE <em>table_name</em> AS <em>query</em></tt> statements where
28  <em>query</em> contains certain MADlib functions fails with the error
29  “function cannot execute on segment because it issues a non-SELECT statement”
30  (Greenplum versions before version 4.2, and in rare special cases also later
31  versions).
32  The workaround is:
33  <pre>SELECT \ref create_table_as('<em>table_name</em>', $$
34  <em>query</em>
35 $$, 'BY (<em>column</em>, [...]) | RANDOMLY');</pre>
36 - <tt>INSERT INTO <em>table_name</em> <em>query</em></tt> where <em>query</em>
37  contains certain MADlib functions fails with the error “function cannot
38  execute on segment because it issues a non-SELECT statement” (Greenplum
39  versions before version 4.2, and in rare special cases also later versions).
40  The workaround is:
41  <pre>SELECT \ref insert_into('<em>table_name</em>', $$
42  <em>query</em>
43 $$);</pre>
44 
45 @note
46 These functions are not needed on PostgreSQL and are usually not needed on
47 Greenplum 4.2 and later. However, they are always installed for compatibility
48 with other platforms.
49 Workarounds should be used only when necessary. For portability and best
50 performance, standard SQL should be prefered whenever possible.
51 
52 @literature
53 
54 [1] Greenplum Admin Guide
55 
56 @sa File compatibility.sql_in (documenting the SQL functions)
57 
58 */
59 
60 /**
61  * @brief Mimick <tt>INSERT INTO</tt>. Create new rows in a table.
62  *
63  * @param inTableName The name (optionally schema-qualified) of an existing
64  * table.
65  * @param inSQL A SELECT command.
66  *
67  * @usage
68  * Use in the same way as the <tt>INSERT INTO</tt> statement:
69  * <pre>SELECT insert_into('<em>table_name</em>', $$
70  * <em>query</em>
71  *$$);</pre>
72  *
73  * @examp
74  * <pre>SELECT insert_into('public.test', $$
75  * SELECT * FROM generate_series(1,10) AS id
76  *$$);\n
77  *SELECT insert_into('logregr_results', $$
78  * SELECT * FROM logregr('data', 'y', 'x')
79  *$$);</pre>
80  *
81  * @note This function is a workaround. For compliance with the SQL standard and
82  * for optimal performance, please use the normal <tt>INSERT INTO</tt>
83  * statement whenever possible.
84  * Known caveats of this workaround:
85  * - For queries returning a large number of rows, this function will be
86  * significantly slower than the <tt>INSERT INTO</tt> statement.
87  */
88 CREATE FUNCTION MADLIB_SCHEMA.insert_into(
89  "inTableName" VARCHAR,
90  "inSQL" VARCHAR)
91 RETURNS VOID
92 LANGUAGE plpgsql
93 VOLATILE
94 RETURNS NULL ON NULL INPUT
95 AS $$
96 DECLARE
97  oldClientMinMessages VARCHAR;
98 BEGIN
99  oldClientMinMessages :=
100  (SELECT setting FROM pg_settings WHERE name = 'client_min_messages');
101  EXECUTE 'SET client_min_messages TO warning';
102 
103  PERFORM MADLIB_SCHEMA.create_schema_pg_temp();
104 
105  EXECUTE
106  'DROP FUNCTION IF EXISTS pg_temp._madlib_temp_function();
107  CREATE FUNCTION pg_temp._madlib_temp_function()
108  RETURNS VOID
109  LANGUAGE plpgsql
110  AS $_madlib_temp_function$
111  DECLARE
112  result ' || "inTableName" || '%ROWTYPE;
113  BEGIN
114  FOR result IN EXECUTE
115  $_madlib_temp_function_string$
116  ' || "inSQL" || '
117  $_madlib_temp_function_string$
118  LOOP
119 
120  INSERT INTO ' || "inTableName" || ' VALUES (result.*);
121  END LOOP;
122  END;
123  $_madlib_temp_function$';
124 
125  -- We call _madlib_temp_function() in a separate
126  -- EXECUTE statement because it is not yet visible before
127  -- (we would see "ERROR: function _madlib_temp_function() does not exist")
128  EXECUTE
129  'SELECT pg_temp._madlib_temp_function();
130  SET client_min_messages TO ' || oldClientMinMessages || ';';
131 END;
132 $$;
133 
134 
135 CREATE FUNCTION MADLIB_SCHEMA.internal_create_table_as(
136  "inTemporary" BOOLEAN,
137  "inTableName" VARCHAR,
138  "inSQL" VARCHAR,
139  "inDistributed" VARCHAR)
140 RETURNS VOID
141 LANGUAGE plpgsql
142 VOLATILE
143 RETURNS NULL ON NULL INPUT
144 AS $$
145 DECLARE
146  whatToCreate VARCHAR;
147 BEGIN
148  IF "inTemporary" = TRUE THEN
149  whatToCreate := 'TEMPORARY TABLE';
150  ELSE
151  whatToCreate := 'TABLE';
152  END IF;
153 
154  -- We separate the following EXECUTE statement because it is prone
155  -- to generate an exception -- e.g., if the table already exists
156  -- In that case we want to keep the context in the error message short
157  EXECUTE
158  'CREATE ' || whatToCreate || ' ' || "inTableName" || ' AS
159  SELECT * FROM (' || "inSQL" || ') AS _madlib_ignore
160  WHERE FALSE
161 m4_ifdef(<!__GREENPLUM__!>,<!
162  DISTRIBUTED ' || "inDistributed";
163 !>,<!
164  ';
165 !>)
166 
167  PERFORM MADLIB_SCHEMA.insert_into("inTableName", "inSQL");
168 END;
169 $$;
170 
171 
172 /**
173  * @brief Mimick <tt>CREATE TABLE AS</tt>. Create a table and fill it with data
174  * computed by a \c SELECT command.
175  *
176  * @param inTableName The name (optionally schema-qualified) of the table to be
177  * created.
178  * @param inSQL A SELECT command.
179  * @param inDistributed The Greenplum Database distribution policy for the
180  * table. This can be either \c RANDOMLY, which is the default, or
181  * <tt>BY (<em>column</em>, [...])</tt>. This parameter is ignored on
182  * PostgreSQL.
183  *
184  * @usage
185  * Use in the same way as the <tt>CREATE TABLE AS</tt> statement:
186  * <pre>SELECT create_table_as('<em>table_name</em>', $$
187  * <em>query</em>
188  *$$, 'BY (<em>column</em>, [...]) | RANDOMLY');</pre>
189  *
190  * @examp
191  * <pre>SELECT create_table_as('public.test', $$
192  * SELECT * FROM generate_series(1,10) AS id
193  *$$, 'BY (id)');\n
194  *SELECT create_table_as('logregr_result', $$
195  * SELECT * FROM logregr('data', 'y', 'x')
196  *$$, 'RANDOMLY');</pre>
197  *
198  * @note This function is a workaround. For compliance with the SQL standard and
199  * for optimal performance, please use the normal <tt>CREATE TABLE AS</tt>
200  * statement whenever possible.
201  * Known caveats of this workaround:
202  * - For queries returning a large number of rows, this function will be
203  * significantly slower than the <tt>CREATE TABLE AS</tt> statement.
204  */
205 CREATE FUNCTION MADLIB_SCHEMA.create_table_as(
206  "inTableName" VARCHAR,
207  "inSQL" VARCHAR,
208  "inDistributed" VARCHAR /*+ = 'RANDOMLY' */)
209 RETURNS VOID
210 LANGUAGE sql
211 VOLATILE
212 RETURNS NULL ON NULL INPUT
213 AS $$
214  SELECT MADLIB_SCHEMA.internal_create_table_as(FALSE,
215  $1, $2, $3);
216 $$;
217 
218 
219 CREATE FUNCTION MADLIB_SCHEMA.create_table_as(
220  "inTableName" VARCHAR,
221  "inSQL" VARCHAR)
222 RETURNS VOID
223 LANGUAGE sql
224 VOLATILE
225 RETURNS NULL ON NULL INPUT
226 AS $$
227  SELECT MADLIB_SCHEMA.internal_create_table_as(FALSE,
228  $1, $2, 'RANDOMLY');
229 $$;
230 
231 
232 /**
233  * @brief Mimick <tt>CREATE TEMPORARY TABLE AS</tt>. Create a temporary table
234  * and fill it with data computed by a \c SELECT command.
235  *
236  * @sa create_table_as()
237  */
238 CREATE FUNCTION MADLIB_SCHEMA.create_temporary_table_as(
239  "inTableName" VARCHAR,
240  "inSQL" VARCHAR,
241  "inDistributed" VARCHAR /*+ = 'RANDOMLY' */)
242 RETURNS VOID
243 LANGUAGE sql
244 VOLATILE
245 RETURNS NULL ON NULL INPUT
246 AS $$
247  SELECT MADLIB_SCHEMA.internal_create_table_as(TRUE,
248  $1, $2, $3);
249 $$;
250 
251 
252 CREATE FUNCTION MADLIB_SCHEMA.create_temporary_table_as(
253  "inTableName" VARCHAR,
254  "inSQL" VARCHAR)
255 RETURNS VOID
256 LANGUAGE sql
257 VOLATILE
258 RETURNS NULL ON NULL INPUT
259 AS $$
260  SELECT MADLIB_SCHEMA.internal_create_table_as(TRUE,
261  $1, $2, 'RANDOMLY');
262 $$;
263 
264 
265 /*
266  * We also provide create_temp_table_as, but we do not advertise it in our
267  * documentation.
268  */
269 CREATE FUNCTION MADLIB_SCHEMA.create_temp_table_as(
270  "inTableName" VARCHAR,
271  "inSQL" VARCHAR,
272  "inDistributed" VARCHAR /*+ = 'RANDOMLY' */)
273 RETURNS VOID
274 LANGUAGE sql
275 VOLATILE
276 RETURNS NULL ON NULL INPUT
277 AS $$
278  SELECT MADLIB_SCHEMA.internal_create_table_as(TRUE,
279  $1, $2, $3);
280 $$;
281 
282 
283 CREATE FUNCTION MADLIB_SCHEMA.create_temp_table_as(
284  "inTableName" VARCHAR,
285  "inSQL" VARCHAR)
286 RETURNS VOID
287 LANGUAGE sql
288 VOLATILE
289 RETURNS NULL ON NULL INPUT
290 AS $$
291  SELECT MADLIB_SCHEMA.internal_create_table_as(TRUE,
292  $1, $2, 'RANDOMLY');
293 $$;
294 
295 m4_changequote(<!`!>,<!'!>)