Re: Executing Dynamic DDL

From: Michael Fuhr <mike(at)fuhr(dot)org>
To: Samer Abukhait <abukhait(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: Executing Dynamic DDL
Date: 2005-05-18 13:23:19
Message-ID: 20050518132319.GA58577@winnie.fuhr.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On Wed, May 18, 2005 at 09:07:55AM +0200, Samer Abukhait wrote:
>
> i am trying to execute an 'alter table' statement dynamically.. it
> seems that "execute" only works with DML..

A simple example shows that EXECUTE does indeed work with DDL:

CREATE TABLE foo (col1 integer);

CREATE FUNCTION execute_ddl() RETURNS void AS $$
BEGIN
EXECUTE 'ALTER TABLE foo ADD col2 timestamp NOT NULL';
RETURN;
END;
$$ LANGUAGE plpgsql VOLATILE;

\d foo
Table "public.foo"
Column | Type | Modifiers
--------+---------+-----------
col1 | integer |

SELECT execute_ddl();

\d foo
Table "public.foo"
Column | Type | Modifiers
--------+-----------------------------+-----------
col1 | integer |
col2 | timestamp without time zone | not null

The problem appears to be in the function's logic:

> create or replace function em.process_table (
> p_table varchar)
> returns void as $$
> declare
> v_check bool;
> begin
> -- Add Creation TimeStamp column if it is not there.
> select count (*)
> into v_check
> from em.all_table_columns
> where tablename = p_table
> and columnname = 'creation_timestamp';

Count returns a bigint but you assign its value to a boolean. This
should work if the return value is 0 (false) or 1 (true), which
presumably are the only possible counts in this case, but I probably
wouldn't coerce the value that way. I'd either use EXISTS or assign
count's value to a bigint.

> if v_check then
> execute 'alter table em.' || p_table || ' add creation_timestamp
> timestamp not null';
> end if;

You're saying that if the column exists (i.e., if v_check is true,
meaning that count returned 1), then add the column; you should be
checking if the column *doesn't* exist (i.e., if v_check is false,
meaning that count returned 0). Also, it's a good idea to use
quote_ident() when building dynamic queries from data that comes
from outside the function. And you might want to consider using
timestamp with time zone instead of timestamp.

> return;
> end;$$ language plpgsql;

A function that has side effects should be declared VOLATILE. And
if the function requires a non-NULL parameter then it should be
STRICT as well.

BTW, the all_table_columns table appears to duplicate information
already contained in the system catalogs. Is this a contrived
example or are you really doing that? Do you have a reason for
doing so?

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Pascual De Ruvo 2005-05-18 13:34:09 Re: double quotes inside VBA string ?
Previous Message Zlatko Matić 2005-05-18 13:14:28 double quotes inside VBA string ?