PHP/PostgreSQL: проверьте, существует ли уже подготовленный оператор

Я создаю свой подготовленный оператор как:

pg_prepare('stm_name', 'SELECT ...');

Сегодня у меня возникла проблема (дважды вызывая функцию из-за ошибки) при двойном объявлении подготовленного оператора с тем же именем:

Warning: pg_prepare() [function.pg-prepare]: Query failed: ERROR: prepared statement "insert_av" already exists in xxx on line 221

Итак, судя по заголовку вопроса, есть способ проверить, существует ли уже оператор подготовки с такой же меткой, и в случае чего перезаписать его?

Я знаю, что эта ошибка возникла из-за моей ошибки и будет решена простым объявлением подготовленных операторов в начале моего кода, но мне интересно, есть ли решение для большего контроля над ними.

ИЗМЕНИТЬ:

После ответа Милен достаточно просто проверить, используется ли уже подготовленный оператор, просто запросив в базе данных таблицу pg_prepared_statements:

try{
    $qrParamExist = pg_query_params("SELECT name FROM pg_prepared_statements WHERE name = $1", array($prepared_statement_name));
    if($qrParamExist){
        if(pg_num_rows($qrParamExist) != 0){
            echo 'parametized statement already created';
        }else{
            echo 'parametized statement not present';
        }
    }else{
        throw new Exception('Unable to query the database.');
    }
}catch(Exception $e){
    echo $e->getMessage();
}

Но я не думаю, что это хорошее решение, потому что мне приходится каждый раз запрашивать базу данных.

Хорошо, обычно подготовленные операторы объявляются в начале скрипта, а затем просто используются повторно, но у меня есть класс, хорошо связанный, и я не люблю объявлять 10 подготовленных операторов, когда я буду использовать только 3 из них.

Итак, я думаю, что буду использовать простой массив PHP для отслеживания создаваемых операторов, а затем с помощью функции isset() проверю, существует ли он или его нужно создать:

try{
    $prepare = pg_prepare('my_stmt_name', "SELECT ...");
    if($prepare){
        $this->rayPrepared['my_stmt_name'] = true;
    }else{
        throw new Exception('Prepared statement failed.');
    }
}catch(Exception $e){
    echo $e->getMessage();
}

person Strae    schedule 28.07.2009    source источник
comment
Иногда необходимо использовать EXECUTE для исправления отношения с OID ###### ошибка не существует.   -  person metoo    schedule 30.11.2010
comment
Подскажите, пожалуйста, как получить предупреждение? Когда у меня нет этого предупреждающего сообщения, я потратил почти час, чтобы понять, почему мой код не работает. Спасибо   -  person Ensom Hodder    schedule 28.04.2013
comment
@EnsomHodder попробуйте с error_reporting(E_ALL); и с pg_last_error, когда ваш результат от pg_prepare или pg_query не работает (т.е. возвращает false)   -  person Strae    schedule 28.04.2013


Ответы (3)


Один из способов (надеюсь, кто-то укажет более простой):

<?
$prepared_statement_name = 'activity1';
$mydbname = '...';

$conn = pg_connect("host=... port=... dbname=... user=... password=...");

$result = pg_query_params($conn, 'SELECT name FROM pg_prepared_statements WHERE name = $1', array($prepared_statement_name));

if (pg_num_rows($result) == 0) {
    $result = pg_prepare($conn, $prepared_statement_name, 'SELECT * FROM pg_stat_activity WHERE datname =  $1');
}

$result = pg_execute($conn, $prepared_statement_name, array($mydbname));
while($row = pg_fetch_row($result)) {
    var_dump($row);
}
person Milen A. Radev    schedule 28.07.2009

Не пробовал это в php, но если это возможно в вашем приложении (если вам нужен оператор только в одном месте и вам не нужно «извлекать» его снова по имени), вы можете попытаться подготовить безымянный оператор. http://www.postgresql.org/docs/8.4/interactive/libpq-exec.html говорит:

PQprepare
...
stmtName может быть "" для создания безымянного оператора, и в этом случае любой ранее существовавший безымянный оператор автоматически заменяется; в противном случае это ошибка, если имя оператора уже определено в текущем сеансе.
php_pg использует PQprepare, так что это может сработать для вас.

person VolkerK    schedule 28.07.2009
comment
Извините, у меня много разных готовых статемов.. можно использовать неназванные. - person Strae; 28.07.2009
comment
Да, текущая сессия. Я узнал на собственном горьком опыте, что текущая сессия не означает соединение. Жаль, что нет надежного способа просто заставить API сообщать нам то, что нам нужно знать, без необходимости идти и делать запрос. - person Opux; 18.03.2016

Почему вы вообще используете подготовленные операторы? Они дают преимущество в производительности только в том случае, если вы используете один и тот же оператор много раз.

person bobflux    schedule 28.07.2009
comment
Во-первых, они обеспечивают большую защиту от инъекций... тогда, где я сказал, что использую их только один раз? ;) - person Strae; 29.07.2009
comment
Я склонен согласиться с этим отрицательным голосом, мне только интересно, почему он понижает мой представитель каждый раз, когда вы это делаете, поскольку на самом деле я был первым парнем, который сделал отрицательный голос? Смущенный. - person Rob; 11.06.2012
comment
Преимущества в производительности — это хорошо, но помощь в борьбе с SQL-инъекциями приятнее. - person xentek; 31.08.2012
comment
Для downvoters: подготовленные операторы НЕ предлагают больше безопасности. Параметризованные операторы делают. И для них есть отдельные функции. @peufeu упоминает очень важный момент. Пожалуйста, просто перестаньте убеждать людей в PS только по незнанию. - person Frunsi; 21.03.2019
comment
@Фрунси действительно. Безопасность достигается за счет использования API-интерфейсов, которые делают безопасный вариант самым простым и очевидным. - person bobflux; 17.05.2019