Showing posts with label REST. Show all posts
Showing posts with label REST. Show all posts

Calling Oracle Procedures from PHP

Using Oracle Functions or Procedures can be used to insert /update/delete data from oracle database.

While creating function ADD_INVOICE to insert data in AR_HEADER and AR_LINES,
I found when calling it from TOAD it works fine and insert data in the two levels (HEADER and LINES).

When using PHP it only insert data in one level (HEADER) only.

After some search , I got the concept of calling stored procedure using PHP.
So, I converted the preceding function (ADD_INVOICE ) to procedure which holds an OUT parameter.

Then  when calling it, the insert was successfully in the two levels (HEADER and LINES).

here's the PHP get code :


<?php
    //Connect to oracle database 
    $db=oci_connect('pos','pos','prod', 'AL32UTF8');
    
    $query = " DECLARE  BEGIN ADD_INVOICE(:message); END;";     
    $stmt =oci_parse ($db , $query);  
    // Bind the output parameter
    oci_bind_by_name($stmt,':message',$message,32);    
    // execute query
    oci_execute($stmt); 
print "$message\n";
UPDATES:
 The preceding  $query in green , must be written in one line , to avoid erros!
Also when receiving JSON  using $_POST methods , it's automatically add back slash to every character.

I send json_text : [{ "product_id": "60402", "price": "20.0", "tax_rate": "0.0" , "qty": "1", }{ "product_id": "60302", "price": "60.0", "tax_rate": "5.0" , "qty": "1", }]

It's converted to: [{ \"product_id\": \"60402\", \"price\": \"20.0\", \"tax_rate\": \"0.0\" , \"qty\": \"1\", }{ \"product_id\": \"60302\", \"price\": \"60.0\", \"tax_rate\": \"5.0\" , \"qty\": \"1\", }]

So We use Oracle REPLACE function to remove back slash  ,then parse json.

Connect PHP and Oracle database 10g

I posted before how to create APIs (Web Services) from Database 10g using PLSQL Gateway in this post.

When Android developer reads API , Arabic fonts was not complete when using FLUTTER, but when he using Android Studio he reads without any losing characters.

I found using php server , it works fine.

Here are steps to create your first APIs to connect PHP and ORACLE 10g together:
1#  HR schema is used in the following example
2#  Download this Github repository from  here (It includes AppServ and API Folders) APPSERV another link
3# Install AppServ to C:\AppServ
4#Extract ora_php-master.zip to C:\AppServ\www
5# Rename C:\AppServ\www\ora_php-master to  C:\AppServ\www\api
 Now your folders and files  should looks like this:

6# Config Folder: Contains database.php ,

<?php

class Database{

 // specify your own database credentials

    private $host     = "localhost"; //DataBase Server

    private $db_name  = "PROD";    //DataBase Name

    private $username = "hr";            //User Name, which We'll Create API for

    private $password = "hr";            //User Password

    public  $conn;                              //Public Varaible
// get the database connection
    public function getConnection(){
  $this->conn = null;
  try{
   $this->conn = oci_connect($this->username, 
                             $this->password, 
           '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)
                                      (HOST = '.$this->host.')
                 (PORT = 1521)) 
               (CONNECT_DATA = (SERVICE_NAME = '.$this->db_name.') 
                               (SID = '.$this->db_name.')))' , 'AL32UTF8');
   }
  catch(Exception $exception){
   echo "Connection error: " . $exception->getMessage();
   }
   return $this->conn;
   }

7# Objects Folder : Contains all Users, if  we do have other users .


8# User Folder : For every object we create folder contains all types of API  (GET, PUT, POST....)


9# To Test API : goto http://localhost/api/user/read.php
URL consists of : Machine_Ip/API_Folder(Which was ora_php-master)/APIS_FOLDER(USER)/API_METHOD(read.php or search.php?id=107)

10# Done , Now you can connect to database from any machine, Android, iOS etc......

UPDATE #1
You may face an error  like Call to undefined function oci_connect .

Here's how to fix it :
# You need to enable OCI for php
# Edit php.ini

# enable extension=php_oci8.dll
BEFORE : ;extension=php_oci8.dll
AFTER    : extension=php_oci8.dll

# Restart AppServ .

UPDATE #2

To make sure OCI works , Open browser and goto  http://localhost/phpinfo.php
it must looks have oci like that :




UPDATE #3

Connecting to remote DataBase is some tricky , You just add connection string  when calling OCI_CONNECT , here's a full example :


<?php
//Connect String
$db="(DESCRIPTION=
     (ADDRESS_LIST=
       (ADDRESS=(PROTOCOL=TCP)
         (HOST=192.168.1.25)(PORT=1521)
       )
    )
        (CONNECT_DATA=(SID=HR))
 )";

//Connect to DB

$conn = oci_connect('hr','hr',$db); 


//Run a sample query

$qry = oci_parse($conn, 'select SYSDATE from DUAL');


if (!qry){

    echo "Not connected";

}else{

    echo "Connected";

}

UPDATE #4

If you still cannot see OCI8 in http://localhost/phpinfo.php , here's final steps :

1# download  oracle instant client (instantclient-basic-win32-10.2.0.5) from here 

2# Extract all contents to the zipped file to :
   - C:\AppServ\Apache2.2\bin
  and
  - C:\AppServ\php5\ext

3#  Edit System Variables PATH 
  add C:\AppServ\php5\ext  at the end of existing text

4# Restart the Apache server

5# You are done !

Create nested JSON Array

To query all EMPLOYEES below the main Departments , and get the result in JSON format .

Connect using SCOTT user

Following are steps:
#1 Create GET method
Type : QUERY
Pagination Size: 0


GET method

#2 Add the following code :


SELECT G.Deptno,
       G.DName,
       CURSOR ( SELECT V.Empno, 
                       V.Ename
                FROM   EMP V 
       WHERE  V.Deptno = G.Deptno )  EMPLOYEES
FROM   DEPT   G
Here's the output in PLSQL/Develoepr

Share folders using Apache Tomcat

When it comes to accessing images, files and other media through internet, There are many solutions especially when using ORACLE  APEX.

But when using Oracle 10g it's bit hard, so I used  Apache Tomcat.

Steps to share folder and access it using http:// :

  1. Downlaod and install Java6 Update 20 from here: https://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html
  2. Download and install Apache Tomact from here: http://tomcat.apache.org/
    1. Remember well the PORT : 8080  or any other one
    2. Remember well the user: ADMIN
    3. Remember well the user Password: ******
  3. Suppose you have installed Apache Tomcat in the following path: C:\Program Files\Apache Software Foundation\ :
    1. Go to : C:\Program Files\Apache Software Foundation\Tomcat 7.0\conf\
    2. Edit web.xml   <param-name>listings</param-name> <param-value>false</param-value>
    3. Change false to true :
      <param-name>listings</param-name> <param-value>true</param-value>
  4. Go to : C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\ROOT
    1. Remove all contents
    2. Place here all your folders, files to make it shareable
  5. Restart Apache Tomcat
  6. Open Browser and Go to  : http://127.0.0.1:8080/
  7. you're done
UPDATE : To share any folder without copying it to ROOT folder :
  1. Go to C:\Program Files\Apache Software Foundation\Tomcat 7.0\conf
  2. Edit server.xml
  3. Add the following line :

<Context docBase="c:\insight_dsk" path="/images" reloadable="true" source="c:\insight_dsk"/> 
c:\insight_dsk : Folder you want to share it
images     : Alias appears on the web page

4. Restart Apache Tomcat

To Display folder files goto:   http://127.0.0.1:8080/images

#9 REST Standalone batch

To Run  ORDS ,REST services must be up all time.
This can be achieved by running ORDS in standalone, deploying on Weblogic, using Apache tomcat...etc

To run ORDS in standalone mode go to this previous post 
  Here's tiny batch file to manually starting ORDS service :

  1. Suppose you have installed  JDK in the path : c:\Program Files\Java\jdk1.8.0_152\bin>java
  2. And you downloaded ORDS, and extracted to : d:\Oracle\ords\ords.war
  3. Open Notepad and add the following code :

@echo off

CD c:\Program Files\
CD Java\jdk1.8.0_152\bin\
CALL java -jar D:\Oracle\ords\ords.war
pause


4. Save file as : Start_ORDS.bat
you are done, To run ORDS anytime you just double click this Start_ORDS.bat file

That's all it.

Generate JSON from SQL and PLSQL

There are many ways to generate JSON  files from  Oracle Database (11g, 12c, ...), but when it comes to Oracle DataBase 10g it's a bit of difficult.

PLSQL-utils is a method can convert SQL and REF_CURSOR to JSON.
You can download it from here: https://code.google.com/archive/p/plsql-utils/downloads

To install only  the required Package:
create or replace type t_str_array as table of varchar2(4000);
/
create or replace package json_util_pkg
as

  /*

  Purpose:    JSON utilities for PL/SQL

  Remarks:

  Who     Date        Description
  ------  ----------  -------------------------------------
  MBR     30.01.2010  Created

  */

  -- generate JSON from REF Cursor
  function ref_cursor_to_json (p_ref_cursor in sys_refcursor,
                               p_max_rows in number := null,
                               p_skip_rows in number := null) return clob;

  -- generate JSON from SQL statement
  function sql_to_json (p_sql in varchar2,
                        p_param_names in t_str_array := null,
                        p_param_values in t_str_array := null,
                        p_max_rows in number := null,
                        p_skip_rows in number := null) return clob;


end json_util_pkg;
/

create or replace package body json_util_pkg
as

  /*

  Purpose:    JSON utilities for PL/SQL

  Remarks:

  Who     Date        Description
  ------  ----------  -------------------------------------
  MBR     30.01.2010  Created

  */


  g_json_null_object             constant varchar2(20) := '{ }';


function get_xml_to_json_stylesheet return varchar2
as
begin

  /*

  Purpose:    return XSLT stylesheet for XML to JSON transformation

  Remarks:    see http://code.google.com/p/xml2json-xslt/

  Who     Date        Description
  ------  ----------  -------------------------------------
  MBR     30.01.2010  Created
  MBR     30.01.2010  Added fix for nulls

  */


  return '<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--
  Copyright (c) 2006, Doeke Zanstra
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification,
  are permitted provided that the following conditions are met:

  Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer. Redistributions in binary
  form must reproduce the above copyright notice, this list of conditions and the
  following disclaimer in the documentation and/or other materials provided with
  the distribution.

  Neither the name of the dzLib nor the names of its contributors may be used to
  endorse or promote products derived from this software without specific prior
  written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  THE POSSIBILITY OF SUCH DAMAGE.
-->

  <xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8" media-type="text/x-json"/>
  <xsl:strip-space elements="*"/>
  <!--contant-->
  <xsl:variable name="d">0123456789</xsl:variable>

  <!-- ignore document text -->
  <xsl:template match="text()[preceding-sibling::node() or following-sibling::node()]"/>

  <!-- string -->
  <xsl:template match="text()">
    <xsl:call-template name="escape-string">
      <xsl:with-param name="s" select="."/>
    </xsl:call-template>
  </xsl:template>

  <!-- Main template for escaping strings; used by above template and for object-properties
       Responsibilities: placed quotes around string, and chain up to next filter, escape-bs-string -->
  <xsl:template name="escape-string">
    <xsl:param name="s"/>
    <xsl:text>"</xsl:text>
    <xsl:call-template name="escape-bs-string">
      <xsl:with-param name="s" select="$s"/>
    </xsl:call-template>
    <xsl:text>"</xsl:text>
  </xsl:template>

  <!-- Escape the backslash (\) before everything else. -->
  <xsl:template name="escape-bs-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <xsl:when test="contains($s,''\'')">
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="concat(substring-before($s,''\''),''\\'')"/>
        </xsl:call-template>
        <xsl:call-template name="escape-bs-string">
          <xsl:with-param name="s" select="substring-after($s,''\'')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Escape the double quote ("). -->
  <xsl:template name="escape-quot-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <xsl:when test="contains($s,''&quot;'')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,''&quot;''),''\&quot;'')"/>
        </xsl:call-template>
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="substring-after($s,''&quot;'')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Replace tab, line feed and/or carriage return by its matching escape code. Can''t escape backslash
       or double quote here, because they don''t replace characters (&#x0; becomes \t), but they prefix
       characters (\ becomes \\). Besides, backslash should be seperate anyway, because it should be
       processed first. This function can''t do that. -->
  <xsl:template name="encode-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <!-- tab -->
      <xsl:when test="contains($s,''&#x9;'')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,''&#x9;''),''\t'',substring-after($s,''&#x9;''))"/>
        </xsl:call-template>
      </xsl:when>
      <!-- line feed -->
      <xsl:when test="contains($s,''&#xA;'')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,''&#xA;''),''\n'',substring-after($s,''&#xA;''))"/>
        </xsl:call-template>
      </xsl:when>
      <!-- carriage return -->
      <xsl:when test="contains($s,''&#xD;'')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,''&#xD;''),''\r'',substring-after($s,''&#xD;''))"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- number (no support for javascript mantise) -->
  <xsl:template match="text()[not(string(number())=''NaN'')]">
    <xsl:value-of select="."/>
  </xsl:template>

  <!-- boolean, case-insensitive -->
  <xsl:template match="text()[translate(.,''TRUE'',''true'')=''true'']">true</xsl:template>
  <xsl:template match="text()[translate(.,''FALSE'',''false'')=''false'']">false</xsl:template>

  <!-- item:null -->
  <xsl:template match="*[count(child::node())=0]">
    <xsl:call-template name="escape-string">
      <xsl:with-param name="s" select="local-name()"/>
    </xsl:call-template>
    <xsl:text>:null</xsl:text>
    <xsl:if test="following-sibling::*">,</xsl:if>
    <xsl:if test="not(following-sibling::*)">}</xsl:if> <!-- MBR 30.01.2010: added this line as it appeared to be missing from stylesheet -->
  </xsl:template>

  <!-- object -->
  <xsl:template match="*" name="base">
    <xsl:if test="not(preceding-sibling::*)">{</xsl:if>
    <xsl:call-template name="escape-string">
      <xsl:with-param name="s" select="name()"/>
    </xsl:call-template>
    <xsl:text>:</xsl:text>
    <xsl:apply-templates select="child::node()"/>
    <xsl:if test="following-sibling::*">,</xsl:if>
    <xsl:if test="not(following-sibling::*)">}</xsl:if>
  </xsl:template>

  <!-- array -->
  <xsl:template match="*[count(../*[name(../*)=name(.)])=count(../*) and count(../*)&gt;1]">
    <xsl:if test="not(preceding-sibling::*)">[</xsl:if>
    <xsl:choose>
      <xsl:when test="not(child::node())">
        <xsl:text>null</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="child::node()"/>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:if test="following-sibling::*">,</xsl:if>
    <xsl:if test="not(following-sibling::*)">]</xsl:if>
  </xsl:template>

  <!-- convert root element to an anonymous container -->
  <xsl:template match="/">
    <xsl:apply-templates select="node()"/>
  </xsl:template>

</xsl:stylesheet>';

end get_xml_to_json_stylesheet;


function ref_cursor_to_json (p_ref_cursor in sys_refcursor,
                             p_max_rows in number := null,
                             p_skip_rows in number := null) return clob
as
  l_ctx         dbms_xmlgen.ctxhandle;
  l_num_rows    pls_integer;
  l_xml         xmltype;
  l_json        xmltype;
  l_returnvalue clob;
begin


  /*

  Purpose:    generate JSON from REF Cursor

  Remarks:

  Who     Date        Description
  ------  ----------  -------------------------------------
  MBR     30.01.2010  Created

  */

  l_ctx := dbms_xmlgen.newcontext (p_ref_cursor);

  dbms_xmlgen.setnullhandling (l_ctx, dbms_xmlgen.empty_tag);

  -- for pagination

  if p_max_rows is not null then
    dbms_xmlgen.setmaxrows (l_ctx, p_max_rows);
  end if;

  if p_skip_rows is not null then
    dbms_xmlgen.setskiprows (l_ctx, p_skip_rows);
  end if;

  -- get the XML content
  l_xml := dbms_xmlgen.getxmltype (l_ctx, dbms_xmlgen.none);

  l_num_rows := dbms_xmlgen.getnumrowsprocessed (l_ctx);

  dbms_xmlgen.closecontext (l_ctx);

  close p_ref_cursor;

  if l_num_rows > 0 then
    -- perform the XSL transformation
    l_json := l_xml.transform (xmltype(get_xml_to_json_stylesheet));
    l_returnvalue := l_json.getclobval();
  else
    l_returnvalue := g_json_null_object;
  end if;

  l_returnvalue := dbms_xmlgen.convert (l_returnvalue, dbms_xmlgen.entity_decode);

  return l_returnvalue;

end ref_cursor_to_json;


function sql_to_json (p_sql in varchar2,
                      p_param_names in t_str_array := null,
                      p_param_values in t_str_array := null,
                      p_max_rows in number := null,
                      p_skip_rows in number := null) return clob
as
  l_ctx         dbms_xmlgen.ctxhandle;
  l_num_rows    pls_integer;
  l_xml         xmltype;
  l_json        xmltype;
  l_returnvalue clob;
begin

  /*

  Purpose:    generate JSON from SQL statement

  Remarks:

  Who     Date        Description
  ------  ----------  -------------------------------------
  MBR     30.01.2010  Created
  MBR     28.07.2010  Handle null value in bind variable value (issue and solution reported by Matt Nolan)

  */


  l_ctx := dbms_xmlgen.newcontext (p_sql);

  dbms_xmlgen.setnullhandling (l_ctx, dbms_xmlgen.empty_tag);

  -- bind variables, if any
  if p_param_names is not null then

    for i in 1..p_param_names.count loop
      dbms_xmlgen.setbindvalue (l_ctx, p_param_names(i), nvl(p_param_values(i), ''));
    end loop;

  end if;

  -- for pagination

  if p_max_rows is not null then
    dbms_xmlgen.setmaxrows (l_ctx, p_max_rows);
  end if;

  if p_skip_rows is not null then
    dbms_xmlgen.setskiprows (l_ctx, p_skip_rows);
  end if;

  -- get the XML content
  l_xml := dbms_xmlgen.getxmltype (l_ctx, dbms_xmlgen.none);

  l_num_rows := dbms_xmlgen.getnumrowsprocessed (l_ctx);

  dbms_xmlgen.closecontext (l_ctx);

  -- perform the XSL transformation
  if l_num_rows > 0 then
    l_json := l_xml.transform (xmltype(get_xml_to_json_stylesheet));
    l_returnvalue := l_json.getclobval();
    l_returnvalue := dbms_xmlgen.convert (l_returnvalue, dbms_xmlgen.entity_decode);
  else
    l_returnvalue := g_json_null_object;
  end if;

  return l_returnvalue;

end sql_to_json;


end json_util_pkg;
/


PLSQ Gateway an alternative to REST services

Oracle PLSQL Gateway is the best method to use web services in old versions of Oracle Databases (10g).

I found that using oracle PLSQL Gateway , builtin feature is very useful in my case .

PLSQL Gateway depends on DAD (DataBase Access Descriptor), In the following steps we'll configure PLSQL Gateway.

* Run the following commands under  SYS privilege, All are CASE sensitive.
  1. Create  DAD :

BEGIN
  DBMS_EPG.create_dad (
                         DAD_NAME => 'sit_dad',
                         PATH     => '/sit_dad/*');
END;
/

2. Associate DAD with User who privileges must be used with DAD:



BEGIN
  DBMS_EPG.set_dad_attribute (
    dad_name   => 'sit_dad',
    attr_name  => 'database-username',
    attr_value => 'SCOTT'); -- Is the target USER
END;
/


3.Setting GATEWAY PORT:

1.First Check if port is set before:


SELECT DBMS_XDB.gethttpport FROM dual;
2. If not exists then, set it :


EXEC DBMS_XDB.sethttpport(8080);

4. To gain Anonymous Access:


EXEC DBMS_EPG.SET_DAD_ATTRIBUTE('sit_dad', 'database-username', 'ANONYMOUS');
ALTER USER ANONYMOUS ACCOUNT UNLOCK ;
then  , Recreate DAD  Again   STEP  #1

5.  Grant execute on DBMS_EPG:


GRANT EXECUTE ON DBMS_EPG TO SCOTT;


* Run the following commands  using SCOTT user:


EXEC DBMS_EPG.AUTHORIZE_DAD('sit_dad');
Here's an example For Get Data:

CREATE OR REPLACE PROCEDURE TEST(P_Id IN NUMBER) IS 
CURSOR GET_Dept_EMPS IS
  SELECT Empno, Ename, Job, Sal,Deptno
  FROM   EMP
  WHERE  DeptNo = P_Id;
BEGIN
  --------------
  FOR  i IN GET_Dept_EMPS LOOP
       HTP.P('Emp: '||i.Empno||', Name: '||i.Ename||' Job: '||i.Job||', Sal: '||i.Sal||', Dept: '||i.Deptno);
  END LOOP;
  --------------  
END;  


To call it:

POST (Insert Data) Example  :

CREATE OR REPLACE PROCEDURE ADD_DEPT( P_Depto   IN  NUMBER,
                                      P_DName   IN  VARCHAR,
                                      P_Loc     IN  VARCHAR) IS
BEGIN
  --------------------------
  INSERT INTO DEPT ( DeptNo  , DName   , Loc)
          VALUES  (  P_Depto , P_DName , P_Loc);
  COMMIT;
  --------------------------
  HTP.PRINT('Done, data Inserted');
  --------------------------
  EXCEPTION
    WHEN OTHERS THEN
      HTP.PRINT('ERROR: '||SQLERRM );
END ADD_DEPT;

To call it:
http://localhost:8080/sit_dad/ADD_DEPT?P_Depto=11&P_DName=ITDEV&P_Loc=CAIRO

Update :
Arabic is readable inside Android Studio, but when it comes to Flutter , you must change NLS Language attribute :

BEGIN
  DBMS_EPG.set_dad_attribute (
    dad_name   => 'sit_dad',
    attr_name  => 'nls-language',
    attr_value => 'American_America.UTF8');
END;
/

#7 Your first DELETE RESTful Service

Here's the case we'll work on using the following example:
The case is : How to Delete specific data from EMP_TABLE  using API ?

The Fix: Using DELETE method
Before You Begin: In contrast to GET methods,  all of POST,PUT and DELETE methods   require third party editor to run .
There are many applications for this purpose, you can install any of them using Google Chrome web store  .
YARC may be the simplest one to use , you can download it from here .


  1. Using PLSQL copy the following code:

BEGIN
  -----------------
  ORDS.DEFINE_MODULE(P_Module_Name    => 'emp',
                     P_Base_Path      => 'emp_data',
                     P_Items_Per_Page => 0);
  -----------------
  ORDS.DEFINE_TEMPLATE(P_Module_Name => 'emp', 
                       P_Pattern     => 'dml/:id');
  -----------------
  ORDS.DEFINE_HANDLER(P_Module_Name    => 'emp',
                      P_Pattern        => 'dml/:id',
                      P_Method         => 'DELETE',
                      P_Source_Type    => 'plsql/block',
                      P_Source         => 'BEGIN 
                                           DELETE FROM EMP_TABLE
                                                 WHERE Id   = :id;
                                           COMMIT;
                                           :P_Status := SQLERRM;
                                           END;',
          p_mimes_allowed  => '',
          P_Items_Per_Page => 0);
  -----------------
  ORDS.DEFINE_PARAMETER(P_Module_Name        => 'emp',
                        P_Pattern            => 'dml/:id',
                        P_Method             => 'DELETE',
                        p_name               => 'id',
                        p_bind_variable_name => 'id',
                        p_source_type        => 'HEADER',
                        p_param_type         => 'INT',
                        p_access_method      => 'IN');   
  -----------------
  ORDS.DEFINE_PARAMETER(P_Module_Name        => 'emp',
                        P_Pattern            => 'dml/:id',
                        P_Method             => 'DELETE',
                        p_name               => 'P_Status',
                        p_bind_variable_name => 'P_Status',
                        p_source_type        => 'RESPONSE',
                        p_param_type         => 'STRING',
                        p_access_method      => 'OUT');
  -----------------
  COMMIT;
  -----------------
END;
In This POST Request:
  • Employee Id = 1  was DELETED from  EMP_TABLE
  • P_Status Parameter defined to return message after inserting data
To run POST request :
  1. Click YARC extension from google chrome
  2. In the URL add: http://localhost:8080/ords/trest/emp_data/dml/1
  3. Choose from the list : DELETE
Once you have finished, click Send Request.
you should get reply of  200 and the following message: 
 {
"P_Status": "ORA-0000: normal, successful completion" }
In the next post, we'll export all REST Defined Services

#4 Your first GET RESTful Service

Here's the case we'll work on using the following example:
The case is : How to Fetch specific data from EMP_TABLE  using API ?
The Fix: Using GET method

  1. Using PLSQL copy the following code:

BEGIN
  -----------------
  ORDS.DEFINE_MODULE(P_Module_Name    => 'emp',
                     P_Base_Path      => 'emp_data',
                P_Items_Per_Page => 0);
  -----------------
  ORDS.DEFINE_TEMPLATE(P_Module_Name => 'emp', 
                       P_Pattern     => 'dml/:P_Emp_Id');
  -----------------
  ORDS.DEFINE_HANDLER(P_Module_Name    => 'emp',
                      P_Pattern        => 'dml/:P_Emp_Id',
        P_Method         => 'GET',
        P_Source_Type    => Ords.Source_Type_Collection_Feed,
        P_Source         => 'SELECT * FROM EMP_TABLE WHERE Id = :P_Emp_Id',
        P_Items_Per_Page => 0);
  -----------------
  ORDS.DEFINE_PARAMETER(P_Module_Name        => 'emp',
                        P_Pattern            => 'dml/:P_Emp_Id',
                        P_Method             => 'GET',
                        p_name               => 'P_Emp_Id',
                        p_bind_variable_name => 'P_Emp_Id',
                        p_source_type        => 'HEADER',
                        p_param_type         => 'INT',
                        p_access_method      => 'IN');   
  COMMIT;
  -----------------
END;
/


You now have created your first REST API , the URL IS: http://localhost:8080/ords/trest/emp_data/dml/1
To get Employee Number 1 , add 1 at the end of URI

#1 Deploy Oracle REST Data Service (ORDS)

What is ORDS ? 

ORDS is a Java application that enables developers with SQL and database skills to develop REST APIs for the Oracle Database, the Oracle Database 12c JSON Document store, and the Oracle NoSQL Database. Any application developer can use these APIs from any language environment, without installing and maintaining client drivers, in the same way they access other external services using the most widely used API technology: REST .  ORACLE site

Required Software: 

  1. JDK (download from : https://www.oracle.com/technetwork/java/javaee/downloads/jdk8-downloads-2133151.html )

    • install to c:\Program Files\Java

  1. Oracle REST (download from : https://www.oracle.com/technetwork/developer-tools/rest-data-services/downloads/index.html )
    • extract ords.war  to c:\Oracle\ords\ords.war
  2. Oracle database  12c or later


How to Enable ORDS ? 
  1. Uninstall if exists using :c:\Program Files\Java\jdk1.8.0_152\bin>java -jar c:\Oracle\ords\ords.war uninstall
    • Enter required data like SYS password
  2. Download a fresh copy of ORDS from : 
  3. install using : c:\Program Files\Java\jdk1.8.0_152\bin>java -jar D:\Oracle\ords\ords.war install
    • Enter the location to store configuration data: D:\Oracle\ords\conf
    • Enter the name of the database server [localhost]: localhost
    • Enter the database listen port [1521]: 1521
    • Enter 1 to specify the database service name, or 2 to specify the database SID [1]: 1
    • Enter the database service name : ORCL
    • Enter 1 if you want to verify/install Oracle REST Data Services schema or 2 to skip this step [1]: 1
    • Enter the database password for ORDS_PUBLIC_USER:oracle
    • Confirm password:oracle
    • Enter the administrator username:SYS *
    • Enter the database password for SYS AS SYSDBA:123456
    • Confirm password:123456
    • Enter 1 if you want to use PL/SQL Gateway or 2 to skip this step.If using Oracle Application Express or migrating from mod_plsql then you must enter 1 [1]: 2
    • Enter 1 if you wish to start in standalone mode or 2 to exit [1]: 1
    • Enter 1 if using HTTP or 2 if using HTTPS [1]:1
    • Enter the HTTP port [8080]:8080
IF you get the following message , this means ORDS is running :
2019-04-28 10:07:46.989:INFO:oejs.Server:main: Started @331997ms

 * Important Notice: You can get this error when installing ORDS:
ords_grant_privs.sql Error: ORA-01031: insufficient privileges
This  is a result of lack of current USER Privileges  even if it was GRANTED DBA permission.
SO , it's very recommended to  use SYS  with a DIGIT password as Oracle ORDS has a built-in Bug which cannot identify passwords letters case.
You changed SYS password  using :
ALTER USER SYS IDENTIFIED BY oracle;
To read more about this bug go here:  https://community.oracle.com/thread/4120820

Remove unused Layouts in Oracle Apex

 Tables used : APEX_XXXXXXX.WWV_FLOW_REPORT_LAYOUTS APEX_XXXXXXX.WWV_FLOW_SHARED_QUERIES use the following query to delete unused Layouts. ...