Php обработка ошибок oracle
PHP - рекурсивный акроним "PHP Hypertext Preprocessor". Это интерпретируемый язык программирования с открытым исходным кодом. Он предназначен для генерации веб-документов на сервере.
Этот документ описывает, как PHP взаимодействует с базой данных Oracle. Подразумевается, что у Вас уже установлен и настроен PHP. Проверить его работоспособность можно следующим скриптом:
Попробуйте выполнить этот код из командной строки либо откройте тестовую страницу в Вашем браузере. Если приведенный выше пример не работает, отложите этот документ и добейтесь корректной работы PHP.
В чем разница между модулями OCI и ORA?
В дистрибутив PHP входят два модуля, предназначенных для работы с PHP:
* Стандартные Oracle-функции (ORA)
* Интерфейс для доступа к функциям Oracle (OCI)
Если есть возможность выбора, предпочтение стоит отдать модулю OCI, так как он более оптимизирован и имеет большую функциональность. К примеру, модуль ORA не поддерживает CLOB, BLOB, BFILE, ROWID.
Как собрать PHP с поддержкой Oracle?
;extension = php_oci8.dll
;extension = php_oracle.dll
Также убедитесь в том, чтобы extension_dir указывала на директорию, содержащую указанные модули.
Если у Вас Linux-сервер, пересоберите PHP с одной из опций:
* Напишите небольшой тестовый скрипт, чтобы убедится в том, что установка завершилась успешно. В качестве тестового скрипта можно взять пример из следующего вопроса.
Как подключится к базе данных?
Если вы используете модуль OCI, воспользуйтесь следующим кодом:
Если вы используете модуль ORA, попробуйте следующее:
Замечание: если у Вас не установлены необходимые переменные окружения, поместите следующие строки в начале каждого скрипта, работающего с Oracle:
В случае, если Вы несколько раз в пределах одного скрипта попробуете подключится к базе данных, используя одинаковую комбинацию логин/пароль, Вы получите одно и то же соединение. Если Вам необходимы различные подключения к базе, используйте функцию OCINLogon(). Если вам нужны постоянные соединения, используйте функцию OCIPLogon().
Почему возникает ошибка "Call to undefined function: ora_logon()/ ocilogon()"?
Вероятнее всего, у Вас не включена поддержка Oracle. Вернитесь к вопросу "Как собрать PHP с поддержкой Oracle?". Вам необходимо пересобрать php, если у Вас Linux или раскомментировать загрузку соответствующей библиотеки, если у вас Windows.
Как выполнять запросы SELECT, INSERT, UPDATE и DELETE посредством PHP?
Приведенный ниже исходный код демонстрирует, как удалять/создавать новые таблицы, записывать/извлекать из них данные в PHP.
Как получить доступ к механизму транзакций из PHP?
При использовании модуля OCI каждый раз после удачного выполнения ociexecute() автоматически происходит commit, и, таким образом, транзакция сразу же завершается. Вы можете управлять этим процессом, указывая дополнительный параметр OCI_COMMIT_ON_SUCCESS либо OCI_DEFAULT при вызове функции ociexecute(). В случае использования OCI_DEFAULT вы сможете полностью управлять механизмом транзакций, для этого используйте функции OCICommit() и OCIRollback().
Следует учесть, что использование OCI_DEFAULT в одном из вызовов ociexecute() автоматически наследуется для всего подключения к базе данных и будет использовано при дальнейших операциях с базой данных. Если вы не хотите использовать автоматический и ручной механизм управления транзакциями одновременно, используйте OCINLogon().
В случае, если Вы используете модуль ORA, управление транзакциями выглядит немного иначе. Используйте функции ORA_CommitOn() и ORA_CommitOff() для переключения между ручным и автоматическим механизмом управления транзакциями. Для завершения транзакции и отката используйте функции ORA_Commit() и ORA_Rollback() соответственно.
В случае, если после завершения работы скрипта ни разу не выполнялся ни commit, ни rollback, PHP завершит транзакцию командой commit.
Как корректно обрабатывать возникающие ошибки?
В случае, если вы используете модуль OCI, используйте функцию OCIError() для получения массива, содержащего детальную информацию о возникающих ошибках. Если подключений несколько, OCIError() позволяет получить информацию об ошибке в каждом их них индивидуально. Если данная функция вызывается без параметров, она возвращает массив с информацией о последней произошедшей ошибке.
В случае, если вы используете модуль ORA, воспользуйтесь функциями ora_error() и errorcode() для получения информации о последней произошедшей ошибке.
Как вызвать из PHP хранимую процедуру?
Приведенный ниже пример демонстрирует создание и вызов хранимой процедуры.
Функция должна вызваться сразу же после появления ошибки. Ошибки очищаются при произведении правильного запроса.
Список параметров
Для большинства ошибок параметром connection_or_statement является соответствующий идентификатор соединения или выражения. Для ошибок во время выполнения функций oci_connect() , oci_new_connect() или oci_pconnect() следует передавать null .
Возвращаемые значения
Если ошибок не найдено, то oci_error() возвращает false . В противном случае, oci_error() возвращает информацию об ошибке в виде ассоциативного массива.
Ключ массива | Тип | Описание |
---|---|---|
code | int | Номер ошибки Oracle. |
message | string | Текст ошибки Oracle. |
offset | int | Позиция ошибки в запросе SQL. Если нет запроса, то равна 0 |
sqltext | string | Текст запроса SQL. Если нет запроса, то строка пуста. |
Список изменений
Версия | Описание |
---|---|
8.0.0, PECL OCI8 3.0.0 | connection_or_statement теперь допускает значение null. |
Примеры
$conn = oci_connect ( "hr" , "welcome" , "localhost/XE" );
if (! $conn ) $e = oci_error (); // Для обработки ошибок oci_connect
trigger_error ( htmlentities ( $e [ 'message' ]), E_USER_ERROR );
>
?>?php
$stid = oci_parse ( $conn , "select ' from dual" ); // пропущенные кавычки
if (! $stid ) $e = oci_error ( $conn ); // Для обработки ошибок oci_parse
trigger_error ( htmlentities ( $e [ 'message' ]), E_USER_ERROR );
>
?>?php
$stid = oci_parse ( $conn , "select does_not_exist from dual" );
$r = oci_execute ( $stid );
if (! $r ) $e = oci_error ( $stid ); // Для обработки ошибок oci_execute
print htmlentities ( $e [ 'message' ]);
print "\n
\n" ;\n" ;
print htmlentities ( $e [ 'sqltext' ]);
printf ( "\n%" .( $e [ 'offset' ]+ 1 ). "s" , "^" );
print "\n
>
?>?php
The function should be called immediately after an error occurs. Errors are cleared by a successful statement.
Parameters
For most errors, connection_or_statement is the resource handle that was passed to the failing function call. For connection errors with oci_connect() , oci_new_connect() or oci_pconnect() null should be passed.
Return Values
If no error is found, oci_error() returns false . Otherwise, oci_error() returns the error information as an associative array.
Array key | Type | Description |
---|---|---|
code | int | The Oracle error number. |
message | string | The Oracle error text. |
offset | int | The byte position of an error in the SQL statement. If there was no statement, this is 0 |
sqltext | string | The SQL statement text. If there was no statement, this is an empty string. |
Changelog
Version | Description |
---|---|
8.0.0, PECL OCI8 3.0.0 | connection_or_statement is now nullable. |
Examples
$conn = oci_connect ( "hr" , "welcome" , "localhost/XE" );
if (! $conn ) $e = oci_error (); // For oci_connect errors do not pass a handle
trigger_error ( htmlentities ( $e [ 'message' ]), E_USER_ERROR );
>
?>?php
$stid = oci_parse ( $conn , "select ' from dual" ); // note mismatched quote
if (! $stid ) $e = oci_error ( $conn ); // For oci_parse errors pass the connection handle
trigger_error ( htmlentities ( $e [ 'message' ]), E_USER_ERROR );
>
?>?php
$stid = oci_parse ( $conn , "select does_not_exist from dual" );
$r = oci_execute ( $stid );
if (! $r ) $e = oci_error ( $stid ); // For oci_execute errors pass the statement handle
print htmlentities ( $e [ 'message' ]);
print "\n
\n" ;\n" ;
print htmlentities ( $e [ 'sqltext' ]);
printf ( "\n%" .( $e [ 'offset' ]+ 1 ). "s" , "^" );
print "\n
>
?>?php
Возвращает данные поля column текущей строки, возвращаемой функцией oci_fetch() .
За подробностями по операции отображения типов данных, осуществляемой модулем OCI8, обратитесь к типам данных, поддерживаемых драйвером
Список параметров
Может быть задано номером поля (начиная с 1), либо по имени. Регистр имени поля должен быть таким же, как и у поля, описанного в метаданных Oracle, которое всегда в верхнем регистре для полей, созданных регистронезависимыми.
Возвращаемые значения
Возвращает все значения в виде строки за исключением абстрактных типов (ROWIDs, LOBs и FILEs). Возвращает false в случае возникновения ошибки.
Примеры
$conn = oci_connect ( 'hr' , 'welcome' , 'localhost/XE' );
if (! $conn ) $e = oci_error ();
trigger_error ( htmlentities ( $e [ 'message' ], ENT_QUOTES ), E_USER_ERROR );
>
$sql = 'SELECT location_id, city FROM locations WHERE location_id < 1200' ;
$stid = oci_parse ( $conn , $sql );
oci_execute ( $stid );
while ( oci_fetch ( $stid )) echo oci_result ( $stid , 'LOCATION_ID' ) . " - это " ;
echo oci_result ( $stid , 'CITY' ) . "
\n" ;
>
// Выведет:
// 1000 - это Roma
// 1100 - это Venice
oci_free_statement ( $stid );
oci_close ( $conn );
Примечания
Замечание:
В версиях PHP ниже 5.0.0 эта функция называлась ociresult() . В PHP 5.0.0 и выше ociresult() является алиасом oci_result() в целях обратной совместимости. Вы можете продолжать использовать это имя, однако это не рекомендуется.
Смотрите также
- oci_fetch_array() - Возвращает следующую строку из результата запроса в виде ассоциативного или нумерованного массива
- oci_fetch_assoc() - Возвращает следующую строку из результата запроса в виде ассоциативного массива
- oci_fetch_object() - Возвращает следующую строку из результата запроса в виде объекта
- oci_fetch_row() - Возвращает следующую строку из результата запроса в виде нумерованного массива
- oci_fetch_all() - Выбирает все строки из результата запроса в двумерный массив
User Contributed Notes 9 notes
OCIResult() requires the column name to be written in capitals, so OCIResult($stmt,"column") won't work, but OCIResult($stmt,"COLUMN") works fine. Hope that helps somebody out
Note that if you are making multiple table selects, you must specify an alias to each column.
This wont work:
----------------------------------------
$qry = "SELECT A.COL_ONE, B.COL_ONE FROM TABLE1 A, TABLE2 B";
$stmt = OCIParse($conn, $qry);
But this will:
----------------------------------------
$qry = "SELECT A.COL_ONE AS X, B.COL_ONE AS Y FROM TABLE1 A, TABLE2 B";
$stmt = OCIParse($conn, $qry);
I am trying to get a list of the first character of a character string.
SELECT distinct substr(version,1,1) as COL1 FROM SPHVVERS where Version is not null order by 1
This was working and then failed recently. I think it is because some of the strings now added contain a number as the first character.
I found to get it to work I had to use decode statement. (To_Char did not work )
SELECT distinct decode (substr(version,1,1),'1','?','0','!',substr(version,1,1)) as COL1 FROM SPHVVERS where Version is not null order by 1
In order to modify Oracle dates (using NLS_DATE_FORMAT. ), you must set $ORACLE_HOME first. This environmental variable is best set in the server startup script (i.e., ./apachectl)
if you want to join two tables having both the same column (e.g. 'id') but you don't want to (or cannot) specify all the other fields in these two tables (like erabbott mentioned), you can use:
SELECT t1.*, t2.*, t1.id AS id1, t2.id AS id2
FROM table1 t1, table2 t2;
Note that this does _not_ work:
SELECT *,t1.id AS id1, t2.id AS id2
FROM table1 t1, table2 t2;
As this function gets a 'mixed' variable type for the column index, you may use an integer to represent the column number. In this case, the count is starting from 1 and not from zero.
I am not sure, but I think this method is a bit faster than using the column name.
For an example, see the OCINumCols first example.
I complained that I couldn't get the time from an Oracle date field. Joe Brown said:
This is not a PHP bug.
Consider setting NLS_DATE_FORMAT.
The manual states OCIResult() returns everything as a string.
NLS_DATE_FORMAT may not be appropriate for your needs.
There are quite a few places you can set NLS_DATE_FORMAT.
* Environment variables (or windows registry on win32)
* orclSID.ora
* on a per session basis; execute this statement after logon:
$cursor=OCIParse($connection,
"ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
OCIExecute($cursor);
OCIFreeCursor($cursor);
I am trying to get a list of the first character of a character string.
SELECT distinct substr(version,1,1) as COL1 FROM SPHVVERS where Version is not null order by 1
This was working and then failed recently. I think it is because some of the strings now added contain a number as the first character.
I found to get it to work I had to use decode statement. (To_Char did not work )
SELECT distinct decode (substr(version,1,1),'1','?','0','!',substr(version,1,1)) as COL1 FROM SPHVVERS where Version is not null order by 1
As in my previous post, the same thing applies when using conversion functions in CLOB columns.
Probably the same thing will occur to any conversion function that you use.
Stored procedures typically group a series of related operations behind a single API. Typically the operations executed by a stored procedure would be mix of SQL statements, to fetch and modify data, as well as PL/SQL statements which act on that data, such performing some mathematical calculations, detailed validation of values and handling error conditions They can be advantageous in improving performance, by reducing the number of "round trips" between a calling program and the database, as well as simplifying data management logic within the client.
Downloads for this article:
If you consider the code normally required to manage a many-to-many relationship between tables, performing an update to existing data can often involve three separate queries. By encapsulating that process in a single stored procedure, traffic between the client and database is reduced while an operation that would normally require multiple steps in the client code is reduced to a single database call.
The PHP OCI8 extension provides support for calling stored procedures, allowing you to bind parameters to a procedure statement in the same way as you would to a normal SQL statement, as well as access to result cursors and Oracle collections. This HowTo provides examples of common operations with stored procedures.
Stored Procedure Input and Output
sayHello (name IN VARCHAR2, greeting OUT VARCHAR2)
When calling this procedure, the first argument name would contain an input value you supply at call-time, while greeting would be populated by the procedure as a "returned" value for use after the procedure has completed.
Reading the Specification
Although a discussion of PL/SQL programming is beyond the scope of this HowTo, deep knowledge of PL/SQL is unecessary as long as you are roughly familiar with how a stored procedure looks and can read the interface specification.
When looking the source of a stored procedure, it will begin by defining the parameters it accepts, for example:
The name of this procedure is edit_entry . Within the parentheses is defined the list of arguments you can pass to the procedure, separated by commas. For each parameter in the list, you will see the name used to reference its value within the procedure itself (you do not need to use the same names in your PHP script), the mode of the parameter (see below) and the type of the parameter.
So for the first parameter in this example:
The internal name is status_out, the mode is OUT, and the type is NUMBER, which is a native Oracle data type.
Later in the script you'll see the id_inout parameter.
id_inout IN OUT INTEGER,
which has the mode IN OUT and type INTEGER.
At the end of the list is the categories_in parameter:
categories_in IN list_of_numbers
Here the type is user defined (more on that type later).
Parameter Modes
- IN —parameters with this mode are supplied by the caller.
- OUT —the parameter may be assigned a value by the procedure and returned to the caller.
- IN OUT —the parameter can be used in both "directions"; that is, the caller may provide a value for this parameter and the procedure may also modify the value of the parameter.
Parameters are Not Optional.
When a procedure is called from PHP, you must bind a PHP variable to all the parameters it defines. You may not have to assign values to the PHP variables, even if they are input parameters—if no value is assigned to a scalar type, Oracle will regard it as a NULL value.
It's worth noting that stored procedures can be "overloaded" in Oracle. In other words, there may be two procedures with the same name but with different parameter signatures. Which one is called will depend on the number and types of the parameters you bind to in PHP.
Complex Types
The parameters used by a stored procedure are not limited only to scalar types such as VARCHAR2 and INTEGER. It's also possible to pass and receive complex data types, such as a list of values or a result cursor corresponding to the set of rows selected from a table.
In general, you will typically receive cursors back from a stored procedure, if there are rows of data to iterate over, while if you need to pass a list of values in, you would typically use a collection. The examples below illustrate these in PHP.
Invoker vs. Definer Rights.
Oracle makes a distinction between "invokers" (a user executing a stored procedure) and "definers" (the user under which the CREATE PROCEDURE statement was issued).
By default, stored procedures are executed with the rights of the definer, even when the invoker is a different user. That means all access to tables, for example, within the procedure will be controller by the rights of the definer so an invoker only needs rights to execute the procedure, not rights to the tables it uses.
This model can be changed with the keywords AUTHID CURRENT_USER as part of the procedure definition. With this directive set, rights required when executing a stored procedure are resolved at runtime against the current user executing the procedure.
One possible use for this approach is to test a procedure that modifies data in a table without actually modifying live data. In this case the invoking user defines a table in their own schema with the same name as a that accessed from within a procedure they want to execute, and the procedure acts against the local table rather than the one available to the definer.
Calling Stored Procedures from PHP
In terms of the SQL statement you would execute from PHP to call a procedure, you will typically nest the call within an Oracle BEGIN . END; block, known as an anonymous block. For example:
You then bind the parameters to PHP variables with calls to oci_bind_by_name() .
If the sayHello procedure was defined by the following DDL statement:
Note that you can run the above statement using the SQL*Plus command line. Save the statement to a file (SAYHELLO.SQL). Next, login with SQL*Plus:
Then create the procedure using the START command:
SQL> START /home/username/SAYHELLO.SQL
Example Package Blog.
To illustrate some of the trickier aspects of calling stored procedures, here you'll use the following package, called blog, which provides an API for fetching and modifying entries in a hypothetical blogging application. Packages are a way to encapsulate procedures, functions, and data inside their own namespace with their own scope, keeping them isolated from other procedures in the global database namespace. When calling a procedure in a package, a period is used to separate package name from procedure name.
The blog package is specified with:
The package provides two procedures: blog.latest, which returns a result cursor containing the most recent num_entries blog entries; and blog.edit_entry, which allows new blog entries to be inserted as well as modification of existing blog entries. If a value is provided for the id_inout parameter, the procedure attempts to update the corresponding blog entry with that id. Otherwise it will insert a new blog entry and populate id_inout with the new row's primary key. This procedure also accepts a CLOB object, corresponding to the body of the blog entry and a collection object corresponding to a list of categories the entry should be filed under. The collection type list_of_numbers referenced here is defined by:
CREATE OR REPLACE TYPE list_of_numbers AS VARRAY(50) OF NUMBER;
The body of the package is shown below. The comments should give you an idea of what it does without needing a deep understanding of PL/SQL:
The underlying table structure the procedures are using is:
Stored Procedures and Reference Cursors
Looking at the blog.latest procedure, you'll see it returns a reference cursor for iterating over the row in my blogs table.
To work with a cursor in PHP two additional steps are required, as compared to accessing rows directly from a SELECT statement. The first step is preparing a cursor resource in PHP, using the oci_new_cursor() function, which you then use to bind to the appropriate parameter. The second step, after you have executed the SQL statement, is calling oci_execute() on the cursor resource.
Stored Procedures and LOBs
Oracle long objects can be passed to and from stored procedures in pretty much the same way as you would with native SQL.
The following example demonstrates a call to the blog.edit_entry procedure using a CLOB. In this example no value is assigned to the id parameter so it will correspond to inserting a new blog entry:
As this script illustrates, a key issue is how transactions should be handled when dealing with LOBs. Here you have chosen to delegate all transaction handling to the PHP script, as updating a LOB is a two-stage process.
Note that, by default, Oracle allows you to have only one transaction running at a time in any given session. That means commit or rollback statements issued within a procedure you are calling from PHP will override calls you make to oci_commit() or oci_rollback() . You can change this behavior using autonomous transactions, enabled with the pragma PRAGMA AUTONOMOUS_TRANSACTION placed inside a procedure definition. You might use autonomous transactions, for example, as part of a logging package that you call from other procedures; this approach would enable you to log information about stored procedure calls without interfering with transactions running within a session.
Stored Procedures and Collections
Collections provide a mechanism to pass a complex data type into a stored procedure. In your blogging application, a blog entry can be filed under multiple categories, corresponding to the many-to-many relationship between the "blogs" and "categories" tables.
A collection type in Oracle must be defined globally in the database, and in this example, you are using the following definition:
CREATE OR REPLACE TYPE list_of_numbers AS VARRAY(50) OF NUMBER;
which allows you to assign a blog entry to a maximum of 50 categories in one go, by passing an instance of this type to the blog.edit_entry procedure.
In PHP, a collection is represented by the pre-defined PHP class OCI-Collection. Instances of this class are created by calling the oci_new_collection() function. An OCI-Collection object provides the following methods:
-
: pushes an element onto the end of the collection : adds an element to a collection from an existing collection : free up an resources associated to the collection handle
- getElem : retrieves an element from a particular index location in the collection : returns the maximum number of elements in the collection : returns the current size of the collection : removes a number of elements from the end of the collection
Conclusion
You have now seen examples of how to call stored procedures from PHP, both with simple procedures involving only scalar data types and more complex procedures using LOBs, cursors, and collections. You should also have enough understanding of stored procedure definitions to be able to read their PL/SQL specification, enabling you to call them correctly from PHP and bind the correct types.
Читайте также: