Skip to content

feat: support oracle oci autonomouse database. Fixes #14792 and Fixes #14628. #14804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions api/configs/middleware/vdb/oracle_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import Field, PositiveInt
from pydantic import Field
from pydantic_settings import BaseSettings


Expand All @@ -9,27 +9,38 @@ class OracleConfig(BaseSettings):
Configuration settings for Oracle database
"""

ORACLE_HOST: Optional[str] = Field(
description="Hostname or IP address of the Oracle database server (e.g., 'localhost' or 'oracle.example.com')",
ORACLE_USER: Optional[str] = Field(
description="Username for authenticating with the Oracle database",
default=None,
)

ORACLE_PORT: PositiveInt = Field(
description="Port number on which the Oracle database server is listening (default is 1521)",
default=1521,
ORACLE_PASSWORD: Optional[str] = Field(
description="Password for authenticating with the Oracle database",
default=None,
)

ORACLE_USER: Optional[str] = Field(
description="Username for authenticating with the Oracle database",
ORACLE_DSN: Optional[str] = Field(
description="Oracle database connection string. For traditional database, use format 'host:port/service_name'. "
"For autonomous database, use the service name from tnsnames.ora in the wallet",
default=None,
)

ORACLE_PASSWORD: Optional[str] = Field(
description="Password for authenticating with the Oracle database",
ORACLE_CONFIG_DIR: Optional[str] = Field(
description="Directory containing the tnsnames.ora configuration file. Only used in thin mode connection",
default=None,
)

ORACLE_DATABASE: Optional[str] = Field(
description="Name of the Oracle database or service to connect to (e.g., 'ORCL' or 'pdborcl')",
ORACLE_WALLET_LOCATION: Optional[str] = Field(
description="Oracle wallet directory path containing the wallet files for secure connection",
default=None,
)

ORACLE_WALLET_PASSWORD: Optional[str] = Field(
description="Password to decrypt the Oracle wallet, if it is encrypted",
default=None,
)

ORACLE_IS_AUTONOMOUS: bool = Field(
description="Flag indicating whether connecting to Oracle Autonomous Database",
default=False,
)
60 changes: 39 additions & 21 deletions api/core/rag/datasource/vdb/oracle/oraclevector.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,30 @@


class OracleVectorConfig(BaseModel):
host: str
port: int
user: str
password: str
database: str
dsn: str
config_dir: str | None = None
wallet_location: str | None = None
wallet_password: str | None = None
is_autonomous: bool = False

@model_validator(mode="before")
@classmethod
def validate_config(cls, values: dict) -> dict:
if not values["host"]:
raise ValueError("config ORACLE_HOST is required")
if not values["port"]:
raise ValueError("config ORACLE_PORT is required")
if not values["user"]:
raise ValueError("config ORACLE_USER is required")
if not values["password"]:
raise ValueError("config ORACLE_PASSWORD is required")
if not values["database"]:
raise ValueError("config ORACLE_DB is required")
if not values["dsn"]:
raise ValueError("config ORACLE_DSN is required")
if values.get("is_autonomous", False):
if not values.get("config_dir"):
raise ValueError("config_dir is required for autonomous database")
if not values.get("wallet_location"):
raise ValueError("wallet_location is required for autonomous database")
if not values.get("wallet_password"):
raise ValueError("wallet_password is required for autonomous database")
return values


Expand All @@ -56,7 +61,7 @@ def validate_config(cls, values: dict) -> dict:
SQL_CREATE_INDEX = """
CREATE INDEX IF NOT EXISTS idx_docs_{table_name} ON {table_name}(text)
INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS
('FILTER CTXSYS.NULL_FILTER SECTION GROUP CTXSYS.HTML_SECTION_GROUP LEXER sys.my_chinese_vgram_lexer')
('FILTER CTXSYS.NULL_FILTER SECTION GROUP CTXSYS.HTML_SECTION_GROUP LEXER multilingual_lexer')
"""


Expand Down Expand Up @@ -103,14 +108,25 @@ def output_type_handler(self, cursor, metadata):
)

def _create_connection_pool(self, config: OracleVectorConfig):
return oracledb.create_pool(
user=config.user,
password=config.password,
dsn="{}:{}/{}".format(config.host, config.port, config.database),
min=1,
max=50,
increment=1,
)
pool_params = {
"user": config.user,
"password": config.password,
"dsn": config.dsn,
"min": 1,
"max": 50,
"increment": 1,
}

if config.is_autonomous:
pool_params.update(
{
"config_dir": config.config_dir,
"wallet_location": config.wallet_location,
"wallet_password": config.wallet_password,
}
)

return oracledb.create_pool(**pool_params)

@contextmanager
def _get_cursor(self):
Expand Down Expand Up @@ -287,10 +303,12 @@ def init_vector(self, dataset: Dataset, attributes: list, embeddings: Embeddings
return OracleVector(
collection_name=collection_name,
config=OracleVectorConfig(
host=dify_config.ORACLE_HOST or "localhost",
port=dify_config.ORACLE_PORT,
user=dify_config.ORACLE_USER or "system",
password=dify_config.ORACLE_PASSWORD or "oracle",
database=dify_config.ORACLE_DATABASE or "orcl",
dsn=dify_config.ORACLE_DSN or "oracle:1521/freepdb1",
config_dir=dify_config.ORACLE_CONFIG_DIR,
wallet_location=dify_config.ORACLE_WALLET_LOCATION,
wallet_password=dify_config.ORACLE_WALLET_PASSWORD,
is_autonomous=dify_config.ORACLE_IS_AUTONOMOUS,
),
)
4 changes: 1 addition & 3 deletions api/tests/integration_tests/vdb/oracle/test_oraclevector.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ def __init__(self):
self.vector = OracleVector(
collection_name=self.collection_name,
config=OracleVectorConfig(
host="localhost",
port=1521,
user="dify",
password="dify",
database="FREEPDB1",
dsn="localhost:1521/FREEPDB1",
),
)

Expand Down
8 changes: 5 additions & 3 deletions docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,13 @@ CHROMA_AUTH_PROVIDER=chromadb.auth.token_authn.TokenAuthClientProvider
CHROMA_AUTH_CREDENTIALS=

# Oracle configuration, only available when VECTOR_STORE is `oracle`
ORACLE_HOST=oracle
ORACLE_PORT=1521
ORACLE_USER=dify
ORACLE_PASSWORD=dify
ORACLE_DATABASE=FREEPDB1
ORACLE_DSN=oracle:1521/FREEPDB1
ORACLE_CONFIG_DIR=/app/api/storage/wallet
ORACLE_WALLET_LOCATION=/app/api/storage/wallet
ORACLE_WALLET_PASSWORD=dify
ORACLE_IS_AUTONOMOUS=false

# relyt configurations, only available when VECTOR_STORE is `relyt`
RELYT_HOST=db
Expand Down
8 changes: 5 additions & 3 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,13 @@ x-shared-env: &shared-api-worker-env
CHROMA_DATABASE: ${CHROMA_DATABASE:-default_database}
CHROMA_AUTH_PROVIDER: ${CHROMA_AUTH_PROVIDER:-chromadb.auth.token_authn.TokenAuthClientProvider}
CHROMA_AUTH_CREDENTIALS: ${CHROMA_AUTH_CREDENTIALS:-}
ORACLE_HOST: ${ORACLE_HOST:-oracle}
ORACLE_PORT: ${ORACLE_PORT:-1521}
ORACLE_USER: ${ORACLE_USER:-dify}
ORACLE_PASSWORD: ${ORACLE_PASSWORD:-dify}
ORACLE_DATABASE: ${ORACLE_DATABASE:-FREEPDB1}
ORACLE_DSN: ${ORACLE_DSN:-oracle:1521/FREEPDB1}
ORACLE_CONFIG_DIR: ${ORACLE_CONFIG_DIR:-/app/api/storage/wallet}
ORACLE_WALLET_LOCATION: ${ORACLE_WALLET_LOCATION:-/app/api/storage/wallet}
ORACLE_WALLET_PASSWORD: ${ORACLE_WALLET_PASSWORD:-dify}
ORACLE_IS_AUTONOMOUS: ${ORACLE_IS_AUTONOMOUS:-false}
RELYT_HOST: ${RELYT_HOST:-db}
RELYT_PORT: ${RELYT_PORT:-5432}
RELYT_USER: ${RELYT_USER:-postgres}
Expand Down
2 changes: 1 addition & 1 deletion docker/startupscripts/init_user.script
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ create user dify identified by dify DEFAULT TABLESPACE users quota unlimited on
grant DB_DEVELOPER_ROLE to dify;

BEGIN
CTX_DDL.CREATE_PREFERENCE('my_chinese_vgram_lexer','CHINESE_VGRAM_LEXER');
CTX_DDL.CREATE_PREFERENCE('dify.multilingual_lexer','CHINESE_VGRAM_LEXER');
END;
/