| 242 | | SELECT * FROM _ensure_globals(); |
| 243 | | DROP FUNCTION _ensure_globals(); |
| 244 | | |
| 245 | | |
| 246 | | -- Note this is in the public schema!! |
| 247 | | CREATE OR REPLACE FUNCTION _global_record(tablename text, creator text) RETURNS record AS $$ |
| 248 | | DECLARE |
| 249 | | result record; |
| 250 | | record_stmt text; |
| 251 | | BEGIN |
| 252 | | EXECUTE 'SELECT NULL::text AS __name__, NULL::text AS __create__, ' |
| 253 | | || 'NULL::text AS __record__, NULL::text AS __iter__, ' |
| 254 | | || 'NULL::text AS __attributes__, 0::int AS __len__, ' |
| 255 | | || '* FROM ' || tablename || ' LIMIT 1' INTO result; |
| 256 | | |
| 257 | | -- We add these values outside the EXECUTE in case the TEMP table has no rows. |
| 258 | | result.__name__ := tablename; |
| 259 | | result.__create__ := creator; |
| 260 | | result.__record__ := 'SELECT * FROM _global_record(''' || tablename || ''', ''' || creator || ''')'; |
| 261 | | result.__iter__ := 'SELECT * FROM ' || tablename; |
| 262 | | result.__attributes__ := 'SELECT attname FROM test.attributes(''' || tablename || ''')'; |
| 263 | | EXECUTE 'SELECT COUNT(*) FROM ' || tablename INTO result.__len__; |
| 264 | | |
| 265 | | RETURN result; |
| 266 | | END; |
| 267 | | $$ LANGUAGE plpgsql; |
| 268 | | |
| 269 | | |
| 270 | | -- Note this is in the public schema!! |
| 271 | | CREATE OR REPLACE FUNCTION global(call text) RETURNS record AS $$ |
| 272 | | -- Stores the given call's output in a TEMP table, and returns it as a record. |
| 273 | | -- If the call produces several rows, only the first record is returned. |
| | 242 | SELECT * FROM test._ensure_globals(); |
| | 243 | DROP FUNCTION test._ensure_globals(); |
| | 244 | |
| | 245 | |
| | 246 | CREATE OR REPLACE FUNCTION test.global(call text, name text) RETURNS text AS $$ |
| | 247 | -- Stores the given call's output in a TEMP table, and returns the TEMP table name. |
| | 250 | DECLARE |
| | 251 | tablename text; |
| | 252 | creator text; |
| | 253 | BEGIN |
| | 254 | IF name IS NULL THEN |
| | 255 | tablename := '_global_' || nextval('_global_ids'); |
| | 256 | ELSE |
| | 257 | tablename := name; |
| | 258 | END IF; |
| | 259 | |
| | 260 | BEGIN |
| | 261 | EXECUTE 'DROP TABLE ' || tablename; |
| | 262 | EXCEPTION WHEN undefined_table THEN |
| | 263 | NULL; |
| | 264 | END; |
| | 265 | |
| | 266 | creator := test.statement(call); |
| | 267 | EXECUTE 'CREATE TEMP TABLE ' || tablename || ' WITHOUT OIDS AS ' || creator; |
| | 268 | EXECUTE 'COMMENT ON TABLE ' || tablename || ' IS ' || quote_literal(creator); |
| | 269 | RETURN tablename; |
| | 270 | END; |
| | 271 | $$ LANGUAGE plpgsql; |
| | 272 | |
| | 273 | CREATE OR REPLACE FUNCTION test.global(call text) RETURNS text AS $$ |
| | 274 | SELECT global FROM test.global($1, NULL); |
| | 275 | $$ LANGUAGE SQL; |
| | 276 | |
| | 277 | CREATE OR REPLACE FUNCTION test.get(p_tablename text, p_offset int) RETURNS record AS $$ |
| | 278 | -- Returns a record (the first one, by default) from the given global table. |
| 282 | | -- * __create__ (text): The SQL statement used to construct the table. |
| 283 | | -- * __record__ (text): The SQL statement used to construct the returned record. |
| 284 | | -- Use this to copy the returned record (perhaps in another function). |
| 285 | | -- Example: EXECUTE g.__record__ INTO g2; |
| 286 | | -- * __iter__ (text): An SQL string to SELECT * FROM the TEMP table. |
| 287 | | -- Example: FOR record IN EXECUTE g.__iter__ |
| 288 | | -- * __attributes__ (text): The SQL string for TEMP table column names. |
| 289 | | -- Example: FOR colname IN EXECUTE g.__attributes__ |
| 290 | | -- * __len__ (int): The number of rows in the TEMP table. This value |
| 291 | | -- is NOT updated if you change the table after its creation. |
| 292 | | DECLARE |
| 293 | | tablename text; |
| 294 | | creator text; |
| | 285 | DECLARE |
| 296 | | BEGIN |
| 297 | | tablename := '_global_' || nextval('_global_ids'); |
| 298 | | creator := test.statement(call); |
| 299 | | EXECUTE 'CREATE TEMP TABLE ' || tablename || ' AS ' || creator; |
| 300 | | result := _global_record(tablename, creator); |
| | 287 | rownum int; |
| | 288 | BEGIN |
| | 289 | IF p_offset IS NULL OR p_offset < 0 THEN |
| | 290 | rownum := 0; |
| | 291 | ELSE |
| | 292 | rownum := p_offset; |
| | 293 | END IF; |
| | 294 | |
| | 295 | EXECUTE 'SELECT *, NULL::text AS __name__ FROM ' || p_tablename || ' LIMIT 1 OFFSET ' || rownum INTO result; |
| | 296 | |
| | 297 | -- We add these values outside the EXECUTE in case the SELECT returned no rows. |
| | 298 | result.__name__ := p_tablename; |
| | 299 | |
| | 304 | CREATE OR REPLACE FUNCTION test.get(p_tablename text) RETURNS record AS $$ |
| | 305 | DECLARE |
| | 306 | result record; |
| | 307 | BEGIN |
| | 308 | EXECUTE 'SELECT *, NULL::text AS __name__ FROM ' || p_tablename || ' LIMIT 1' INTO result; |
| | 309 | |
| | 310 | -- We add these values outside the EXECUTE in case the SELECT returned no rows. |
| | 311 | result.__name__ := p_tablename; |
| | 312 | |
| | 313 | RETURN result; |
| | 314 | END; |
| | 315 | $$ LANGUAGE plpgsql; |
| | 316 | |
| | 317 | |
| | 318 | CREATE OR REPLACE FUNCTION test.constructor(tablename text) RETURNS text AS $$ |
| | 319 | -- Return the SQL statement used to construct the given global table. |
| | 320 | SELECT obj_description(pgc.oid, 'pg_class') FROM pg_class pgc WHERE relname = $1; |
| | 321 | $$ LANGUAGE SQL; |
| | 322 | |
| | 323 | |
| | 324 | CREATE OR REPLACE FUNCTION test.len(tablename text) RETURNS int AS $$ |
| | 325 | -- Return the number of rows in the given table. |
| | 326 | DECLARE |
| | 327 | num int; |
| | 328 | BEGIN |
| | 329 | EXECUTE 'SELECT COUNT(*) FROM ' || tablename INTO num; |
| | 330 | RETURN num; |
| | 331 | END |
| | 332 | $$ LANGUAGE plpgsql; |
| | 333 | |
| | 334 | |
| | 335 | CREATE OR REPLACE FUNCTION test.iter(tablename text) RETURNS text AS $$ |
| | 336 | -- Return SQL to retrieve all rows in the given table. |
| | 337 | SELECT 'SELECT * FROM ' || $1 |
| | 338 | $$ LANGUAGE sql; |
| | 339 | |