KaiGai Kohei wrote:

> (1) Who/Where should allocate a string area?
> 
> + /* Note that this assumes that the variable is already allocated! */
> + #define HANDLE_STRING_RELOPTION(optname, var, option)                 \
> +       if (HAVE_RELOPTION(optname, option))                        \
> +       {                                                           \
> +           strcpy(var,                                             \
> +                  option.isset ? option.values.string_val :        \
> +                  ((relopt_string *) option.gen)->default_val);    \
> +           continue;                                               \
> +       }
> 
> I think HANDLE_STRING_RELOPTION() should allocate a string area via
> pstrdup(). If we have to put individual pstrdup() for each reloptions,
> it will make noisy listing of codes.
> 
> How do you think:
> 
> #define HANDLE_STRING_RELOPTION(optname, var, option)             \
>     if (HAVE_RELOPTION(optname, option))                          \
>     {                                                             \
>         char *tmp = (option.isset ? option.values.string_val :    \
>                     ((relopt_string *) option.gen)->default_val); \
>         var = pstrdup(tmp);                                       \
>         continue;                                                 \
>     }

Well, that's precisely the problem with string options.  If we want
memory to be freed properly, we can only allocate a single chunk which
is what's going to be stored under the rd_options bytea pointer.
Allocating separately doesn't work because we need to rebuild the
relcache entry (freeing it and allocating a new one) when it is
invalidated for whatever reason.  Since the relcache code cannot follow
a pointer stored in the bytea area, this would result in a permanent
memory leak.

So the rule I came up with is that the caller is responsible for
allocating it -- but it must be inside the bytea area to be returned.
Below is a sample amoptions routine to show how it works.  Note that
this is exactly why I said that only a single string option can be
supported.

If you have a better idea, I'm all ears.

> (2) How does it represent NULL in string_option?
> 
> It seems to me we cannot represent a NULL string in the default.
> Is it possible to add a mark to indicate NULL, like "bool default_null"
> within struct relopt_string?

Ah, good point.  I'll have a look at this.

> (3) heap_reloptions() from RelationParseRelOptions() makes a trouble.

This is the same as (1) actually.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
/* must follow StdRdOptions conventions */
typedef struct BtOptions
{
        int32   vl_len_;
        int             fillfactor;
        char    teststring[1];
} BtOptions;


Datum
btoptions(PG_FUNCTION_ARGS)
{
        Datum           reloptions = PG_GETARG_DATUM(0);
        bool            validate = PG_GETARG_BOOL(1);
        bytea      *result;
        relopt_value *options;
        int                     numoptions;
        int                     i;
        static  bool initialized = false;

        if (!initialized)
        {
                add_string_reloption(RELOPT_KIND_BTREE, "teststring", NULL,
                                                         "helluva string here 
and there!");
                initialized = true;
        }

        options = parseRelOptions(reloptions, validate, RELOPT_KIND_BTREE, 
&numoptions);

        /* if none set, we're done */
        if (numoptions == 0)
                result = NULL;
        else
        {
                BtOptions *rdopts;
                int             tstrlen;

                for (i = 0; i < numoptions; i++)
                {
                        if (HAVE_RELOPTION("teststring", options[i]))
                        {
                                tstrlen = options[i].isset ?
                                        strlen(options[i].values.string_val) :
                                        ((relopt_string *) 
options[i].gen)->default_len;
                                break;
                        }
                }

                rdopts = palloc0(sizeof(BtOptions) + tstrlen + 1);

                for (i = 0; i < numoptions; i++)
                {
                        HANDLE_INT_RELOPTION("fillfactor", rdopts->fillfactor, 
options[i]);
                        HANDLE_STRING_RELOPTION("teststring", 
rdopts->teststring, options[i]);
                }

                pfree(options);
                SET_VARSIZE(rdopts, sizeof(BtOptions) + tstrlen + 1);
                result = (bytea *) rdopts;
        }

        if (result)
                PG_RETURN_BYTEA_P(result);
        PG_RETURN_NULL();
}
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to