Skip to content

Commit dfe6ac2

Browse files
committedFeb 14, 2019
Allow to store record type as a scalar variable
1 parent d00692b commit dfe6ac2

File tree

4 files changed

+95
-39
lines changed

4 files changed

+95
-39
lines changed
 

‎expected/pg_variables.out

+27-3
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,27 @@ SELECT package FROM pgv_stats() WHERE package = 'vars4';
759759
---------
760760
(0 rows)
761761

762+
-- Record variables as scalar
763+
SELECT pgv_set('vars5', 'r1', row(1, 'str11'));
764+
pgv_set
765+
---------
766+
767+
(1 row)
768+
769+
SELECT pgv_get('vars5', 'r1', NULL::record);
770+
pgv_get
771+
-----------
772+
(1,str11)
773+
(1 row)
774+
775+
SELECT pgv_set('vars5', 'r1', row(1, 'str11'), true); -- fail
776+
ERROR: variable "r1" already created as NOT TRANSACTIONAL
777+
SELECT pgv_insert('vars5', 'r1', row(1, 'str11')); -- fail
778+
ERROR: "r1" isn't a record variable
779+
SELECT pgv_select('vars5', 'r1'); -- fail
780+
ERROR: "r1" isn't a record variable
781+
SELECT pgv_get('vars3', 'r1', NULL::record); -- fail
782+
ERROR: "r1" isn't a scalar variable
762783
-- Manipulate variables
763784
SELECT * FROM pgv_list() order by package, name;
764785
package | name | is_transactional
@@ -786,15 +807,17 @@ SELECT * FROM pgv_list() order by package, name;
786807
vars2 | j2 | f
787808
vars3 | r1 | f
788809
vars3 | r2 | f
789-
(23 rows)
810+
vars5 | r1 | f
811+
(24 rows)
790812

791813
SELECT package FROM pgv_stats() order by package;
792814
package
793815
---------
794816
vars
795817
vars2
796818
vars3
797-
(3 rows)
819+
vars5
820+
(4 rows)
798821

799822
SELECT pgv_remove('vars', 'int3');
800823
ERROR: unrecognized variable "int3"
@@ -849,7 +872,8 @@ SELECT * FROM pgv_list() order by package, name;
849872
vars | tstzNULL | f
850873
vars3 | r1 | f
851874
vars3 | r2 | f
852-
(20 rows)
875+
vars5 | r1 | f
876+
(21 rows)
853877

854878
SELECT pgv_free();
855879
pgv_free

‎pg_variables.c

+53-36
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,10 @@ static void ensurePackagesHashExists(void);
5050
static void getKeyFromName(text *name, char *key);
5151

5252
static Package *getPackageByName(text *name, bool create, bool strict);
53-
static Variable *getVariableInternal(Package *package,
54-
text *name, Oid typid,
55-
bool strict);
56-
static Variable *createVariableInternal(Package *package,
57-
text *name, Oid typid,
58-
bool is_transactional);
53+
static Variable *getVariableInternal(Package *package, text *name,
54+
Oid typid, bool is_record, bool strict);
55+
static Variable *createVariableInternal(Package *package, text *name, Oid typid,
56+
bool is_record, bool is_transactional);
5957
static void removePackageInternal(Package *package);
6058
static void resetVariablesCache(bool with_package);
6159

@@ -65,7 +63,7 @@ static void releaseSavepoint(TransObject *object, TransObjectType type);
6563
static void rollbackSavepoint(TransObject *object, TransObjectType type);
6664

6765
static void copyValue(VarState *src, VarState *dest, Variable *destVar);
68-
static void freeValue(VarState *varstate, Oid typid);
66+
static void freeValue(VarState *varstate, bool is_record);
6967
static void removeState(TransObject *object, TransObjectType type,
7068
TransState *stateToDelete);
7169
static bool isObjectChangedInCurrentTrans(TransObject *object);
@@ -160,7 +158,7 @@ variable_set(text *package_name, text *var_name,
160158
ScalarVar *scalar;
161159

162160
package = getPackageByName(package_name, true, false);
163-
variable = createVariableInternal(package, var_name, typid,
161+
variable = createVariableInternal(package, var_name, typid, false,
164162
is_transactional);
165163

166164
scalar = &(GetActualValue(variable).scalar);
@@ -197,7 +195,7 @@ variable_get(text *package_name, text *var_name,
197195
return 0;
198196
}
199197

200-
variable = getVariableInternal(package, var_name, typid, strict);
198+
variable = getVariableInternal(package, var_name, typid, false, strict);
201199

202200
if (variable == NULL)
203201
{
@@ -343,7 +341,7 @@ variable_insert(PG_FUNCTION_ARGS)
343341
VARSIZE_ANY_EXHDR(var_name)) != 0)
344342
{
345343
variable = createVariableInternal(package, var_name, RECORDOID,
346-
is_transactional);
344+
true, is_transactional);
347345
LastVariable = variable;
348346
}
349347
else
@@ -455,7 +453,8 @@ variable_update(PG_FUNCTION_ARGS)
455453
strncmp(VARDATA_ANY(var_name), GetName(LastVariable),
456454
VARSIZE_ANY_EXHDR(var_name)) != 0)
457455
{
458-
variable = getVariableInternal(package, var_name, RECORDOID, true);
456+
variable = getVariableInternal(package, var_name, RECORDOID, true,
457+
true);
459458
LastVariable = variable;
460459
}
461460
else
@@ -543,7 +542,8 @@ variable_delete(PG_FUNCTION_ARGS)
543542
strncmp(VARDATA_ANY(var_name), GetName(LastVariable),
544543
VARSIZE_ANY_EXHDR(var_name)) != 0)
545544
{
546-
variable = getVariableInternal(package, var_name, RECORDOID, true);
545+
variable = getVariableInternal(package, var_name, RECORDOID, true,
546+
true);
547547
LastVariable = variable;
548548
}
549549
else
@@ -592,7 +592,8 @@ variable_select(PG_FUNCTION_ARGS)
592592
var_name = PG_GETARG_TEXT_PP(1);
593593

594594
package = getPackageByName(package_name, false, true);
595-
variable = getVariableInternal(package, var_name, RECORDOID, true);
595+
variable = getVariableInternal(package, var_name, RECORDOID, true,
596+
true);
596597

597598
record = &(GetActualValue(variable).record);
598599

@@ -667,7 +668,7 @@ variable_select_by_value(PG_FUNCTION_ARGS)
667668
}
668669

669670
package = getPackageByName(package_name, false, true);
670-
variable = getVariableInternal(package, var_name, RECORDOID, true);
671+
variable = getVariableInternal(package, var_name, RECORDOID, true, true);
671672

672673
if (!value_is_null)
673674
check_record_key(variable, value_type);
@@ -736,7 +737,8 @@ variable_select_by_values(PG_FUNCTION_ARGS)
736737
var_name = PG_GETARG_TEXT_PP(1);
737738

738739
package = getPackageByName(package_name, false, true);
739-
variable = getVariableInternal(package, var_name, RECORDOID, true);
740+
variable = getVariableInternal(package, var_name, RECORDOID, true,
741+
true);
740742

741743
check_record_key(variable, ARR_ELEMTYPE(values));
742744

@@ -870,7 +872,7 @@ remove_variable(PG_FUNCTION_ARGS)
870872
var_name = PG_GETARG_TEXT_PP(1);
871873

872874
package = getPackageByName(package_name, false, true);
873-
variable = getVariableInternal(package, var_name, InvalidOid, true);
875+
variable = getVariableInternal(package, var_name, InvalidOid, false, true);
874876

875877
/* Add package to changes list, so we can remove it if it is empty */
876878
if (!isObjectChangedInCurrentTrans(&package->transObject))
@@ -908,7 +910,6 @@ remove_package(PG_FUNCTION_ARGS)
908910
{
909911
Package *package;
910912
text *package_name;
911-
char key[NAMEDATALEN];
912913

913914
if (PG_ARGISNULL(0))
914915
ereport(ERROR,
@@ -1430,7 +1431,8 @@ getPackageByName(text *name, bool create, bool strict)
14301431
* flag 'is_transactional' of this variable is unknown.
14311432
*/
14321433
static Variable *
1433-
getVariableInternal(Package *package, text *name, Oid typid, bool strict)
1434+
getVariableInternal(Package *package, text *name, Oid typid, bool is_record,
1435+
bool strict)
14341436
{
14351437
Variable *variable;
14361438
char key[NAMEDATALEN];
@@ -1447,15 +1449,25 @@ getVariableInternal(Package *package, text *name, Oid typid, bool strict)
14471449
/* Check variable type */
14481450
if (found)
14491451
{
1450-
if (typid != InvalidOid && variable->typid != typid)
1452+
if (typid != InvalidOid)
14511453
{
1452-
char *var_type = DatumGetCString(DirectFunctionCall1(regtypeout,
1453-
ObjectIdGetDatum(variable->typid)));
1454+
if (variable->typid != typid)
1455+
{
1456+
char *var_type = DatumGetCString(
1457+
DirectFunctionCall1(regtypeout,
1458+
ObjectIdGetDatum(variable->typid)));
14541459

1455-
ereport(ERROR,
1456-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1457-
errmsg("variable \"%s\" requires \"%s\" value",
1458-
key, var_type)));
1460+
ereport(ERROR,
1461+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1462+
errmsg("variable \"%s\" requires \"%s\" value",
1463+
key, var_type)));
1464+
}
1465+
1466+
if (variable->is_record != is_record)
1467+
ereport(ERROR,
1468+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1469+
errmsg("\"%s\" isn't a %s variable",
1470+
key, is_record ? "record" : "scalar")));
14591471
}
14601472
if (!GetActualState(variable)->is_valid && strict)
14611473
ereport(ERROR,
@@ -1475,11 +1487,11 @@ getVariableInternal(Package *package, text *name, Oid typid, bool strict)
14751487

14761488
/*
14771489
* Create a variable or return a pointer to existing one.
1478-
* Function is useful to set new value to variable and
1479-
* flag 'is_transactional' is known.
1490+
* Function is useful to set new value to variable and flag 'is_transactional'
1491+
* is known.
14801492
*/
14811493
static Variable *
1482-
createVariableInternal(Package *package, text *name, Oid typid,
1494+
createVariableInternal(Package *package, text *name, Oid typid, bool is_record,
14831495
bool is_transactional)
14841496
{
14851497
Variable *variable;
@@ -1521,6 +1533,12 @@ createVariableInternal(Package *package, text *name, Oid typid,
15211533
key, var_type)));
15221534
}
15231535

1536+
if (variable->is_record != is_record)
1537+
ereport(ERROR,
1538+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1539+
errmsg("\"%s\" isn't a %s variable",
1540+
key, is_record ? "record" : "scalar")));
1541+
15241542
/*
15251543
* Savepoint must be created when variable changed in current
15261544
* transaction. For each transaction level there should be a
@@ -1540,14 +1558,15 @@ createVariableInternal(Package *package, text *name, Oid typid,
15401558
/* Variable entry was created, so initialize new variable. */
15411559
variable->typid = typid;
15421560
variable->package = package;
1561+
variable->is_record = is_record;
15431562
variable->is_transactional = is_transactional;
15441563

15451564
dlist_init(GetStateStorage(variable));
15461565
varState = MemoryContextAllocZero(pack_hctx(package, is_transactional),
15471566
sizeof(VarState));
15481567

15491568
dlist_push_head(GetStateStorage(variable), &varState->state.node);
1550-
if (typid != RECORDOID)
1569+
if (!variable->is_record)
15511570
{
15521571
ScalarVar *scalar = &(varState->value.scalar);
15531572

@@ -1578,7 +1597,7 @@ copyValue(VarState *src, VarState *dest, Variable *destVar)
15781597

15791598
oldcxt = MemoryContextSwitchTo(destVar->package->hctxTransact);
15801599

1581-
if (destVar->typid == RECORDOID)
1600+
if (destVar->is_record)
15821601
/* copy record value */
15831602
{
15841603
HASH_SEQ_STATUS rstat;
@@ -1610,19 +1629,17 @@ copyValue(VarState *src, VarState *dest, Variable *destVar)
16101629
}
16111630

16121631
static void
1613-
freeValue(VarState *varstate, Oid typid)
1632+
freeValue(VarState *varstate, bool is_record)
16141633
{
1615-
if (typid == RECORDOID && varstate->value.record.hctx)
1634+
if (is_record && varstate->value.record.hctx)
16161635
{
16171636
/* All records will be freed */
16181637
MemoryContextDelete(varstate->value.record.hctx);
16191638
}
1620-
else if (varstate->value.scalar.typbyval == false &&
1639+
else if (!is_record && varstate->value.scalar.typbyval == false &&
16211640
varstate->value.scalar.is_null == false &&
16221641
varstate->value.scalar.value)
1623-
{
16241642
pfree(DatumGetPointer(varstate->value.scalar.value));
1625-
}
16261643
}
16271644

16281645
static void
@@ -1632,7 +1649,7 @@ removeState(TransObject *object, TransObjectType type, TransState *stateToDelete
16321649
{
16331650
Variable *var = (Variable *) object;
16341651

1635-
freeValue((VarState *) stateToDelete, var->typid);
1652+
freeValue((VarState *) stateToDelete, var->is_record);
16361653
}
16371654
dlist_delete(&stateToDelete->node);
16381655
pfree(stateToDelete);

‎pg_variables.h

+5
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ typedef struct Variable
101101
TransObject transObject;
102102
Package *package;
103103
Oid typid;
104+
/*
105+
* We need an additional flag to determine variable's type since we can
106+
* store record type DATUM within scalar variable
107+
*/
108+
bool is_record;
104109

105110
/*
106111
* The flag determines the further behavior of the variable. Can be

‎sql/pg_variables.sql

+10
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,16 @@ SELECT pgv_insert('vars4', 'r2', row(1, 'str1', 'str2'));
215215
SELECT pgv_remove('vars4', 'r2');
216216
SELECT package FROM pgv_stats() WHERE package = 'vars4';
217217

218+
-- Record variables as scalar
219+
SELECT pgv_set('vars5', 'r1', row(1, 'str11'));
220+
SELECT pgv_get('vars5', 'r1', NULL::record);
221+
SELECT pgv_set('vars5', 'r1', row(1, 'str11'), true); -- fail
222+
223+
SELECT pgv_insert('vars5', 'r1', row(1, 'str11')); -- fail
224+
SELECT pgv_select('vars5', 'r1'); -- fail
225+
226+
SELECT pgv_get('vars3', 'r1', NULL::record); -- fail
227+
218228
-- Manipulate variables
219229
SELECT * FROM pgv_list() order by package, name;
220230
SELECT package FROM pgv_stats() order by package;

0 commit comments

Comments
 (0)
Please sign in to comment.