Syntax error at or near $1 while trying to alter type in postgreSQL-9.6

£可爱£侵袭症+ 提交于 2021-02-20 03:46:39

问题


I'm trying to add a value to an enumerated type in postgreSQL-9.6, and am having trouble figuring out what I'm doing wrong.

var tc = new NpgsqlCommand(@"ALTER TYPE attributeName ADD VALUE IF NOT EXISTS 
:a", conn);

//tc.Parameters.Add(new NpgsqlParameter("a", NpgsqlDbType.Text));
//tc.Parameters[0].Value = "test";
tc.Parameters.AddWithValue("a", NpgsqlDbType.Text, "test");

tc.ExecuteNonQuery();

I tried both the commented out code and the current version, and both resulted in an exception. The exception details are:

$exception  {"42601: syntax error at or near \"$1\""}

I understand the $1 is in reference to the text being passed through the "a" parameter, but I don't understand why there is a problem or how to fix it. PostgreSQL's documentation says that ALTER TYPE cannot be performed in a transaction block, but as far as I can tell Npgsql doesn't automatically start transactions, so that shouldn't be a problem. If I perform a different SQL command with similar syntax, such as:

var tc = new NpgsqlCommand(@"INSERT INTO test VALUES (:a)", conn);

the program works flawlessly. Also, if I type the command directly into the psql shell, like this:

ALTER TYPE attributeName ADD VALUE IF NOT EXISTS 'test';

it works as expected. Can anybody help me understand what I'm doing wrong? Thanks.


回答1:


I might be wrong, but I think it can't be achieved for the same reason a table name cannot be passed as a query parameter.

However, you can use a string replacement for it:

string name = "test";
var tc = new NpgsqlCommand($"ALTER TYPE attributeName ADD VALUE IF NOT EXISTS '{name}'", conn);

Please keep in mind it's not a secure approach!

UPDATE:

Another solution would be usage of a stored procedure that executes the command. However, you cannot simply call the ALTER TYPE ... ADD VALUE ... command inside a procedure/function because it doesn't work inside transaction blocks. You would get the following error:

"ALTER TYPE ... ADD cannot be executed from a function or multi-command string"

This thread should shed some light on the issue: Problems with ENUM type manipulation in 9.1

However, there might be a solution for your problem. It looks like you're trying to modify the existing enum type (add a new value). You can create a function that operates on the pg_enum table directly. The set of database functions, designed for enum types manipulation, can found here: PostgreSQL 8.3+, 9.1+ ALTER ENUM emulation: element addition/removal, transactions.

The function that adds a new value to existing enum looks as follows:

-- Also works within transactions in PostgreSQL 9.1+ (but you need
-- to reconnect to the database after transaction commit, because 
-- new enum items are not be visible within the session you used
-- to add them).
--
-- See http://en.dklab.ru/lib/dklab_postgresql_enum/
--
-- (C) Dmitry Koterov, 2013
-- This code is BSD licensed.
--

CREATE SCHEMA enum AUTHORIZATION postgres;


SET search_path = enum, pg_catalog;
SET check_function_bodies = false;
CREATE OR REPLACE FUNCTION enum.enum_add (
  enum_name varchar,
  enum_elem varchar
)
RETURNS void AS
$body$
DECLARE
    eoid OID;
    has_sortorder BOOLEAN;
BEGIN
    eoid := (
        SELECT pg_type.oid
        FROM pg_type JOIN pg_namespace ON pg_namespace.oid=pg_type.typnamespace
        WHERE typtype='e' AND enum_name IN(typname, nspname||'.'||typname)
    );
    has_sortorder := EXISTS(
        select 1
        from pg_attribute
        where attrelid=(select oid from pg_class where relname='pg_enum') and attname='enumsortorder'
    );
    IF has_sortorder THEN
        EXECUTE '
            INSERT INTO pg_enum(enumtypid, enumlabel, enumsortorder) VALUES(
                '||eoid||',
                '||quote_literal(enum_elem)||',
                (SELECT MAX(enumsortorder) + 1 FROM pg_enum WHERE enumtypid='||eoid||')
            )
        ';
    ELSE
        EXECUTE E'INSERT INTO pg_enum(enumtypid, enumlabel) VALUES('||eoid||', '||quote_literal(enum_elem)||')';
    END IF;
END;
$body$
    LANGUAGE 'plpgsql';

COMMENT ON FUNCTION enum.enum_add (enum_name character varying, enum_elem character varying) IS 'Inserts a new ENUM element wthout re-creating the whole type.';

Now, you can just call the stored procedure/function from your C# code:

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = @"enum.enum_add";
    cmd.Parameters.AddWithValue("enum_name", "attributeName");
    cmd.Parameters.AddWithValue("enum_elem", "O'Reilly");
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.ExecuteNonQuery();
}

Please note, that the above function will fail if you try to add an existing value.




回答2:


I have no experience with npgsql, though might be totally wrong, but NpgsqlCommand seems to execute prepared statement. If so, you cant prepare ALTER statement:

statement

Any SELECT, INSERT, UPDATE, DELETE, or VALUES statement.




回答3:


PostgreSQL doesn't support parameter placeholders everywhere, and unless I'm mistaken it's specifically unsupported in DDL statements such as ALTER TYPE. You will likely have to insert the value you want as a literal in your statement (be sure to take into account SQL injection).



来源:https://stackoverflow.com/questions/44011994/syntax-error-at-or-near-1-while-trying-to-alter-type-in-postgresql-9-6

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!