# Oracle Session Parameter per JDBC?



## AMiGA (17. Feb 2010)

Hallo,

ich habe per JDBC eine Verbindung zu einer Oracle Datenbank hergestellt. Beim Öffnen der Verbindung kann man ja Sitzungsparameter setzen:


```
StringBuffer url = new StringBuffer();

url.append("jdbc:oracle:thin:");
url.append("@" + hostName);
url.append(":" + port + ":");
url.append(databaseName);

Properties props = new Properties();
props.put("v$session.program", "Programmname");

DriverManager.getConnection(url, props);
```

Ist dies auch während einer Sitzung irgendwie möglich? Ich würde gerne direkt vor einem (Delete-) Statement einen Sitzungsparameter setzen.

Hintergrund ist, dass beim Ausführen des Delete-Statements ein Trigger angestoßen wird, der den Datensatz vor dem Löschen in eine Historien-Tabelle schreibt. Beim Löschen wird aber nicht der (Applikations-) Benutzer im Datensatz aktualisiert, so dass ich diesen Wert gerne per Sitzungsparameter an Oracle weiterreichen würde, so dass der Trigger ihn dann auswerten und beim Wegschreiben setzen kann.

Gruß,
AMiGA


----------



## MrWhite (17. Feb 2010)

Klar geht das:

Nativen Query der Form 


```
ALTER SESSION ...
```

absetzen.

Macht man gerne mit Optimizern z.B.

Der rulebased Optimizer ist naemlich wesentlich performanter bei kaskadierten Views und anderen Scherzen.


----------



## AMiGA (18. Feb 2010)

Okay, also mit 
	
	
	
	





```
ALTER SESSION SET parameter = value
```
 kann ich Parameterwerte setzen, das ist schon mal gut, danke.

Kann ich denn auch eigene Parameter definieren oder kann ich irgendeinen Oracle-Parameter für meinen Wert missbrauchen? 



> Der rulebased Optimizer ist naemlich wesentlich performanter bei kaskadierten Views und anderen Scherzen.


Also ist 
	
	
	
	





```
alter session set optimizer_mode=RULE
```
 heute immer noch üblich? Ich dachte, dass das seit Oracle 10 keine Auswirkungen mehr hat weil Oracle Statements selbstständig optimiert.

Gruß,
AMiGA


----------



## MrWhite (18. Feb 2010)

AMiGA hat gesagt.:


> Okay, also mit
> 
> 
> 
> ...



Hmm, spontan würde ich dir raten, ein Package anzulegen und dort die Variable zu deklarieren. Beim Starten der Applikation kannst du dort deinen User reinschreiben und die Trigger können es dort rauslesen. Öffentliche Variablen in Packages sind im Session-Scope;

Alles andere funktioniert nur mit SQL+, denke ich.




> Also ist
> 
> 
> 
> ...



Aber hallo! Gib dir mal Explain-Pläne mit der rulebased optimization aus. Die sind gerade unter 10g oft wesentlich performanter! Nach einer Migration auf 10g mussten wir da viele Selects mit der /*+ rule */ hint versehen, sonst wäre überhaupt nichts mehr gelaufen!


----------



## Gast2 (21. Feb 2010)

Anstatt in Packages globale Variablen zu setzen würd ich eher eine Context empfehlen:
create context [Oracle]

Erfordert allerdings das der DBA die CREATE CONTEXT granted


----------



## AMiGA (24. Feb 2010)

Leider klappt es immer noch nicht wie gewünscht. Folgendes habe ich gemacht:

Package angelegt:

```
CREATE PACKAGE MyPackage AS
   UsrName VARCHAR2(10);
   PROCEDURE setUsrName(param IN VARCHAR2);
   FUNCTION getUsrName RETURN VARCHAR2;
END MyPackage;
```

Package Body angelegt:

```
CREATE PACKAGE BODY MyPackage AS
   PROCEDURE setUsrName(param IN VARCHAR2) IS
   BEGIN
      UsrName := param;
   END;

   FUNCTION getUsrName RETURN VARCHAR2 IS
   BEGIN
      RETURN UsrName;
   END;
END MyPackage;
```

Wenn ich im SQL-Tool 
	
	
	
	





```
EXECUTE MyPackage.setUsrName('NAME');
```
 ausführe, ist alles in Ordnung. Ich kann den übergebenen Namen danach mit 
	
	
	
	





```
SELECT MyPackage.getUsrName FROM DUAL;
```
 wieder auslesen.

In meinem Java-Programm funktioniert es aber nicht:

```
Statement stmt = connection.createStatement();
stmt.execute("SELECT MyPackage.getUsrName FROM DUAL;");
stmt.close();
```
liefert mir java.sql.SQLSyntaxErrorException: ORA-00900: Ungültige SQL-Anweisung.

Was mache ich falsch?

Noch eine Frage zum Package: Das Package gilt nur auf Sitzungsebene? Das heißt, ich kann für jede Sitzung ein eigenes Package anlegen? Sobald die Sitzung beendet wird, verschwindet auch das Package wieder?

Gruß,
AMiGA


----------



## Gast2 (24. Feb 2010)

Du darfst das ";" nicht mitgeben. Ausserdem musst du sicherstellen das das package überhaupt gefunden wird. Also du müsstest schon das Schema mit angeben oder ein PUBLIC Synonym verwenden.

Ehrlich gesagt ist das mit dem Package aber eher nicht der Weg den ich gehen würde. hast du dir mal ORACLE Contexte angesehn (sieh mein letzer Kommentar)? Das ist für genau so etwas gedacht.

Ein package "existiert" persistent. Wenn du einmal "CREATE OR REPLACE" gemacht hast gibt es das package bis es mit "DROP" entfernt wird.

Der Wert deiner Variablen gilt allerdings nur für die aktuelle Datenbank Session. Wenn du die Verbidnung schließt und wieder öffnest ist der Wert weg. Du kannst also in 5 sitzungen 5 mal die SET-Procedur mit unterschielidhcen Werten aufrufen.

Nebenbei - was macht deine Funktion wenn vorher nicht mit der Procedur ein Wert gesetzt wurde? Solltest du drauf achten.

Aber nochmal - schau die Contexte an


----------



## AMiGA (24. Feb 2010)

> Aber nochmal - schau die Contexte an


Okay, danke. Ich hatte das zunächst nur überflogen, tut mir leid. Dabei hatte ich gesehen, dass auch dort Packages erzeugt werden und hatte vermutet, dass es noch eine Stufe komplexer ist. Sorry.

Folgendes habe ich nun angelegt:

```
CREATE CONTEXT MyContext USING MyPackage;

CREATE PACKAGE MyPackage AS
   PROCEDURE setValue(value IN VARCHAR2);
END MyPackage;

CREATE PACKAGE BODY MyPackage AS
   PROCEDURE setValue(value IN VARCHAR2) IS
   BEGIN
      dbms_session.set_context('MyContext', 'UsrName', value);
   END setValue;
END MyPackage;
```

Ein Aufruf von 
	
	
	
	





```
exec MySchema.MyPackage.setValue('Test');
```
 sowie 
	
	
	
	





```
SELECT sys_context('MyContext', 'UsrName') FROM DUAL;
```
 funktioniert im SQL-Tool wunderbar.

Von der Java-Anwendung aus funktioniert das Auslesen auch (mit dem Ergebnis NULL, ist ja in Ordnung). Das Setzen eines Wertes funktioniert leider immer noch nicht. Ich erhalte wieder eine java.sql.SQLSyntaxErrorException: ORA-00900: Ungültige SQL-Anweisung. Das Semikolon habe ich weggelassen. Auch der Aufruf mit ergänztem Schema schlägt fehl.

Ich bedanke mich schonmal für die Unterstützung!

Gruß,
AMiGA


----------



## Gast2 (24. Feb 2010)

Du kannst nur Functionen in einem SELECT verwenden. Procedures musst du in einem anonymen PL/SQL Block aufrufen


```
String sql  = "BEGIN ";
          sql += "  MySchema.MyPackage.setValue('Test'); ";
          sql += "END;";
```


----------



## AMiGA (25. Feb 2010)

Funktioniert perfekt, danke!

Edit: Um das ganze sauber zu programmieren, würde ich gerne programmtechnisch feststellen, ob der Context bzw. das Package in der DB überhaupt vorhanden ist. Leider habe ich da bislang noch keinen Weg gefunden.

In v$context werden wohl nur die bereits gesetzten Werte abgelegt. In DBA_SOURCE könnte ich nachschauen, ob das Package angelegt ist, da hat der DB-User aber normalerweise keine Rechte zu.

Gibt es einen View, wo man die Packages eines Users sehen kann?

Edit2: USER_OBJECTS scheint geeignet zu sein.

Gruß,
AMiGA


----------



## Gast2 (25. Feb 2010)

Es gibt immer drei Views bei ORACLE. Das gilt für Objecte wie auch für privilegen, user (gut hiernicht, da sind es nur zwei) etc.
DBA
ALL
USER

z.B. DBA_OBJECTS, ALL_OBJECTS und USER_OBJECTS

Für einen Anwender oder Programmierer reicht meist ALL_OBJECTS und USER_OBJECTS


----------



## AMiGA (1. Mrz 2010)

> Für einen Anwender oder Programmierer reicht meist ALL_OBJECTS und USER_OBJECTS.


Okay, ich denke USER_OBJECTS ist das Richtige für mich.

Wie unter create context [Oracle] ganz unten zu lesen, besteht leider nicht die Möglichkeit, einen Kontext in einem bestimmten Schema anzulegen. Wenn ich mehrere Schemata in einer Datenbank habe und für jedes Schema den Kontext mit Package und Package Body erzeuge, erhalte ich beim Zugriff mittels dbms_session.set_context nun "ORA-01031 Nicht ausreichende Berechtigungen". Besteht irgendeine Möglichkeit, dies für verschiedene Schemata zu realisieren?

Kann ich per SQL im voraus abfragen, ob ich die benötigten Zugriffsrechte unter Oracle habe? Ansonsten müßte ich programmtechnisch die Exception abfangen, was eher unschön wäre.

Gruß,
AMiGA


----------



## AMiGA (3. Mrz 2010)

> Kann ich per SQL im voraus abfragen, ob ich die benötigten Zugriffsrechte unter Oracle habe?


Bislang habe ich leider noch nichts wirklich brauchbares gefunden. Die Rollen des angemeldeten Benutzers finde ich in USER_ROLE_PRIVS, die einzelnen Privilegien in SESSION_PRIVS. Ich weiß aber leider nicht, wie ich prüfen kann, ob der Kontext MyContext dem Package MySchema.MyPackage oder aber dem Package OtherSchema.MyPackage zugeordnet ist.

Ein Kontext für mehrere Schemata scheint ja leider nicht möglich zu sein. D.h. ich muss für jedes Schema auch einen eigenen Kontext anlegen, der dann auch anders benannt ist, da er ja im SYS-Schema abgelegt wird?

Gruß,
AMiGA


----------



## Gast2 (3. Mrz 2010)

Alle Priviliegen eines Benutzers verlässlich abfragen geht nur über einige DBA Views, ist aber auch nicht nötig. Was spricht denn dagegen es einfach mal auszuprobieren und die Exception abzufangen? Das ist doch genau der Sinn dahinter, in deinem Design solltest du die Datenbank soweit wie möglich abstrahieren. 

Ob du jetzt ein Statement absetzt, das Resultset ausließt und dann entschließt das du Statement2 absetzten darfst oder gleich Statement2 abschießt ist doch egal, um genauzu sein eigentlich ist es sogar besser gleich Statement2 zu versuchen.

In einen [c]try [...] catch (SQLException)[/c] Block muss eh alles rein. 

Mir erschließt sich noch nicht ganz was du vorhast? Wofür brauchst du für jedes Schema einen Kontext? Bist du dir über deine Applikationstruktur klar? Versuch mal zu umreißen was du eigentlich machen möchtes, ich denke das Design deiner (verteilten) Anwendung ist "verbesserungswürdig" <- nicht bös gemeint.


----------



## AMiGA (3. Mrz 2010)

> Mir erschließt sich noch nicht ganz was du vorhast? Wofür brauchst du für jedes Schema einen Kontext? Bist du dir über deine Applikationstruktur klar? Versuch mal zu umreißen was du eigentlich machen möchtes, ich denke das Design deiner (verteilten) Anwendung ist "verbesserungswürdig" <- nicht bös gemeint.


Oh sorry, hatte ich gar nichts zu gesagt. Grundsätzlich habe ich *eine* Applikation mit *einem* Schema und *einem* Kontext. Da wir auf den Entwicklerrechnern unter Umständen aber mehrere Projekte parallel entwickeln, haben wir dort entsprechend auch mehrere Schemata.

Ich werde es wohl so lösen, dass beim Start der Applikation der Kontext jeweils neu angelegt wird:


```
CREATE OR REPLACE CONTEXT MyContext USING MyPackage;
```
Dadurch hat die gestartete Applikation dann automatisch die erforderlichen Rechte.

Gruß,
AMiGA


----------

