Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hBl2I-0005Dp-MP for pgsql-hackers@arkaria.postgresql.org; Wed, 03 Apr 2019 18:54:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1hBl2G-0002mW-7i for pgsql-hackers@arkaria.postgresql.org; Wed, 03 Apr 2019 18:54:56 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hBl2F-0002mP-T9 for pgsql-hackers@lists.postgresql.org; Wed, 03 Apr 2019 18:54:55 +0000 Received: from ssl.nataraj.su ([195.54.209.170]) by magus.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1hBl28-0000ge-EG for pgsql-hackers@lists.postgresql.org; Wed, 03 Apr 2019 18:54:55 +0000 Received: from x200m.localnet (unknown [91.203.188.92]) by ssl.nataraj.su (Postfix) with ESMTPSA id D46B3511E294; Wed, 3 Apr 2019 21:54:16 +0300 (MSK) From: Nikolay Shaplov To: pgsql-hackers@lists.postgresql.org Cc: Michael Paquier , Alvaro Herrera , Tom Lane , Robert Haas Subject: Re: [PATCH] src/test/modules/dummy_index -- way to test reloptions from inside of access method Date: Wed, 03 Apr 2019 21:54:13 +0300 Message-ID: <1562184.o3gKksHyEI@x200m> User-Agent: KMail/5.2.3 (Linux/4.9.0-8-amd64; KDE/5.28.0; x86_64; ; ) In-Reply-To: <20190319070913.GE2899@paquier.xyz> References: <17071942.m9zZutALE6@x200m> <20190319070913.GE2899@paquier.xyz> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart5241259.YKYAKusuDl" Content-Transfer-Encoding: 7Bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk This is a multi-part message in MIME format. --nextPart5241259.YKYAKusuDl Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" =D0=92 =D0=BF=D0=B8=D1=81=D1=8C=D0=BC=D0=B5 =D0=BE=D1=82 =D0=B2=D1=82=D0=BE= =D1=80=D0=BD=D0=B8=D0=BA, 19 =D0=BC=D0=B0=D1=80=D1=82=D0=B0 2019 =D0=B3. 16= :09:13 MSK =D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0= =BB=D1=8C Michael=20 Paquier =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB: > > So I created src/test/modules/dummy_index, it does no real indexing, but > > it > > has all types of reloptions that can be set (reloption_int, > > reloption_real, > > reloption_bool, reloption_string and reloption_string2). It also has set > > of > > boolean GUC variables that enables test output concerning certain > > reloption: (do_test_reloption_int, do_test_reloption_real, > > do_test_reloption_bool and do_test_reloption_string and=20 > > do_test_reloption_string2) also set > > do_test_reloptions to true to get any output at all. > > Dummy index will print this output when index is created, and when reco= rd > > is inserted (this needed to check if your ALTER TABLE did well) > > Then you just use normal regression tests: turns on test output, sets s= ome > > reloption and check test output, that it properly reaches the access > > method > > internals. >=20 > Thanks for doing the effort to split that stuff. This looks like an > interesting base template for anybody willing to look after some > basics with index AMs, like what's done for FDWs with blackhole_fdw. I am not sure it is good template. Most methods are empty, and does not sho= w=20 any example of how it should work. If I am to create a template I would try to create index that just do seq s= can=20 of indexed values. It would have all code index must have, but the code of = the=20 index algorithm iteslf would be minimal. But it is another task. > Perhaps the name should be dummy_am_index or dummy_index_am? > dummy_index does not sound bad either. Actually I do not see any reason to do it, all indexes in postgres are=20 implemented as access methods, so it sounds as double naming for me. But I= =20 actually do not care about this name, if you think adding _am is better, so= I=20 did it. But i did not remove .c file names and did not change di- suffix to dia- in= the=20 code. Is it ok for you? > > While writing this module I kept in mind the idea that this module can = be > > also used for other am-related tests, so I separated the code into two > > parts: dummy_index.c has only code related to implementation of an empty > > access method, and all code related to reloptions tests were stored in= to > > direloptions.c. So in future somebody can add di[what_ever_he_wants].c > > whith his own tests code, add necessary calls to dummy_index.c, create > > some GUC variables, and has his own feature tested. >=20 > Here are some comments. I think that this could be simplified > further more. >=20 > The README file could have a more consistent format with the rest. > See for example dummy_seclabel/README. You could add a small > example with its usage. Good notion. Fixed it. > Is there any point in having string_option2? String reloptions are > already tested with string_option. There are two reasons for that: 1. We should test both behavior with validation function, and without one. = =46or=20 this we need two options, because we can change this in runtime 2. The implementation of string functions is a bit tricky. It allocates som= e=20 more memory after the Option structure, and string values are placed there.= It=20 works well with one string option, but I was not sure that is works properl= y=20 for two of them. I can imagine a bug that will show itself only with a seco= nd=20 option. So we anyway should test two.=20 > Also =3D> s/Seconf/Second/. > s/valudate/validate/. Thanks. I tried my best with aspell, but still missed something. > +-- Test behavior of second string option (there can be issues with second > one) What are those issues? This issues are listed in README. And also I've written them above. To prev= ent=20 confusion I've removed this issue notion. :-) One who want to know more, c= an=20 read README file ;-) =20 > + } else > + { > Code format does not follow the Postgres guidelines. You could fix > all that with an indent run. Oups, it's my favorite codestyle, I fall back to it when does not pay=20 attention. I've reindented the code, a good idea. Should come to it myself.= =2E.. > The ranges of the different values are not tested, wouldn't it be > better to test that as well? My idea was to test only things that can't be tested in regression tests.=20 Ranges are tested in regression tests ( I also wrote that tests) and it is= =20 better to leave it there. But the question is good, I would mention it in README file, to make it=20 clear.... > The way the test is configured with the strong dependencies between > the reloption types and the GUCs is much bug-prone I think. All of > that is present only to print a couple of WARNING messages with > specific values of values. So, why not removing the GUCs and the > printing logic which shows a subset of values?=20 I am afraid that we will get a mess that will work well, but it would be=20 difficult for a human to find any logic in the output. And sooner or later = we=20 will need it, when something will go wrong and somebody will try to find ou= t=20 why. So it is better to test one option at a time, and that's why mute test outp= ut=20 for other options. > Please note that these > are visible directly via pg_class.reloptions. So we could shave quite > some code. Values from pg_class are well tested in regression test. My point here is t= o=20 check that they reach index internal as expected. And there is a long way=20 between pg_class.reloptions and index internals. > Please note that the compilation of the module fails. > nodes/relation.h maybe is access/relation.h? You may want to review > all that. Hm... I do not quite understand how it get there and why in worked for me=20 before. But I changed it to nodes/pathnodes.h It was here because it is nee= ded=20 for PlannerInfo symbol.=20 PS. Sorry for long delays. I do not always have much time to do postgres... --nextPart5241259.YKYAKusuDl Content-Disposition: attachment; filename="dummy_index_v2.diff" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="dummy_index_v2.diff" diff --git a/.gitignore b/.gitignore index 794e35b..37331c2 100644 diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index dfd0956..742078e 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -7,6 +7,7 @@ include $(top_builddir)/src/Makefile.global SUBDIRS = \ brin \ commit_ts \ + dummy_index_am \ dummy_seclabel \ snapshot_too_old \ test_bloomfilter \ diff --git a/src/test/modules/dummy_index_am/.gitignore b/src/test/modules/dummy_index_am/.gitignore new file mode 100644 index 0000000..5dcb3ff --- /dev/null +++ b/src/test/modules/dummy_index_am/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/src/test/modules/dummy_index_am/Makefile b/src/test/modules/dummy_index_am/Makefile new file mode 100644 index 0000000..695941b --- /dev/null +++ b/src/test/modules/dummy_index_am/Makefile @@ -0,0 +1,21 @@ +# contrib/bloom/Makefile + +MODULE_big = dummy_index_am +OBJS = dummy_index.o direloptions.o $(WIN32RES) + +EXTENSION = dummy_index_am +DATA = dummy_index_am--1.0.sql +PGFILEDESC = "dummy index access method - needed for all kinds of tests" + +REGRESS = reloptions + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/dummy_index_am +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/dummy_index_am/README b/src/test/modules/dummy_index_am/README new file mode 100644 index 0000000..61f80d3 --- /dev/null +++ b/src/test/modules/dummy_index_am/README @@ -0,0 +1,45 @@ +Dummy index AM +============== + +Dummy index, an index module for testing am-related internal calls that can't be +properly tested inside production indexes, but better to be tested inside actual +access method module. + +Guidelines: +1. Keep this index as simple as as possible. It should not do any real indexing +(unless you need it for your tests), if you need it make it as simple as +possible; +2. Keep all code related to feature you test inside id[name_of_a_feature].c +file. dummy_index.c file should contain code that is needed for everyone, and +make calls to feature-related code; +3. Code related to your feature tests should be enabled and disabled by GUC +variables. Create as many boolean GUC variables as you need and set them on so +your test will know when it is time to do test output. Thus output from +different features tests are not interfered; +4. Add section to this README file that describes the general idea of what your +tests do. + +Reloptions tests +================ + +Some relotions testing are done in regression tests. There we can check if new +option value properly reaches pg_class, minimum/maximum checks, etc. But we +can't check if option value successfully reached index internal code when we are +dealing with production indexes. But we can do it here in Dummy index. +Here we check that values of reloptions properly reaches am-internals, and that +all reloption-related code works as expected. Several GUC variables are defined +to control test's output. do_test_reloptions turns on and off any +reloptions-related output. You will also get some test output in the case when +no relation options is set at all. do_test_reloption_int, +do_test_reloption_real, do_test_reloption_bool and do_test_reloption_string +allows to enable test output for int, real, boolean and string options. +do_test_reloption_string2 enables test output for another string option. We need +second string option, because a) string reloption implementation is a bit +tricky, and it is better to check that second value works as well; b) better to +check both cases: string option with validation function and without one, so we +need two string options. + + +Authors +======= +Nikolay Shaplov (Dummy index core, reloptions tests) diff --git a/src/test/modules/dummy_index_am/direloptions.c b/src/test/modules/dummy_index_am/direloptions.c new file mode 100644 index 0000000..3c7cca5 --- /dev/null +++ b/src/test/modules/dummy_index_am/direloptions.c @@ -0,0 +1,219 @@ +/*------------------------------------------------------------------------- + * + * direloptions.c + * Functions and variables needed for reloptions tests. + * + * Copyright (c) 2019, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/test/modules/dummy_index_am/direloptions.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "utils/rel.h" +#include "access/reloptions.h" +#include "utils/guc.h" + +#include "dummy_index.h" + + +/* parse table for fillRelOptions */ +relopt_parse_elt di_relopt_tab[5]; + + +/* Kind of relation options for dummy index */ +relopt_kind di_relopt_kind; + +/* GUC variables */ +static bool do_test_reloptions = false; +static bool do_test_reloption_int = false; +static bool do_test_reloption_real = false; +static bool do_test_reloption_bool = false; +static bool do_test_reloption_string = false; +static bool do_test_reloption_string2 = false; + +/* + * This function creates reloptions that would be used in reloptions tests + */ +void +create_reloptions_table() +{ + di_relopt_kind = add_reloption_kind(); + + add_int_reloption(di_relopt_kind, "int_option", + "Int option used for relotions test purposes", + 10, -10, 100); + di_relopt_tab[0].optname = "int_option"; + di_relopt_tab[0].opttype = RELOPT_TYPE_INT; + di_relopt_tab[0].offset = offsetof(DummyIndexOptions, int_option); + + add_real_reloption(di_relopt_kind, "real_option", + "Real option used for relotions test purposes", + 3.1415, -10, 100); + di_relopt_tab[1].optname = "real_option"; + di_relopt_tab[1].opttype = RELOPT_TYPE_REAL; + di_relopt_tab[1].offset = offsetof(DummyIndexOptions, real_option); + + + add_bool_reloption(di_relopt_kind, "bool_option", + "Boolean option used for relotions test purposes", + true); + di_relopt_tab[2].optname = "bool_option"; + di_relopt_tab[2].opttype = RELOPT_TYPE_BOOL; + di_relopt_tab[2].offset = offsetof(DummyIndexOptions, bool_option); + + add_string_reloption(di_relopt_kind, "string_option", + "String option used for relotions test purposes", + "DefaultValue", &validate_string_option); + di_relopt_tab[3].optname = "string_option"; + di_relopt_tab[3].opttype = RELOPT_TYPE_STRING; + di_relopt_tab[3].offset = offsetof(DummyIndexOptions, string_option_offset); + + add_string_reloption(di_relopt_kind, "string_option2", + "Second string option used for relotions test purposes", + "SecondDefaultValue", &validate_string_option); + di_relopt_tab[4].optname = "string_option2"; + di_relopt_tab[4].opttype = RELOPT_TYPE_STRING; + di_relopt_tab[4].offset = offsetof(DummyIndexOptions, string_option2_offset); + +} + +/* + * This function creates GUC variables that allows to turn on and off test + * output for different relopntions + */ +void +create_reloptions_test_GUC() +{ + DefineCustomBoolVariable("dummy_index.do_test_reloptions", + "Set to true if you are going to test reloptions.", + NULL, + &do_test_reloptions, + false, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); + + DefineCustomBoolVariable("dummy_index.do_test_reloption_int", + "Set to true if you are going to test int reloption.", + NULL, + &do_test_reloption_int, + false, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); + + DefineCustomBoolVariable("dummy_index.do_test_reloption_real", + "Set to true if you are going to test real reloption.", + NULL, + &do_test_reloption_real, + false, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); + + DefineCustomBoolVariable("dummy_index.do_test_reloption_bool", + "Set to true if you are going to test boolean reloption.", + NULL, + &do_test_reloption_bool, + false, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); + + DefineCustomBoolVariable("dummy_index.do_test_reloption_string", + "Set to true if you are going to test string reloption.", + NULL, + &do_test_reloption_string, + false, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); + DefineCustomBoolVariable("dummy_index.do_test_reloption_string2", + "Set to true if you are going to test second string reloption.", + NULL, + &do_test_reloption_string2, + false, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); +} + +/* + * Function prints output for reloptions tests if GUC variables switches are + * properly set on. + */ +void +print_reloptions_test_output(Relation index) +{ + if (do_test_reloptions) + { + if (!index->rd_options) + { + elog(WARNING, "No reloptions is set, default values will be chosen in module runtime"); + } + else + { + DummyIndexOptions *opt; + + opt = (DummyIndexOptions *) index->rd_options; + if (do_test_reloption_int) + { + elog(WARNING, "int_option = %d", opt->int_option); + } + if (do_test_reloption_real) + { + elog(WARNING, "real_option = %f", opt->real_option); + } + if (do_test_reloption_bool) + { + elog(WARNING, "bool_option = %d", opt->bool_option); + } + if (do_test_reloption_string) + { + char *str; + + str = (char *) opt + opt->string_option_offset; + elog(WARNING, "string_option = '%s'", str); + } + if (do_test_reloption_string2) + { + char *str; + + str = (char *) opt + opt->string_option2_offset; + elog(WARNING, "string_option2 = '%s'", str); + } + } + } +} + +/* + * Validation function for string_option reloption + */ +void +validate_string_option(const char *value) +{ + if (do_test_reloptions && do_test_reloption_string) + { + if (value) + elog(WARNING, "Validating string option '%s'", value); + else + elog(WARNING, "Validating string option with NULL value"); + } + if (!value || *value == 'I') + elog(ERROR, "This seems to be invalid value. Please set valid value"); +} diff --git a/src/test/modules/dummy_index_am/dummy_index.c b/src/test/modules/dummy_index_am/dummy_index.c new file mode 100644 index 0000000..bd4c665 --- /dev/null +++ b/src/test/modules/dummy_index_am/dummy_index.c @@ -0,0 +1,197 @@ +/*------------------------------------------------------------------------- + * + * dummy_index.c + * Dummy index AM main file. + * + * Copyright (c) 2019, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/test/modules/dummy_index_am/dummy_index.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/amapi.h" +#include "catalog/index.h" +#include "access/reloptions.h" +#include "utils/guc.h" +#include "dummy_index.h" + + +PG_FUNCTION_INFO_V1(dihandler); +PG_MODULE_MAGIC; + +void +_PG_init(void) + +{ + create_reloptions_table(); + create_reloptions_test_GUC(); +} + +/* + * Dummy index handler function: return IndexAmRoutine with access method + * parameters and callbacks. + */ +Datum +dihandler(PG_FUNCTION_ARGS) +{ + IndexAmRoutine *amroutine = makeNode(IndexAmRoutine); + + amroutine->amstrategies = 0; + amroutine->amsupport = 1; + amroutine->amcanorder = false; + amroutine->amcanorderbyop = false; + amroutine->amcanbackward = false; + amroutine->amcanunique = false; + amroutine->amcanmulticol = false; + amroutine->amoptionalkey = false; + amroutine->amsearcharray = false; + amroutine->amsearchnulls = false; + amroutine->amstorage = false; + amroutine->amclusterable = false; + amroutine->ampredlocks = false; + amroutine->amcanparallel = false; + amroutine->amcaninclude = false; + amroutine->amkeytype = InvalidOid; + + amroutine->ambuild = dibuild; + amroutine->ambuildempty = dibuildempty; + amroutine->aminsert = diinsert; + amroutine->ambulkdelete = dibulkdelete; + amroutine->amvacuumcleanup = divacuumcleanup; + amroutine->amcanreturn = NULL; + amroutine->amcostestimate = dicostestimate; + amroutine->amoptions = dioptions; + amroutine->amproperty = NULL; + amroutine->amvalidate = divalidate; + amroutine->ambeginscan = dibeginscan; + amroutine->amrescan = direscan; + amroutine->amgettuple = NULL; + amroutine->amgetbitmap = NULL; + amroutine->amendscan = diendscan; + amroutine->ammarkpos = NULL; + amroutine->amrestrpos = NULL; + amroutine->amestimateparallelscan = NULL; + amroutine->aminitparallelscan = NULL; + amroutine->amparallelrescan = NULL; + + PG_RETURN_POINTER(amroutine); +} + +IndexBuildResult * +dibuild(Relation heap, Relation index, IndexInfo *indexInfo) +{ + IndexBuildResult *result; + + result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult)); + + /* let's pretend that no tuples were scanned */ + result->heap_tuples = 0; + /* and no index tuples were created (that is true) */ + result->index_tuples = 0; + + print_reloptions_test_output(index); + + return result; +} + +void +dibuildempty(Relation index) +{ + /* Let's see what will happen if nothing is done here */ + /* Add tests for reloptions here */ +} + +bool +diinsert(Relation index, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) +{ + /* This is Dummy Index we do nothing on insert :-) */ + print_reloptions_test_output(index); + return false; + +} + +IndexBulkDeleteResult * +dibulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, void *callback_state) +{ + /* + * Do not delete anything; Return NULL as we have nothing to pass to + * amvacuumcleanup + */ + return NULL; +} + +IndexBulkDeleteResult * +divacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) +{ + /* Index have not been modified, so it is absolutely right to return NULL */ + return NULL; +} + +void +dicostestimate(PlannerInfo *root, IndexPath *path, double loop_count, + Cost *indexStartupCost, Cost *indexTotalCost, + Selectivity *indexSelectivity, double *indexCorrelation, + double *indexPages) +{ + /* Tell planner to never use this index! */ + *indexStartupCost = 1.0e10; /* AKA disable_cost */ + *indexTotalCost = 1.0e10; /* AKA disable_cost */ + + /* Do not care about the rest */ + *indexSelectivity = 1; + *indexCorrelation = 0; + *indexPages = 1; +} + +bytea * +dioptions(Datum reloptions, bool validate) +{ + relopt_value *options; + int numoptions; + DummyIndexOptions *rdopts; + + /* Parse the user-given reloptions */ + options = parseRelOptions(reloptions, validate, di_relopt_kind, &numoptions); + rdopts = allocateReloptStruct(sizeof(DummyIndexOptions), options, numoptions); + fillRelOptions((void *) rdopts, sizeof(DummyIndexOptions), options, numoptions, + validate, di_relopt_tab, lengthof(di_relopt_tab)); + + return (bytea *) rdopts; +} + +bool +divalidate(Oid opclassoid) +{ + /* Index does not really work so we are happy with any opclass */ + return true; +} + +IndexScanDesc +dibeginscan(Relation r, int nkeys, int norderbys) +{ + IndexScanDesc scan; + + /* Let's pretend we are doing something, just in case */ + scan = RelationGetIndexScan(r, nkeys, norderbys); + return scan; +} + +void +direscan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys) +{ + /* Just do nothing */ +} + +void +diendscan(IndexScanDesc scan) +{ + /* Do nothing */ +} diff --git a/src/test/modules/dummy_index_am/dummy_index.h b/src/test/modules/dummy_index_am/dummy_index.h new file mode 100644 index 0000000..fa6e405 --- /dev/null +++ b/src/test/modules/dummy_index_am/dummy_index.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * dummy_index.h + * Header for dummy_index_am index. + * + * Copyright (c) 2019, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/test/modules/dummy_index_am/dummy_index.h + * + *------------------------------------------------------------------------- + */ +#ifndef _DUMMY_INDEX_H_ +#define _DUMMY_INDEX_H_ + +#include "nodes/pathnodes.h" + +/* Dummy index options */ +typedef struct DummyIndexOptions +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int int_option; /* for reloptions test purposes */ + double real_option; /* for reloptions test purposes */ + bool bool_option; /* for reloptions test purposes */ + int string_option_offset; /* for reloptions test purposes */ + int string_option2_offset; /* for reloptions test purposes */ +} DummyIndexOptions; + +extern void _PG_init(void); + +/* index access method interface functions */ +extern bool divalidate(Oid opclassoid); +extern bool diinsert(Relation index, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); +extern IndexScanDesc dibeginscan(Relation r, int nkeys, int norderbys); +extern void direscan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys); +extern void diendscan(IndexScanDesc scan); +extern IndexBuildResult *dibuild(Relation heap, Relation index, + struct IndexInfo *indexInfo); +extern void dibuildempty(Relation index); +extern IndexBulkDeleteResult *dibulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *divacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern bytea *dioptions(Datum reloptions, bool validate); +extern void dicostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, Cost *indexStartupCost, + Cost *indexTotalCost, Selectivity *indexSelectivity, + double *indexCorrelation, double *indexPages); + +/* direoptions.c */ +/* Functions and variables needed for reloptions tests*/ + +extern relopt_parse_elt di_relopt_tab[5]; +extern relopt_kind di_relopt_kind; + +extern void create_reloptions_table(void); +extern void create_reloptions_test_GUC(void); +extern void print_reloptions_test_output(Relation index); +extern void validate_string_option(const char *value); + +#endif diff --git a/src/test/modules/dummy_index_am/dummy_index_am--1.0.sql b/src/test/modules/dummy_index_am/dummy_index_am--1.0.sql new file mode 100644 index 0000000..8049c43 --- /dev/null +++ b/src/test/modules/dummy_index_am/dummy_index_am--1.0.sql @@ -0,0 +1,20 @@ +/* src/test/modules/dummy_index/dummy_index_am--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION dummy_index_am" to load this file. \quit + +CREATE FUNCTION dihandler(internal) +RETURNS index_am_handler +AS 'MODULE_PATHNAME' +LANGUAGE C; + +-- Access method +CREATE ACCESS METHOD dummy_index_am TYPE INDEX HANDLER dihandler; +COMMENT ON ACCESS METHOD dummy_index_am IS 'dummy index am is access method for test purposes'; + +-- Opclasses + +CREATE OPERATOR CLASS int4_ops +DEFAULT FOR TYPE int4 USING dummy_index_am AS + OPERATOR 1 =(int4, int4), + FUNCTION 1 hashint4(int4); diff --git a/src/test/modules/dummy_index_am/dummy_index_am.control b/src/test/modules/dummy_index_am/dummy_index_am.control new file mode 100644 index 0000000..93fb57b --- /dev/null +++ b/src/test/modules/dummy_index_am/dummy_index_am.control @@ -0,0 +1,5 @@ +# dummy_index extension +comment = 'dummmy_index_am access method that does nothin and is used for test purposes' +default_version = '1.0' +module_pathname = '$libdir/dummy_index_am' +relocatable = true diff --git a/src/test/modules/dummy_index_am/expected/reloptions.out b/src/test/modules/dummy_index_am/expected/reloptions.out new file mode 100644 index 0000000..f80b2fc --- /dev/null +++ b/src/test/modules/dummy_index_am/expected/reloptions.out @@ -0,0 +1,97 @@ +CREATE EXTENSION dummy_index_am; +SET dummy_index.do_test_reloptions to true; +CREATE TABLE tst (i int4); +-- Test reloptions behavior when no reloption is set +CREATE INDEX test_idx ON tst USING dummy_index_am (i); +WARNING: No reloptions is set, default values will be chosen in module runtime +DROP INDEX test_idx; +-- Test behavior of int option (default and non default values) +SET dummy_index.do_test_reloption_int to true; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (bool_option = false); +WARNING: int_option = 10 +DROP INDEX test_idx; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (int_option = 5); +WARNING: int_option = 5 +ALTER INDEX test_idx SET (int_option = 3); +INSERT INTO tst VALUES(1); +WARNING: int_option = 3 +ALTER INDEX test_idx SET (bool_option = false); +ALTER INDEX test_idx RESET (int_option); +INSERT INTO tst VALUES(1); +WARNING: int_option = 10 +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_int to false; +-- Test behavior of real option (default and non default values) +SET dummy_index.do_test_reloption_real to true; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (bool_option = false); +WARNING: real_option = 3.141500 +DROP INDEX test_idx; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (real_option = 5); +WARNING: real_option = 5.000000 +ALTER INDEX test_idx SET (real_option = 3); +INSERT INTO tst VALUES(1); +WARNING: real_option = 3.000000 +ALTER INDEX test_idx SET (bool_option = false); +ALTER INDEX test_idx RESET (real_option); +INSERT INTO tst VALUES(1); +WARNING: real_option = 3.141500 +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_real to false; +-- Test behavior of bool option (default and non default values) +SET dummy_index.do_test_reloption_bool to true; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (int_option = 5); +WARNING: bool_option = 1 +DROP INDEX test_idx; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (bool_option = false); +WARNING: bool_option = 0 +ALTER INDEX test_idx SET (bool_option = true); +INSERT INTO tst VALUES(1); +WARNING: bool_option = 1 +ALTER INDEX test_idx SET (int_option = 5, bool_option = false); +ALTER INDEX test_idx RESET (bool_option); +INSERT INTO tst VALUES(1); +WARNING: bool_option = 1 +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_bool to false; +-- Test behavior of string option (default and non default values + validate +-- function) +SET dummy_index.do_test_reloption_string to true; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (int_option = 5); +WARNING: string_option = 'DefaultValue' +DROP INDEX test_idx; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option = +"Invalid_value"); +WARNING: Validating string option 'Invalid_value' +ERROR: This seems to be invalid value. Please set valid value +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option = +"Valid_value"); +WARNING: Validating string option 'Valid_value' +WARNING: string_option = 'Valid_value' +ALTER INDEX test_idx SET (string_option = "Valid_value_2", int_option = 5); +WARNING: Validating string option 'Valid_value_2' +INSERT INTO tst VALUES(1); +WARNING: string_option = 'Valid_value_2' +ALTER INDEX test_idx RESET (string_option); +INSERT INTO tst VALUES(1); +WARNING: string_option = 'DefaultValue' +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_string to false; +-- Test behavior of second string option +-- Testing default and non default values + _no_ validate function) +SET dummy_index.do_test_reloption_string2 to true; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option = +"Something"); +WARNING: string_option2 = 'SecondDefaultValue' +DROP INDEX test_idx; +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option2 = +"Some_value"); +WARNING: string_option2 = 'Some_value' +ALTER INDEX test_idx SET (string_option2 = "Valid_value_2", int_option = 5); +INSERT INTO tst VALUES(1); +WARNING: string_option2 = 'Valid_value_2' +ALTER INDEX test_idx RESET (string_option2); +INSERT INTO tst VALUES(1); +WARNING: string_option2 = 'SecondDefaultValue' +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_string2 to false; +SET dummy_index.do_test_reloptions to false; diff --git a/src/test/modules/dummy_index_am/sql/reloptions.sql b/src/test/modules/dummy_index_am/sql/reloptions.sql new file mode 100644 index 0000000..804a358 --- /dev/null +++ b/src/test/modules/dummy_index_am/sql/reloptions.sql @@ -0,0 +1,101 @@ +CREATE EXTENSION dummy_index_am; + +SET dummy_index.do_test_reloptions to true; + +CREATE TABLE tst (i int4); + +-- Test reloptions behavior when no reloption is set +CREATE INDEX test_idx ON tst USING dummy_index_am (i); +DROP INDEX test_idx; + +-- Test behavior of int option (default and non default values) +SET dummy_index.do_test_reloption_int to true; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (bool_option = false); +DROP INDEX test_idx; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (int_option = 5); + +ALTER INDEX test_idx SET (int_option = 3); +INSERT INTO tst VALUES(1); +ALTER INDEX test_idx SET (bool_option = false); +ALTER INDEX test_idx RESET (int_option); +INSERT INTO tst VALUES(1); + +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_int to false; + +-- Test behavior of real option (default and non default values) +SET dummy_index.do_test_reloption_real to true; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (bool_option = false); +DROP INDEX test_idx; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (real_option = 5); + +ALTER INDEX test_idx SET (real_option = 3); +INSERT INTO tst VALUES(1); +ALTER INDEX test_idx SET (bool_option = false); +ALTER INDEX test_idx RESET (real_option); +INSERT INTO tst VALUES(1); + +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_real to false; + +-- Test behavior of bool option (default and non default values) +SET dummy_index.do_test_reloption_bool to true; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (int_option = 5); +DROP INDEX test_idx; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (bool_option = false); + +ALTER INDEX test_idx SET (bool_option = true); +INSERT INTO tst VALUES(1); +ALTER INDEX test_idx SET (int_option = 5, bool_option = false); +ALTER INDEX test_idx RESET (bool_option); +INSERT INTO tst VALUES(1); + +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_bool to false; + +-- Test behavior of string option (default and non default values + validate +-- function) +SET dummy_index.do_test_reloption_string to true; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (int_option = 5); +DROP INDEX test_idx; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option = +"Invalid_value"); + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option = +"Valid_value"); + +ALTER INDEX test_idx SET (string_option = "Valid_value_2", int_option = 5); +INSERT INTO tst VALUES(1); +ALTER INDEX test_idx RESET (string_option); +INSERT INTO tst VALUES(1); + +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_string to false; + +-- Test behavior of second string option +-- Testing default and non default values + _no_ validate function) +SET dummy_index.do_test_reloption_string2 to true; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option = +"Something"); +DROP INDEX test_idx; + +CREATE INDEX test_idx ON tst USING dummy_index_am (i) WITH (string_option2 = +"Some_value"); + +ALTER INDEX test_idx SET (string_option2 = "Valid_value_2", int_option = 5); +INSERT INTO tst VALUES(1); +ALTER INDEX test_idx RESET (string_option2); +INSERT INTO tst VALUES(1); + +DROP INDEX test_idx; +SET dummy_index.do_test_reloption_string2 to false; +SET dummy_index.do_test_reloptions to false; --nextPart5241259.YKYAKusuDl--