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)}")