'****************************************************************************
' (c) Copyright IBM Corp. 2007 All rights reserved.
'
' The following sample of source code ("Sample") is owned by International
' Business Machines Corporation or one of its subsidiaries ("IBM") and is
' copyrighted and licensed, not sold. You may use, copy, modify, and
' distribute the Sample in any form without payment to IBM, for the purpose of
' assisting you in the development of your applications.
'
' The Sample code is provided to you on an "AS IS" basis, without warranty of
' any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR
' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do
' not allow for the exclusion or limitation of implied warranties, so the above
' limitations or exclusions may not apply to you. IBM shall not be liable for
' any damages you suffer as a result of using, copying, modifying or
' distributing the Sample, even if IBM has been advised of the possibility of
' such damages.
'****************************************************************************
'
' SOURCE FILE NAME: UDFcli.vb
'
' SAMPLE: Client application that calls the UDFs in UDFsrv.vb
'
'****************************************************************************
'
'  Steps to run the sample with the command line window:
'
'        I)  If you have a compatible nmake program on your system, 
'            do the following:
'
'            1. Compile this server source file, UDFsrv.vb. This 
'               erases any existing assembly of the same name and copies
'               the newly compiled assembly UDFsrv.dll from the 
'               current directory to the $(DB2PATH)\function directory). 
'               This also runs a batchfile UDFCat that executes SQL to 
'               drop (if already existing) and create the UDFs
'               in DB2 that have their UDF-body implemented by the 
'               methods in this file, UDFsrv.vb:
'
'                   nmake/make UDFsrv
'
'              To run UDFcli successfully you must have succesfully
'              completed step 1.
'
'            2. Compile the client source file UDFcli.vb.   
'
'                   nmake/make UDFcli
'
'            3. Run the client UDFcli:
'
'                   UDFcli
'
'
'        II) If you don't have a compatible nmake program on your 
'            system do the following:
'
'            1. Compile this file, UDFsrv.vb, containing the Visual Basic  
'               (VB) UDF methods that implement the UDF-bodies, with 
'               bldrn.bat. This batch file first erases any
'               existing assembly of the same name.  Then it 
'               compiles UDFsrv.vb and copies the assembly file 
'               UDFsrv.dll from the current directory to the DB2 function 
'               directory:  $(DB2PATH)\function.  
'
'                   bldrtn UDFsrv
'
'
'            2. Create the UDFs in DB2 by entering the following 
'               at the command prompt:
'
'                   UDFCat
'
'               This will drop the UDFs from DB2, if they exist, and 
'               then executes SQL CREATE FUNCTION statements to create the
'               UDFs in DB2.  These statements associate each function 
'               name with an external VB method in the assembly UDFsrv.dll 
'               that is in the DB2 function directory.
'
'            3. Compile the UDFcli.vb file with the bldapp.bat batch file by 
'               entering the following at the command prompt:
'
'                  bldapp UDFcli 
'
'            4. Run the UDFcli program by entering the program name at 
'               the command prompt:
'
'                 UDFcli
'
'  UDFcli calls several methods that call the UDFs:
'
'  Class UDFsrv contains the following methods:
'
'     1. ScalarUDF               Updates employee salary based on job type
'     2. ScratchpadScalarUDF     Increments a count each time UDF is called
'     3. ScalarUDFReturningError Shows how to return an error from a UDF 
'     4. TableUDF                Given a salary update multiplier returns a 
'                                 table-reference with employees' names, jobs, 
'                                 and updated salaries   
'
'****************************************************************************
'
' SQL Statements USED:
'         SELECT
'         UPDATE
'
'                           
'****************************************************************************
'
' For more information on the sample programs, see the README file.
'
' For information on developing JDBC applications, see the Application
' Development Guide.
'
' For information on using SQL statements, see the SQL Reference. 
'
'****************************************************************************/

Imports System
Imports System.Data
Imports Microsoft.VisualBasic
Imports IBM.Data.DB2

Public Class UDFClient

  Public Shared Sub Main(args() As String)

   ' Declare a DB2Connection and a DB2Transaction 
    Dim conn As DB2Connection
    Dim trans As DB2Transaction

    Try
      Console.WriteLine( _
        vbNewLine & _
        "  THIS SAMPLE SHOWS HOW TO CALL THE UDFs" & _ 
        " IN UDFsrv.vb")
      Console.WriteLine() 

      ' Connect to a database
      Console.WriteLine("  Connecting to a database ...")
      conn = ConnectDb(args)

      ' Invoke an external scalar UDF: ScalarUDF
      trans=conn.BeginTransaction()
      InvokeExternalScalarUDF(conn, trans)

      ' Invoke a scalar UDF with a scratchpad: ScratchpadScUDF
      trans=conn.BeginTransaction()
      InvokeScratchpadScUDF(conn, trans)

      ' Invoke a scalar UDF that returns an error: ScUDFReturningErr
      trans=conn.BeginTransaction()
      InvokeScUDFReturningErr(conn, trans)
      
      ' Invoke a table UDF with a scratchpad: TableUDF
      trans=conn.BeginTransaction()
      InvokeTableUDF(conn, trans)

      ' Disconnect from the database
      Console.WriteLine( _
        vbNewLine & "  Disconnect from the database")
      conn.Close()

    Catch e As Exception
      Console.WriteLine( _
        vbNewLine & "Error caught in client of UDFsrv application.")
      Console.WriteLine(e.ToString())
      Try
        conn.Close()
      Catch x As Exception
        Console.WriteLine(x.Message)
      End Try
    End Try

  End Sub ' Main



  ' This method establishes a connection to a database
  Public Shared Function ConnectDb(argv() As String) As DB2Connection

    Dim server As String
    Dim dbalias As String
    Dim userId As String
    Dim password As String
    Dim portNumber As Int32 = -1
    Dim connectString As String

    If (argv.Length > 5) Then
      Throw new Exception( _
        "Usage: prog_name [dbAlias] [userId passwd]" & vbNewLine & _
        "       prog_name [dbAlias] server portNum userId passwd")
    Else
      If (argv.Length = 1) Then
        If( String.Compare(argv(0),"?") = 0           Or _
            String.Compare(argv(0),"-?") = 0          Or _
            String.Compare(argv(0),"/?") = 0          Or _
            String.Compare(argv(0),"-h",true) = 0     Or _
            String.Compare(argv(0),"/h",true) = 0     Or _
            String.Compare(argv(0),"-help",true) = 0  Or _
            String.Compare(argv(0),"/help",true) = 0 ) Then

          Throw new Exception( _
            "Usage: prog_name [dbAlias] [userId passwd]" & vbNewLine & _
            "       prog_name [dbAlias] server portNum userId passwd")
        End If
      End If
    End If

    Select Case (argv.Length)
      Case 0  ' Use all defaults
        dbalias = "sample"
        userId = ""
        password = ""
      Case 1  ' dbAlias specified
        dbalias = argv(0)
        userId = ""
        password = ""
      Case 2  ' userId & passwd specified
        dbalias = "sample"
        userId = argv(0)
        password = argv(1)
      Case 3  ' dbAlias, userId & passwd specified
        dbalias = argv(0)
        userId = argv(1)
        password = argv(2)
      Case 4  ' use default dbAlias
        dbalias = "sample"
        server = argv(0)
        portNumber = Convert.ToInt32(argv(1))
        userId = argv(2)
        password = argv(3)
      Case 5  ' everything specified
        dbalias = argv(0)
        server = argv(1)
        portNumber = Convert.ToInt32(argv(2))
        userId = argv(3)
        password = argv(4)

    End Select

    If(portNumber = -1) Then
      connectString = "Database=" & dbalias
    Else
      connectString = "Server=" & server & ":" & portNumber & _
                      "Database=" & dbalias
    End If
    
    If (userId <> "")
      connectString += "UID=" & userId & "PWD=" & password
    End If

    Dim conn As DB2Connection = new DB2Connection(connectString)
    conn.Open()
    Console.WriteLine("  Connected to the " & dbalias & " database")
    Return conn

  End Function ' ConnectDb



  ' Helper method: This method displays the result set contained in the
  ' DB2DataReader
  Public Shared Sub DisplayResultSet (reader As DB2DataReader)
  
    Do While reader.Read()
      Console.Write("    ")
      Dim k As integer
      For k=0 To reader.FieldCount-1
        Dim str As String
        If (Equals(reader.GetFieldType(k), _
                   Type.GetType("System.Decimal"))) Then
          str = FormatNumber(CType(reader.GetValue(k),Decimal),2)
        Else
          str = reader.GetValue(k).ToString()
        End If
        If (str.Length < 10) Then
          Console.Write(str.PadRight(10, Convert.ToChar(" ") ) & " ")
        Else
          Console.Write(str.Substring(0, 10) & " ")
        End If
      Next k
      Console.WriteLine()
    Loop

  End Sub ' DisplayResultSet


  Public Shared Sub InvokeExternalScalarUDF(conn As DB2Connection, _
                                            trans As DB2Transaction)

    Dim reader As DB2DataReader 
    Dim cmd As DB2Command  
 
    Try
      Console.WriteLine("")
      Console.WriteLine("  Invoke the scalar UDF 'ScalarUDF' in a SELECT" & _ 
                        " statement:")
      Console.WriteLine()
      Console.WriteLine("    SELECT name, job, salary, ")
      Console.WriteLine("           ScalarUDF(cast(job as char(5)), salary)")
      Console.WriteLine("            AS calculated_salary")
      Console.WriteLine("      FROM staff")
      Console.WriteLine("        WHERE name LIKE 'S%'")
      Console.WriteLine("")  

      ' Create a DB2Command to execute a SELECT statement with a UDF reference
      cmd = conn.CreateCommand()
      cmd.Transaction = trans
      cmd.CommandText = "SELECT name, job, salary, " & _
                        "       ScalarUDF(cast(job as char(5)), salary) " & _
                        "        AS calculated_salary " & _
                        "  FROM staff " & _
                        "  WHERE name LIKE 'S%'"
      reader = cmd.ExecuteReader()

      Console.WriteLine("    NAME       JOB        SALARY     CALCULATED_SALARY")
      Console.WriteLine("    ---------- ---------- ---------- -----------------")
      
      ' Display the result set
      DisplayResultSet(reader)
      reader.Close()

      ' Rollback the transactions to preserve the SAMPLE 
      ' database's original state
      trans.Rollback()
      
    Catch e As exception 
      reader.Close()
      trans.Rollback()
      Console.WriteLine(e.ToString())
    End Try

  End Sub ' InvokeScalarUDF



  ' This method invokes external scratchpad scalar UDF, ScratchpadScUDF, in
  ' a SELECT query.  The scratchpad scalar UDF generates a row value for each
  ' row that is returned by the query - a quick way to display a numbered 
  ' list to accompany row values without having to alter the table.
  public Shared Sub InvokeScratchpadScUDF(conn As DB2Connection, _
                                          trans As DB2Transaction)

    Dim reader As DB2DataReader 
    Dim cmd As DB2Command 

    Try
      Console.WriteLine()
      Console.WriteLine("  Invoke the scratchpad scalar UDF "  & _
                        "'ScratchpadScUDF' in a SELECT statement:")
      Console.WriteLine()         
      Console.WriteLine("    SELECT ScratchpadScUDF() AS row_id, name, job")
      Console.WriteLine("      FROM staff")
      Console.WriteLine("        WHERE name LIKE 'S%'")
      Console.WriteLine()  

      ' Create a DB2Command to execute a SELECT statement with a UDF reference
      cmd = conn.CreateCommand()
      cmd.Transaction = trans
      cmd.CommandText = "SELECT ScratchpadScUDF() AS row_id, name, job " & _
                        "  FROM staff " & _
                        "    WHERE name LIKE 'S%'"

      reader = cmd.ExecuteReader()

      Console.WriteLine("    ROW_ID     NAME       JOB")
      Console.WriteLine("    ---------- ---------- -------")
      
      ' Display the result set
      DisplayResultSet(reader)
      reader.Close()

      ' Rollback the transactions to preserve the SAMPLE 
      ' database's original state
      trans.Rollback()
    
    Catch e As Exception
      reader.Close()
      trans.Rollback()
      Console.WriteLine(e.ToString())
    End Try  
    
  End Sub ' InvokeScratchpadScUDF



   ' This method invokes a scratchpad scalar UDF in a SELECT query to show how
   ' how an error is returned from a UDF.  The UDF performs a simple division.
   ' If the input divisor is 0, an error is returned.
  public Shared Sub InvokeScUDFReturningErr(conn As DB2Connection, _
                                            trans As DB2Transaction)
   
    Dim reader As DB2DataReader
    Dim cmd As DB2Command  
    
    Try
      Console.WriteLine()
      Console.WriteLine("  Invoke the scalar UDF 'ScUDFReturningErr'," & _
                        " which returns an error, in a SELECT statement:")
      Console.WriteLine()
      Console.WriteLine("    SELECT name, job, ScUDFReturningErr(salary, 0.0)")
      Console.WriteLine("           AS calculated_salary")
      Console.WriteLine("      FROM staff")
      Console.WriteLine("        WHERE name LIKE 'S%' ")
      Console.WriteLine()  

      ' Create a DB2Command to execute a SELECT statement with a UDF reference
      cmd = conn.CreateCommand()
      cmd.Transaction = trans
      cmd.CommandText = "SELECT ScUDFReturningErr(cast(salary as double), 0.00) " & _
                        "       AS divided_salary " & _
                        "  FROM staff " & _
                        "    WHERE name LIKE 'S%'"
      reader = cmd.ExecuteReader()

      ' Display the result set
      DisplayResultSet(reader)
      reader.Close()

      ' Rollback the transactions to preserve the SAMPLE  
      ' database's original state
      trans.Rollback()      
    
    Catch e As Exception
      reader.Close()
      trans.Rollback()
      Console.WriteLine(e.ToString())
    End Try 
    
  End Sub ' InvokeScUDFReturningErr



  ' This method updates salaries in the EMPLOYEE table according to 3 values
  public Shared Sub InvokeTableUDF(conn As DB2Connection, _
                                   trans As DB2Transaction)

    Dim reader As DB2DataReader
    Dim cmd As DB2Command
    
    Try
      Console.WriteLine()
      Console.WriteLine("  Invoke the tableUDF 'TableUDF'," & _
                        " in a SELECT statement:")
      Console.WriteLine()
      Console.WriteLine("    SELECT udfTable.name, udfTable.job,")
      Console.WriteLine("           udfTable.salary")
      Console.WriteLine("      FROM TABLE(TableUDF(1.5))")
      Console.WriteLine("        AS udfTable")
      Console.WriteLine()  

      ' Create a DB2Command to execute a SELECT statement with 
      ' a UDF table-reference (note the use of the keyword TABLE)
      cmd = conn.CreateCommand()
      cmd.Transaction = trans
      cmd.CommandText = "SELECT udfTable.name, udfTable.job, udfTable.salary" & _
                        "  FROM TABLE(TableUDF(1.5))" & _
                        "    AS udfTable"
      reader = cmd.ExecuteReader()

      Console.WriteLine("    NAME       JOB        SALARY")
      Console.WriteLine("    ---------- ---------- -------")

      ' Display the result set
      DisplayResultSet(reader)
      reader.Close()

      ' Rollback the transactions to preserve the SAMPLE  
      ' database's original state
      trans.Rollback()
    
    Catch e As Exception 
      reader.Close()
      trans.Rollback()
      Console.WriteLine(e.ToString())
    End Try
    
  End Sub ' InvokeTableUDF

End Class