1-- 2-- Test data type behavior 3-- 4 5-- 6-- Base/common types 7-- 8 9CREATE FUNCTION test_type_conversion_bool(x bool) RETURNS bool AS $$ 10plpy.info(x, type(x)) 11return x 12$$ LANGUAGE plpythonu; 13 14SELECT * FROM test_type_conversion_bool(true); 15SELECT * FROM test_type_conversion_bool(false); 16SELECT * FROM test_type_conversion_bool(null); 17 18 19-- test various other ways to express Booleans in Python 20CREATE FUNCTION test_type_conversion_bool_other(n int) RETURNS bool AS $$ 21# numbers 22if n == 0: 23 ret = 0 24elif n == 1: 25 ret = 5 26# strings 27elif n == 2: 28 ret = '' 29elif n == 3: 30 ret = 'fa' # true in Python, false in PostgreSQL 31# containers 32elif n == 4: 33 ret = [] 34elif n == 5: 35 ret = [0] 36plpy.info(ret, not not ret) 37return ret 38$$ LANGUAGE plpythonu; 39 40SELECT * FROM test_type_conversion_bool_other(0); 41SELECT * FROM test_type_conversion_bool_other(1); 42SELECT * FROM test_type_conversion_bool_other(2); 43SELECT * FROM test_type_conversion_bool_other(3); 44SELECT * FROM test_type_conversion_bool_other(4); 45SELECT * FROM test_type_conversion_bool_other(5); 46 47 48CREATE FUNCTION test_type_conversion_char(x char) RETURNS char AS $$ 49plpy.info(x, type(x)) 50return x 51$$ LANGUAGE plpythonu; 52 53SELECT * FROM test_type_conversion_char('a'); 54SELECT * FROM test_type_conversion_char(null); 55 56 57CREATE FUNCTION test_type_conversion_int2(x int2) RETURNS int2 AS $$ 58plpy.info(x, type(x)) 59return x 60$$ LANGUAGE plpythonu; 61 62SELECT * FROM test_type_conversion_int2(100::int2); 63SELECT * FROM test_type_conversion_int2(-100::int2); 64SELECT * FROM test_type_conversion_int2(null); 65 66 67CREATE FUNCTION test_type_conversion_int4(x int4) RETURNS int4 AS $$ 68plpy.info(x, type(x)) 69return x 70$$ LANGUAGE plpythonu; 71 72SELECT * FROM test_type_conversion_int4(100); 73SELECT * FROM test_type_conversion_int4(-100); 74SELECT * FROM test_type_conversion_int4(null); 75 76 77CREATE FUNCTION test_type_conversion_int8(x int8) RETURNS int8 AS $$ 78plpy.info(x, type(x)) 79return x 80$$ LANGUAGE plpythonu; 81 82SELECT * FROM test_type_conversion_int8(100); 83SELECT * FROM test_type_conversion_int8(-100); 84SELECT * FROM test_type_conversion_int8(5000000000); 85SELECT * FROM test_type_conversion_int8(null); 86 87 88CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$ 89# print just the class name, not the type, to avoid differences 90# between decimal and cdecimal 91plpy.info(str(x), x.__class__.__name__) 92return x 93$$ LANGUAGE plpythonu; 94 95SELECT * FROM test_type_conversion_numeric(100); 96SELECT * FROM test_type_conversion_numeric(-100); 97SELECT * FROM test_type_conversion_numeric(100.0); 98SELECT * FROM test_type_conversion_numeric(100.00); 99SELECT * FROM test_type_conversion_numeric(5000000000.5); 100SELECT * FROM test_type_conversion_numeric(1234567890.0987654321); 101SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321); 102SELECT * FROM test_type_conversion_numeric(null); 103 104 105CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$ 106plpy.info(x, type(x)) 107return x 108$$ LANGUAGE plpythonu; 109 110SELECT * FROM test_type_conversion_float4(100); 111SELECT * FROM test_type_conversion_float4(-100); 112SELECT * FROM test_type_conversion_float4(5000.5); 113SELECT * FROM test_type_conversion_float4(null); 114 115 116CREATE FUNCTION test_type_conversion_float8(x float8) RETURNS float8 AS $$ 117plpy.info(x, type(x)) 118return x 119$$ LANGUAGE plpythonu; 120 121SELECT * FROM test_type_conversion_float8(100); 122SELECT * FROM test_type_conversion_float8(-100); 123SELECT * FROM test_type_conversion_float8(5000000000.5); 124SELECT * FROM test_type_conversion_float8(null); 125SELECT * FROM test_type_conversion_float8(100100100.654321); 126 127 128CREATE FUNCTION test_type_conversion_oid(x oid) RETURNS oid AS $$ 129plpy.info(x, type(x)) 130return x 131$$ LANGUAGE plpythonu; 132 133SELECT * FROM test_type_conversion_oid(100); 134SELECT * FROM test_type_conversion_oid(2147483649); 135SELECT * FROM test_type_conversion_oid(null); 136 137 138CREATE FUNCTION test_type_conversion_text(x text) RETURNS text AS $$ 139plpy.info(x, type(x)) 140return x 141$$ LANGUAGE plpythonu; 142 143SELECT * FROM test_type_conversion_text('hello world'); 144SELECT * FROM test_type_conversion_text(null); 145 146 147CREATE FUNCTION test_type_conversion_bytea(x bytea) RETURNS bytea AS $$ 148plpy.info(x, type(x)) 149return x 150$$ LANGUAGE plpythonu; 151 152SELECT * FROM test_type_conversion_bytea('hello world'); 153SELECT * FROM test_type_conversion_bytea(E'null\\000byte'); 154SELECT * FROM test_type_conversion_bytea(null); 155 156 157CREATE FUNCTION test_type_marshal() RETURNS bytea AS $$ 158import marshal 159return marshal.dumps('hello world') 160$$ LANGUAGE plpythonu; 161 162CREATE FUNCTION test_type_unmarshal(x bytea) RETURNS text AS $$ 163import marshal 164try: 165 return marshal.loads(x) 166except ValueError, e: 167 return 'FAILED: ' + str(e) 168$$ LANGUAGE plpythonu; 169 170SELECT test_type_unmarshal(x) FROM test_type_marshal() x; 171 172 173-- 174-- Domains 175-- 176 177CREATE DOMAIN booltrue AS bool CHECK (VALUE IS TRUE OR VALUE IS NULL); 178 179CREATE FUNCTION test_type_conversion_booltrue(x booltrue, y bool) RETURNS booltrue AS $$ 180return y 181$$ LANGUAGE plpythonu; 182 183SELECT * FROM test_type_conversion_booltrue(true, true); 184SELECT * FROM test_type_conversion_booltrue(false, true); 185SELECT * FROM test_type_conversion_booltrue(true, false); 186 187 188CREATE DOMAIN uint2 AS int2 CHECK (VALUE >= 0); 189 190CREATE FUNCTION test_type_conversion_uint2(x uint2, y int) RETURNS uint2 AS $$ 191plpy.info(x, type(x)) 192return y 193$$ LANGUAGE plpythonu; 194 195SELECT * FROM test_type_conversion_uint2(100::uint2, 50); 196SELECT * FROM test_type_conversion_uint2(100::uint2, -50); 197SELECT * FROM test_type_conversion_uint2(null, 1); 198 199 200CREATE DOMAIN nnint AS int CHECK (VALUE IS NOT NULL); 201 202CREATE FUNCTION test_type_conversion_nnint(x nnint, y int) RETURNS nnint AS $$ 203return y 204$$ LANGUAGE plpythonu; 205 206SELECT * FROM test_type_conversion_nnint(10, 20); 207SELECT * FROM test_type_conversion_nnint(null, 20); 208SELECT * FROM test_type_conversion_nnint(10, null); 209 210 211CREATE DOMAIN bytea10 AS bytea CHECK (octet_length(VALUE) = 10 AND VALUE IS NOT NULL); 212 213CREATE FUNCTION test_type_conversion_bytea10(x bytea10, y bytea) RETURNS bytea10 AS $$ 214plpy.info(x, type(x)) 215return y 216$$ LANGUAGE plpythonu; 217 218SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold'); 219SELECT * FROM test_type_conversion_bytea10('hello world', 'hello wold'); 220SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world'); 221SELECT * FROM test_type_conversion_bytea10(null, 'hello word'); 222SELECT * FROM test_type_conversion_bytea10('hello word', null); 223 224 225-- 226-- Arrays 227-- 228 229CREATE FUNCTION test_type_conversion_array_int4(x int4[]) RETURNS int4[] AS $$ 230plpy.info(x, type(x)) 231return x 232$$ LANGUAGE plpythonu; 233 234SELECT * FROM test_type_conversion_array_int4(ARRAY[0, 100]); 235SELECT * FROM test_type_conversion_array_int4(ARRAY[0,-100,55]); 236SELECT * FROM test_type_conversion_array_int4(ARRAY[NULL,1]); 237SELECT * FROM test_type_conversion_array_int4(ARRAY[]::integer[]); 238SELECT * FROM test_type_conversion_array_int4(NULL); 239SELECT * FROM test_type_conversion_array_int4(ARRAY[[1,2,3],[4,5,6]]); 240SELECT * FROM test_type_conversion_array_int4(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]); 241SELECT * FROM test_type_conversion_array_int4('[2:4]={1,2,3}'); 242 243CREATE FUNCTION test_type_conversion_array_int8(x int8[]) RETURNS int8[] AS $$ 244plpy.info(x, type(x)) 245return x 246$$ LANGUAGE plpythonu; 247 248SELECT * FROM test_type_conversion_array_int8(ARRAY[[[1,2,NULL],[NULL,5,6]],[[NULL,8,9],[10,11,12]]]::int8[]); 249 250CREATE FUNCTION test_type_conversion_array_date(x date[]) RETURNS date[] AS $$ 251plpy.info(x, type(x)) 252return x 253$$ LANGUAGE plpythonu; 254 255SELECT * FROM test_type_conversion_array_date(ARRAY[[['2016-09-21','2016-09-22',NULL],[NULL,'2016-10-21','2016-10-22']], 256 [[NULL,'2016-11-21','2016-10-21'],['2015-09-21','2015-09-22','2014-09-21']]]::date[]); 257 258CREATE FUNCTION test_type_conversion_array_timestamp(x timestamp[]) RETURNS timestamp[] AS $$ 259plpy.info(x, type(x)) 260return x 261$$ LANGUAGE plpythonu; 262 263SELECT * FROM test_type_conversion_array_timestamp(ARRAY[[['2016-09-21 15:34:24.078792-04','2016-10-22 11:34:24.078795-04',NULL], 264 [NULL,'2016-10-21 11:34:25.078792-04','2016-10-21 11:34:24.098792-04']], 265 [[NULL,'2016-01-21 11:34:24.078792-04','2016-11-21 11:34:24.108792-04'], 266 ['2015-09-21 11:34:24.079792-04','2014-09-21 11:34:24.078792-04','2013-09-21 11:34:24.078792-04']]]::timestamp[]); 267 268 269CREATE OR REPLACE FUNCTION pyreturnmultidemint4(h int4, i int4, j int4, k int4 ) RETURNS int4[] AS $BODY$ 270m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] 271plpy.info(m, type(m)) 272return m 273$BODY$ LANGUAGE plpythonu; 274 275select pyreturnmultidemint4(8,5,3,2); 276 277CREATE OR REPLACE FUNCTION pyreturnmultidemint8(h int4, i int4, j int4, k int4 ) RETURNS int8[] AS $BODY$ 278m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] 279plpy.info(m, type(m)) 280return m 281$BODY$ LANGUAGE plpythonu; 282 283select pyreturnmultidemint8(5,5,3,2); 284 285CREATE OR REPLACE FUNCTION pyreturnmultidemfloat4(h int4, i int4, j int4, k int4 ) RETURNS float4[] AS $BODY$ 286m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] 287plpy.info(m, type(m)) 288return m 289$BODY$ LANGUAGE plpythonu; 290 291select pyreturnmultidemfloat4(6,5,3,2); 292 293CREATE OR REPLACE FUNCTION pyreturnmultidemfloat8(h int4, i int4, j int4, k int4 ) RETURNS float8[] AS $BODY$ 294m = [[[[x for x in range(h)] for y in range(i)] for z in range(j)] for w in range(k)] 295plpy.info(m, type(m)) 296return m 297$BODY$ LANGUAGE plpythonu; 298 299select pyreturnmultidemfloat8(7,5,3,2); 300 301CREATE FUNCTION test_type_conversion_array_text(x text[]) RETURNS text[] AS $$ 302plpy.info(x, type(x)) 303return x 304$$ LANGUAGE plpythonu; 305 306SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']); 307SELECT * FROM test_type_conversion_array_text(ARRAY[['foo', 'bar'],['foo2', 'bar2']]); 308 309 310CREATE FUNCTION test_type_conversion_array_bytea(x bytea[]) RETURNS bytea[] AS $$ 311plpy.info(x, type(x)) 312return x 313$$ LANGUAGE plpythonu; 314 315SELECT * FROM test_type_conversion_array_bytea(ARRAY[E'\\xdeadbeef'::bytea, NULL]); 316 317 318CREATE FUNCTION test_type_conversion_array_mixed1() RETURNS text[] AS $$ 319return [123, 'abc'] 320$$ LANGUAGE plpythonu; 321 322SELECT * FROM test_type_conversion_array_mixed1(); 323 324 325CREATE FUNCTION test_type_conversion_array_mixed2() RETURNS int[] AS $$ 326return [123, 'abc'] 327$$ LANGUAGE plpythonu; 328 329SELECT * FROM test_type_conversion_array_mixed2(); 330 331CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$ 332return [[1,2,3],[4,5]] 333$$ LANGUAGE plpythonu; 334 335SELECT * FROM test_type_conversion_mdarray_malformed(); 336 337CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$ 338return [[[[[[[1]]]]]]] 339$$ LANGUAGE plpythonu; 340 341SELECT * FROM test_type_conversion_mdarray_toodeep(); 342 343 344CREATE FUNCTION test_type_conversion_array_record() RETURNS type_record[] AS $$ 345return [{'first': 'one', 'second': 42}, {'first': 'two', 'second': 11}] 346$$ LANGUAGE plpythonu; 347 348SELECT * FROM test_type_conversion_array_record(); 349 350 351CREATE FUNCTION test_type_conversion_array_string() RETURNS text[] AS $$ 352return 'abc' 353$$ LANGUAGE plpythonu; 354 355SELECT * FROM test_type_conversion_array_string(); 356 357CREATE FUNCTION test_type_conversion_array_tuple() RETURNS text[] AS $$ 358return ('abc', 'def') 359$$ LANGUAGE plpythonu; 360 361SELECT * FROM test_type_conversion_array_tuple(); 362 363CREATE FUNCTION test_type_conversion_array_error() RETURNS int[] AS $$ 364return 5 365$$ LANGUAGE plpythonu; 366 367SELECT * FROM test_type_conversion_array_error(); 368 369 370-- 371-- Domains over arrays 372-- 373 374CREATE DOMAIN ordered_pair_domain AS integer[] CHECK (array_length(VALUE,1)=2 AND VALUE[1] < VALUE[2]); 375 376CREATE FUNCTION test_type_conversion_array_domain(x ordered_pair_domain) RETURNS ordered_pair_domain AS $$ 377plpy.info(x, type(x)) 378return x 379$$ LANGUAGE plpythonu; 380 381SELECT * FROM test_type_conversion_array_domain(ARRAY[0, 100]::ordered_pair_domain); 382SELECT * FROM test_type_conversion_array_domain(NULL::ordered_pair_domain); 383 384CREATE FUNCTION test_type_conversion_array_domain_check_violation() RETURNS ordered_pair_domain AS $$ 385return [2,1] 386$$ LANGUAGE plpythonu; 387SELECT * FROM test_type_conversion_array_domain_check_violation(); 388 389 390-- 391-- Arrays of domains 392-- 393 394CREATE FUNCTION test_read_uint2_array(x uint2[]) RETURNS uint2 AS $$ 395plpy.info(x, type(x)) 396return x[0] 397$$ LANGUAGE plpythonu; 398 399select test_read_uint2_array(array[1::uint2]); 400 401CREATE FUNCTION test_build_uint2_array(x int2) RETURNS uint2[] AS $$ 402return [x, x] 403$$ LANGUAGE plpythonu; 404 405select test_build_uint2_array(1::int2); 406select test_build_uint2_array(-1::int2); -- fail 407 408-- 409-- ideally this would work, but for now it doesn't, because the return value 410-- is [[2,4], [2,4]] which our conversion code thinks should become a 2-D 411-- integer array, not an array of arrays. 412-- 413CREATE FUNCTION test_type_conversion_domain_array(x integer[]) 414 RETURNS ordered_pair_domain[] AS $$ 415return [x, x] 416$$ LANGUAGE plpythonu; 417 418select test_type_conversion_domain_array(array[2,4]); 419select test_type_conversion_domain_array(array[4,2]); -- fail 420 421CREATE FUNCTION test_type_conversion_domain_array2(x ordered_pair_domain) 422 RETURNS integer AS $$ 423plpy.info(x, type(x)) 424return x[1] 425$$ LANGUAGE plpythonu; 426 427select test_type_conversion_domain_array2(array[2,4]); 428select test_type_conversion_domain_array2(array[4,2]); -- fail 429 430CREATE FUNCTION test_type_conversion_array_domain_array(x ordered_pair_domain[]) 431 RETURNS ordered_pair_domain AS $$ 432plpy.info(x, type(x)) 433return x[0] 434$$ LANGUAGE plpythonu; 435 436select test_type_conversion_array_domain_array(array[array[2,4]::ordered_pair_domain]); 437 438 439--- 440--- Composite types 441--- 442 443CREATE TABLE employee ( 444 name text, 445 basesalary integer, 446 bonus integer 447); 448 449INSERT INTO employee VALUES ('John', 100, 10), ('Mary', 200, 10); 450 451CREATE OR REPLACE FUNCTION test_composite_table_input(e employee) RETURNS integer AS $$ 452return e['basesalary'] + e['bonus'] 453$$ LANGUAGE plpythonu; 454 455SELECT name, test_composite_table_input(employee.*) FROM employee; 456 457ALTER TABLE employee DROP bonus; 458 459SELECT name, test_composite_table_input(employee.*) FROM employee; 460 461ALTER TABLE employee ADD bonus integer; 462UPDATE employee SET bonus = 10; 463 464SELECT name, test_composite_table_input(employee.*) FROM employee; 465 466CREATE TYPE named_pair AS ( 467 i integer, 468 j integer 469); 470 471CREATE OR REPLACE FUNCTION test_composite_type_input(p named_pair) RETURNS integer AS $$ 472return sum(p.values()) 473$$ LANGUAGE plpythonu; 474 475SELECT test_composite_type_input(row(1, 2)); 476 477ALTER TYPE named_pair RENAME TO named_pair_2; 478 479SELECT test_composite_type_input(row(1, 2)); 480 481 482-- 483-- Domains within composite 484-- 485 486CREATE TYPE nnint_container AS (f1 int, f2 nnint); 487 488CREATE FUNCTION nnint_test(x int, y int) RETURNS nnint_container AS $$ 489return {'f1': x, 'f2': y} 490$$ LANGUAGE plpythonu; 491 492SELECT nnint_test(null, 3); 493SELECT nnint_test(3, null); -- fail 494 495 496-- 497-- Domains of composite 498-- 499 500CREATE DOMAIN ordered_named_pair AS named_pair_2 CHECK((VALUE).i <= (VALUE).j); 501 502CREATE FUNCTION read_ordered_named_pair(p ordered_named_pair) RETURNS integer AS $$ 503return p['i'] + p['j'] 504$$ LANGUAGE plpythonu; 505 506SELECT read_ordered_named_pair(row(1, 2)); 507SELECT read_ordered_named_pair(row(2, 1)); -- fail 508 509CREATE FUNCTION build_ordered_named_pair(i int, j int) RETURNS ordered_named_pair AS $$ 510return {'i': i, 'j': j} 511$$ LANGUAGE plpythonu; 512 513SELECT build_ordered_named_pair(1,2); 514SELECT build_ordered_named_pair(2,1); -- fail 515 516CREATE FUNCTION build_ordered_named_pairs(i int, j int) RETURNS ordered_named_pair[] AS $$ 517return [{'i': i, 'j': j}, {'i': i, 'j': j+1}] 518$$ LANGUAGE plpythonu; 519 520SELECT build_ordered_named_pairs(1,2); 521SELECT build_ordered_named_pairs(2,1); -- fail 522 523 524-- 525-- Prepared statements 526-- 527 528CREATE OR REPLACE FUNCTION test_prep_bool_input() RETURNS int 529LANGUAGE plpythonu 530AS $$ 531plan = plpy.prepare("SELECT CASE WHEN $1 THEN 1 ELSE 0 END AS val", ['boolean']) 532rv = plpy.execute(plan, ['fa'], 5) # 'fa' is true in Python 533return rv[0]['val'] 534$$; 535 536SELECT test_prep_bool_input(); -- 1 537 538 539CREATE OR REPLACE FUNCTION test_prep_bool_output() RETURNS bool 540LANGUAGE plpythonu 541AS $$ 542plan = plpy.prepare("SELECT $1 = 1 AS val", ['int']) 543rv = plpy.execute(plan, [0], 5) 544plpy.info(rv[0]) 545return rv[0]['val'] 546$$; 547 548SELECT test_prep_bool_output(); -- false 549 550 551CREATE OR REPLACE FUNCTION test_prep_bytea_input(bb bytea) RETURNS int 552LANGUAGE plpythonu 553AS $$ 554plan = plpy.prepare("SELECT octet_length($1) AS val", ['bytea']) 555rv = plpy.execute(plan, [bb], 5) 556return rv[0]['val'] 557$$; 558 559SELECT test_prep_bytea_input(E'a\\000b'); -- 3 (embedded null formerly truncated value) 560 561 562CREATE OR REPLACE FUNCTION test_prep_bytea_output() RETURNS bytea 563LANGUAGE plpythonu 564AS $$ 565plan = plpy.prepare("SELECT decode('aa00bb', 'hex') AS val") 566rv = plpy.execute(plan, [], 5) 567plpy.info(rv[0]) 568return rv[0]['val'] 569$$; 570 571SELECT test_prep_bytea_output(); 572