first commit
This commit is contained in:
BIN
app/services/__pycache__/database_manager.cpython-313.pyc
Normal file
BIN
app/services/__pycache__/database_manager.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/services/__pycache__/database_service.cpython-313.pyc
Normal file
BIN
app/services/__pycache__/database_service.cpython-313.pyc
Normal file
Binary file not shown.
76
app/services/database_manager.py
Normal file
76
app/services/database_manager.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from app.services.database_service import DatabaseService
|
||||
import os
|
||||
|
||||
class DatabaseManager:
|
||||
"""Manager für verschiedene Datenbankverbindungen"""
|
||||
|
||||
def __init__(self):
|
||||
self.connections = {}
|
||||
self._load_default_connections()
|
||||
|
||||
def _load_default_connections(self):
|
||||
"""Lade Standard-Datenbankverbindungen"""
|
||||
|
||||
# Oracle-Datenbank (wenn konfiguriert)
|
||||
oracle_host = os.environ.get('ORACLE_HOST')
|
||||
if oracle_host:
|
||||
self.connections['oracle'] = {
|
||||
'name': 'Oracle Database',
|
||||
'type': 'oracle',
|
||||
'description': 'Oracle-Produktionsdatenbank',
|
||||
'host': oracle_host,
|
||||
'port': int(os.environ.get('ORACLE_PORT', 1521)),
|
||||
'service_name': os.environ.get('ORACLE_SERVICE_NAME', 'ORCL'),
|
||||
'username': os.environ.get('ORACLE_USERNAME'),
|
||||
'password': os.environ.get('ORACLE_PASSWORD')
|
||||
}
|
||||
|
||||
# PostgreSQL (wenn konfiguriert)
|
||||
postgres_host = os.environ.get('POSTGRES_HOST')
|
||||
if postgres_host:
|
||||
self.connections['postgres'] = {
|
||||
'name': 'PostgreSQL Database',
|
||||
'type': 'postgresql',
|
||||
'description': 'PostgreSQL-Datenbank',
|
||||
'host': postgres_host,
|
||||
'port': int(os.environ.get('POSTGRES_PORT', 5432)),
|
||||
'database': os.environ.get('POSTGRES_DATABASE', 'postgres'),
|
||||
'username': os.environ.get('POSTGRES_USERNAME'),
|
||||
'password': os.environ.get('POSTGRES_PASSWORD')
|
||||
}
|
||||
|
||||
def get_database_service(self, connection_name='demo'):
|
||||
"""Erstelle DatabaseService für spezifische Verbindung"""
|
||||
if connection_name not in self.connections:
|
||||
raise ValueError(f"Datenbankverbindung '{connection_name}' nicht gefunden")
|
||||
|
||||
config = self.connections[connection_name]
|
||||
|
||||
# Nur Oracle-Verbindungen unterstützt
|
||||
return DatabaseService(config)
|
||||
|
||||
def get_available_connections(self):
|
||||
"""Hole alle verfügbaren Datenbankverbindungen"""
|
||||
return [
|
||||
{
|
||||
'key': key,
|
||||
'name': config['name'],
|
||||
'type': config['type'],
|
||||
'description': config['description']
|
||||
}
|
||||
for key, config in self.connections.items()
|
||||
]
|
||||
|
||||
def test_connection(self, connection_name):
|
||||
"""Teste eine Datenbankverbindung"""
|
||||
try:
|
||||
db_service = self.get_database_service(connection_name)
|
||||
|
||||
# Oracle Test-Query
|
||||
test_query = "SELECT 1 FROM DUAL"
|
||||
|
||||
result = db_service.execute_query(test_query)
|
||||
return {'success': True, 'message': 'Verbindung erfolgreich'}
|
||||
|
||||
except Exception as e:
|
||||
return {'success': False, 'message': str(e)}
|
||||
268
app/services/database_service.py
Normal file
268
app/services/database_service.py
Normal file
@@ -0,0 +1,268 @@
|
||||
import os
|
||||
from flask import current_app
|
||||
import logging
|
||||
|
||||
# Oracle-Unterstützung
|
||||
try:
|
||||
import oracledb
|
||||
ORACLE_AVAILABLE = True
|
||||
except ImportError:
|
||||
try:
|
||||
import cx_Oracle
|
||||
ORACLE_AVAILABLE = True
|
||||
except ImportError:
|
||||
ORACLE_AVAILABLE = False
|
||||
logging.warning("Oracle-Treiber nicht verfügbar. Installiere cx-Oracle oder oracledb für Oracle-Unterstützung.")
|
||||
|
||||
# Weitere Datenbank-Treiber
|
||||
try:
|
||||
import psycopg2
|
||||
POSTGRESQL_AVAILABLE = True
|
||||
except ImportError:
|
||||
POSTGRESQL_AVAILABLE = False
|
||||
|
||||
try:
|
||||
import pymysql
|
||||
MYSQL_AVAILABLE = True
|
||||
except ImportError:
|
||||
MYSQL_AVAILABLE = False
|
||||
|
||||
class DatabaseService:
|
||||
def __init__(self, connection_config=None):
|
||||
"""
|
||||
Initialisiere Database Service - Nur Oracle-Unterstützung
|
||||
connection_config: Dictionary mit Oracle-Verbindungsparametern
|
||||
"""
|
||||
if connection_config is None:
|
||||
raise ValueError("Oracle-Verbindungskonfiguration erforderlich")
|
||||
|
||||
self.connection_config = connection_config
|
||||
self.db_type = connection_config.get('type', 'oracle')
|
||||
|
||||
if self.db_type == 'oracle':
|
||||
self._validate_oracle_config()
|
||||
else:
|
||||
raise ValueError(f"Datenbanktyp '{self.db_type}' wird nicht unterstützt. Nur Oracle ist verfügbar.")
|
||||
|
||||
def _validate_oracle_config(self):
|
||||
"""Validiere Oracle-Konfiguration"""
|
||||
if not ORACLE_AVAILABLE:
|
||||
raise Exception("Oracle-Treiber nicht verfügbar. Installiere cx-Oracle oder oracledb.")
|
||||
|
||||
required_fields = ['host', 'username', 'password']
|
||||
for field in required_fields:
|
||||
if not self.connection_config.get(field):
|
||||
raise Exception(f"Oracle-Konfiguration unvollständig: {field} fehlt")
|
||||
|
||||
def execute_query(self, query):
|
||||
"""Führe Oracle SQL-Query aus und gebe Ergebnisse zurück"""
|
||||
return self._execute_oracle_query(query)
|
||||
|
||||
def _execute_oracle_query(self, query):
|
||||
"""Führe Oracle Query aus"""
|
||||
if not ORACLE_AVAILABLE:
|
||||
raise Exception("Oracle-Treiber nicht verfügbar")
|
||||
|
||||
# Erstelle Oracle-Verbindung
|
||||
config = self.connection_config
|
||||
dsn = f"{config['host']}:{config.get('port', 1521)}/{config.get('service_name', 'ORCL')}"
|
||||
|
||||
try:
|
||||
# Verwende den neueren oracledb-Treiber wenn verfügbar, sonst cx_Oracle
|
||||
try:
|
||||
import oracledb
|
||||
conn = oracledb.connect(
|
||||
user=config['username'],
|
||||
password=config['password'],
|
||||
dsn=dsn
|
||||
)
|
||||
except ImportError:
|
||||
import cx_Oracle
|
||||
conn = cx_Oracle.connect(
|
||||
user=config['username'],
|
||||
password=config['password'],
|
||||
dsn=dsn
|
||||
)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# Entferne Semikolon am Ende (Oracle mag das nicht bei einzelnen Statements)
|
||||
cleaned_query = query.strip()
|
||||
if cleaned_query.endswith(';'):
|
||||
cleaned_query = cleaned_query[:-1]
|
||||
|
||||
cursor.execute(cleaned_query)
|
||||
|
||||
# Wenn es eine SELECT-Query ist, hole Ergebnisse
|
||||
if query.strip().lower().startswith('select'):
|
||||
columns = [desc[0] for desc in cursor.description]
|
||||
data = cursor.fetchall()
|
||||
|
||||
# Konvertiere Oracle-spezifische Datentypen
|
||||
processed_data = []
|
||||
for row in data:
|
||||
processed_row = []
|
||||
for value in row:
|
||||
# Konvertiere LOB, CLOB, BLOB zu String
|
||||
if hasattr(value, 'read'):
|
||||
processed_row.append(value.read())
|
||||
# Konvertiere Oracle NUMBER zu Python-Typen
|
||||
elif str(type(value)).find('NUMBER') != -1:
|
||||
processed_row.append(float(value) if '.' in str(value) else int(value))
|
||||
else:
|
||||
processed_row.append(value)
|
||||
processed_data.append(processed_row)
|
||||
|
||||
return {
|
||||
'columns': columns,
|
||||
'data': processed_data,
|
||||
'row_count': len(processed_data)
|
||||
}
|
||||
else:
|
||||
# Für INSERT, UPDATE, DELETE etc.
|
||||
conn.commit()
|
||||
return {
|
||||
'message': f'Query erfolgreich ausgeführt. {cursor.rowcount} Zeilen betroffen.',
|
||||
'affected_rows': cursor.rowcount
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
raise e
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Oracle-Datenbankfehler: {str(e)}")
|
||||
finally:
|
||||
if 'conn' in locals():
|
||||
conn.close()
|
||||
|
||||
def get_tables(self):
|
||||
"""Hole alle Oracle Tabellennamen"""
|
||||
return self._get_oracle_tables()
|
||||
|
||||
def _get_oracle_tables(self):
|
||||
"""Hole Oracle Tabellennamen"""
|
||||
if not ORACLE_AVAILABLE:
|
||||
raise Exception("Oracle-Treiber nicht verfügbar")
|
||||
|
||||
config = self.connection_config
|
||||
dsn = f"{config['host']}:{config.get('port', 1521)}/{config.get('service_name', 'ORCL')}"
|
||||
|
||||
try:
|
||||
try:
|
||||
import oracledb
|
||||
conn = oracledb.connect(
|
||||
user=config['username'],
|
||||
password=config['password'],
|
||||
dsn=dsn
|
||||
)
|
||||
except ImportError:
|
||||
import cx_Oracle
|
||||
conn = cx_Oracle.connect(
|
||||
user=config['username'],
|
||||
password=config['password'],
|
||||
dsn=dsn
|
||||
)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Hole alle Tabellen für den aktuellen Benutzer
|
||||
cursor.execute("""
|
||||
SELECT table_name
|
||||
FROM user_tables
|
||||
ORDER BY table_name
|
||||
""")
|
||||
|
||||
tables = [row[0] for row in cursor.fetchall()]
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return tables
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Fehler beim Laden der Oracle-Tabellen: {str(e)}")
|
||||
|
||||
def get_table_schema(self, table_name):
|
||||
"""Hole Oracle Tabellenschema"""
|
||||
return self._get_oracle_table_schema(table_name)
|
||||
|
||||
def _get_oracle_table_schema(self, table_name):
|
||||
"""Hole Oracle Tabellenschema"""
|
||||
if not ORACLE_AVAILABLE:
|
||||
raise Exception("Oracle-Treiber nicht verfügbar")
|
||||
|
||||
config = self.connection_config
|
||||
dsn = f"{config['host']}:{config.get('port', 1521)}/{config.get('service_name', 'ORCL')}"
|
||||
|
||||
try:
|
||||
try:
|
||||
import oracledb
|
||||
conn = oracledb.connect(
|
||||
user=config['username'],
|
||||
password=config['password'],
|
||||
dsn=dsn
|
||||
)
|
||||
except ImportError:
|
||||
import cx_Oracle
|
||||
conn = cx_Oracle.connect(
|
||||
user=config['username'],
|
||||
password=config['password'],
|
||||
dsn=dsn
|
||||
)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Hole Spalten-Informationen
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
c.column_name,
|
||||
c.data_type,
|
||||
c.data_length,
|
||||
c.data_precision,
|
||||
c.data_scale,
|
||||
c.nullable,
|
||||
c.data_default,
|
||||
CASE WHEN p.column_name IS NOT NULL THEN 'Y' ELSE 'N' END as primary_key
|
||||
FROM user_tab_columns c
|
||||
LEFT JOIN (
|
||||
SELECT acc.column_name, acc.table_name
|
||||
FROM user_constraints ac, user_cons_columns acc
|
||||
WHERE ac.constraint_name = acc.constraint_name
|
||||
AND ac.constraint_type = 'P'
|
||||
AND ac.table_name = :table_name
|
||||
) p ON c.column_name = p.column_name AND c.table_name = p.table_name
|
||||
WHERE c.table_name = :table_name
|
||||
ORDER BY c.column_id
|
||||
""", {'table_name': table_name.upper()})
|
||||
|
||||
columns = []
|
||||
for row in cursor.fetchall():
|
||||
data_type = row[1]
|
||||
if row[2]: # data_length
|
||||
if row[3]: # data_precision
|
||||
data_type += f"({row[3]}"
|
||||
if row[4]: # data_scale
|
||||
data_type += f",{row[4]}"
|
||||
data_type += ")"
|
||||
elif row[1] in ('VARCHAR2', 'CHAR', 'NVARCHAR2', 'NCHAR'):
|
||||
data_type += f"({row[2]})"
|
||||
|
||||
columns.append({
|
||||
'name': row[0],
|
||||
'type': data_type,
|
||||
'not_null': row[5] == 'N',
|
||||
'default_value': row[6],
|
||||
'primary_key': row[7] == 'Y'
|
||||
})
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return columns
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Fehler beim Laden des Oracle-Tabellenschemas: {str(e)}")
|
||||
Reference in New Issue
Block a user