iris-vector-rag 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. adapters/rag_templates_bridge.py +578 -0
  2. common/__init__.py +1 -0
  3. common/batch_utils.py +294 -0
  4. common/config.py +58 -0
  5. common/connection_manager.py +242 -0
  6. common/connection_pool.py +445 -0
  7. common/database.py +141 -0
  8. common/database_schema_manager.py +289 -0
  9. common/db_init_with_indexes.py +181 -0
  10. common/db_vector_utils.py +181 -0
  11. common/environment_manager.py +220 -0
  12. common/huggingface_utils.py +206 -0
  13. common/iris_client.py +92 -0
  14. common/iris_connection_manager.py +411 -0
  15. common/iris_connection_pool.py +360 -0
  16. common/iris_connector.py +71 -0
  17. common/iris_dbapi_connector.py +323 -0
  18. common/iris_index_utils.py +195 -0
  19. common/iris_sql_utils.py +704 -0
  20. common/iris_stream_reader.py +166 -0
  21. common/llm_cache_config.py +308 -0
  22. common/llm_cache_iris.py +671 -0
  23. common/llm_cache_manager.py +911 -0
  24. common/utils.py +559 -0
  25. common/vector_sql_utils.py +584 -0
  26. evaluation_framework/__init__.py +66 -0
  27. evaluation_framework/biomedical_question_generator.py +826 -0
  28. evaluation_framework/comparative_analysis_system.py +1173 -0
  29. evaluation_framework/empirical_reporting.py +1298 -0
  30. evaluation_framework/evaluation_orchestrator.py +1123 -0
  31. evaluation_framework/execute_production_evaluation.py +382 -0
  32. evaluation_framework/pmc_data_pipeline.py +1332 -0
  33. evaluation_framework/production_evaluation_config.py +353 -0
  34. evaluation_framework/ragas_metrics_framework.py +1013 -0
  35. evaluation_framework/real_production_evaluation.py +544 -0
  36. evaluation_framework/run_10k_evaluation.py +175 -0
  37. evaluation_framework/simple_test.py +364 -0
  38. evaluation_framework/statistical_evaluation_methodology.py +1016 -0
  39. evaluation_framework/test_framework.py +281 -0
  40. evaluation_framework/test_iris_connectivity.py +244 -0
  41. evaluation_framework/test_small_scale_evaluation.py +432 -0
  42. evaluation_framework/true_e2e_evaluation.py +639 -0
  43. evaluation_framework/visualization_engine.py +585 -0
  44. iris_rag/__init__.py +284 -0
  45. iris_rag/config/default_config.yaml +295 -0
  46. iris_vector_rag-0.2.1.dist-info/METADATA +499 -0
  47. iris_vector_rag-0.2.1.dist-info/RECORD +50 -0
  48. iris_vector_rag-0.2.1.dist-info/WHEEL +5 -0
  49. iris_vector_rag-0.2.1.dist-info/entry_points.txt +2 -0
  50. iris_vector_rag-0.2.1.dist-info/top_level.txt +4 -0
@@ -0,0 +1,704 @@
1
+ """
2
+ IRIS SQL Utilities - Proper IRIS SQL Syntax Support
3
+
4
+ This module provides utilities for working with IRIS-specific SQL syntax,
5
+ particularly for vector operations and index creation.
6
+ """
7
+
8
+ import logging
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Import the DBAPI connector for self-managed connections
14
+ try:
15
+ from common.iris_dbapi_connector import get_iris_dbapi_connection
16
+ except ImportError:
17
+ logger.warning(
18
+ "Could not import get_iris_dbapi_connection. Self-managed connections will not be available."
19
+ )
20
+ get_iris_dbapi_connection = None
21
+
22
+
23
+ class IRISSQLUtils:
24
+ """Utilities for IRIS-specific SQL operations."""
25
+
26
+ @staticmethod
27
+ def create_vector_index(
28
+ connection: Any,
29
+ table_name: str,
30
+ column_name: str,
31
+ index_name: Optional[str] = None,
32
+ metric: str = "COSINE",
33
+ index_type: str = "HNSW",
34
+ ) -> bool:
35
+ """
36
+ Create a vector index using proper IRIS syntax.
37
+
38
+ Uses the correct IRIS HNSW index syntax from db_init_complete.sql:
39
+ CREATE INDEX IF NOT EXISTS idx_hnsw_source_embedding
40
+ ON RAG.SourceDocuments (embedding)
41
+ AS HNSW(M=16, efConstruction=200, Distance='COSINE');
42
+
43
+ Args:
44
+ connection: Database connection
45
+ table_name: Name of the table
46
+ column_name: Name of the vector column
47
+ index_name: Optional custom index name
48
+ metric: Vector similarity metric (COSINE, DOT, EUCLIDEAN)
49
+ index_type: Index type (HNSW, FLAT) - currently only HNSW supported
50
+
51
+ Returns:
52
+ True if successful, False otherwise
53
+ """
54
+ if not index_name:
55
+ # Clean table name for index naming
56
+ clean_table = table_name.replace(".", "_")
57
+ index_name = f"{clean_table}_{column_name}_vector_idx"
58
+
59
+ # IRIS vector index syntax using AS HNSW (from db_init_complete.sql)
60
+ # Note: IRIS doesn't support "IF NOT EXISTS" in CREATE INDEX statements
61
+ sql = f"""
62
+ CREATE INDEX {index_name}
63
+ ON {table_name} ({column_name})
64
+ AS HNSW(M=16, efConstruction=200, Distance='{metric}')
65
+ """
66
+
67
+ # Check if index already exists first
68
+ if IRISSQLUtils.check_index_exists(connection, index_name, table_name):
69
+ logger.debug(f"Vector index {index_name} already exists")
70
+ return True
71
+
72
+ try:
73
+ cursor = connection.cursor()
74
+ cursor.execute(sql)
75
+ connection.commit()
76
+ cursor.close()
77
+ logger.info(
78
+ f"✓ Created vector index {index_name} on {table_name}.{column_name}"
79
+ )
80
+ return True
81
+ except Exception as e:
82
+ error_msg = str(e).lower()
83
+ # Handle IRIS-specific error codes and messages
84
+ if (
85
+ "already exists" in error_msg
86
+ or "duplicate" in error_msg
87
+ or "sqlcode: <-324>" in error_msg
88
+ or "index with this name already defined" in error_msg
89
+ ):
90
+ logger.debug(f"Vector index {index_name} already exists")
91
+ return True
92
+ else:
93
+ logger.error(f"Failed to create vector index {index_name}: {e}")
94
+ return False
95
+
96
+ @staticmethod
97
+ def create_simple_index(
98
+ connection: Any,
99
+ table_name: str,
100
+ column_name: str,
101
+ index_name: Optional[str] = None,
102
+ ) -> bool:
103
+ """
104
+ Create a simple (non-vector) index using IRIS syntax.
105
+
106
+ Args:
107
+ connection: Database connection
108
+ table_name: Name of the table
109
+ column_name: Name of the column
110
+ index_name: Optional custom index name
111
+
112
+ Returns:
113
+ True if successful, False otherwise
114
+ """
115
+ if not index_name:
116
+ clean_table = table_name.replace(".", "_")
117
+ index_name = f"{clean_table}_{column_name}_idx"
118
+
119
+ # Simple index syntax for IRIS
120
+ sql = f"CREATE INDEX {index_name} ON {table_name} ({column_name})"
121
+
122
+ # Check if index already exists first
123
+ if IRISSQLUtils.check_index_exists(connection, index_name, table_name):
124
+ logger.debug(f"Index {index_name} already exists")
125
+ return True
126
+
127
+ try:
128
+ cursor = connection.cursor()
129
+ cursor.execute(sql)
130
+ connection.commit()
131
+ cursor.close()
132
+ logger.info(f"✓ Created index {index_name} on {table_name}.{column_name}")
133
+ return True
134
+ except Exception as e:
135
+ error_msg = str(e).lower()
136
+ # Handle IRIS-specific error codes and messages
137
+ if (
138
+ "already exists" in error_msg
139
+ or "duplicate" in error_msg
140
+ or "sqlcode: <-324>" in error_msg
141
+ or "index with this name already defined" in error_msg
142
+ ):
143
+ logger.debug(f"Index {index_name} already exists")
144
+ return True
145
+ else:
146
+ logger.error(f"Failed to create index {index_name}: {e}")
147
+ return False
148
+
149
+ @staticmethod
150
+ def check_table_exists(connection: Any, table_name: str) -> bool:
151
+ """
152
+ Check if a table exists using IRIS-compatible syntax.
153
+ Uses a self-managed database connection to avoid "DataRow is inaccessible" errors.
154
+
155
+ Args:
156
+ connection: Database connection (kept for compatibility, but not used)
157
+ table_name: Name of the table (schema.table format)
158
+
159
+ Returns:
160
+ True if table exists, False otherwise
161
+ """
162
+ # Use self-managed connection to avoid interference with other operations
163
+ if get_iris_dbapi_connection is None:
164
+ logger.warning(
165
+ "Self-managed connections not available, falling back to provided connection"
166
+ )
167
+ return IRISSQLUtils._check_table_exists_with_connection(
168
+ connection, table_name
169
+ )
170
+
171
+ temp_connection = None
172
+ cursor = None
173
+ try:
174
+ temp_connection = get_iris_dbapi_connection()
175
+ if not temp_connection:
176
+ logger.error(
177
+ "Failed to obtain temporary connection for table existence check"
178
+ )
179
+ return False
180
+
181
+ # Split schema and table name
182
+ if "." in table_name:
183
+ schema, table = table_name.split(".", 1)
184
+ else:
185
+ schema = "USER" # Default schema
186
+ table = table_name
187
+
188
+ cursor = temp_connection.cursor()
189
+ # Use IRIS system tables to check existence
190
+ cursor.execute(
191
+ """
192
+ SELECT COUNT(*)
193
+ FROM INFORMATION_SCHEMA.TABLES
194
+ WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
195
+ """,
196
+ [schema, table],
197
+ )
198
+
199
+ result = cursor.fetchone()
200
+ return result[0] > 0
201
+
202
+ except Exception as e:
203
+ logger.error(f"Failed to check table existence for {table_name}: {e}")
204
+ return False
205
+ finally:
206
+ # Ensure cleanup of temporary connection and cursor
207
+ if cursor:
208
+ try:
209
+ cursor.close()
210
+ except:
211
+ pass
212
+ if temp_connection:
213
+ try:
214
+ temp_connection.close()
215
+ except:
216
+ pass
217
+
218
+ @staticmethod
219
+ def _check_table_exists_with_connection(connection: Any, table_name: str) -> bool:
220
+ """
221
+ Fallback method using provided connection for table existence check.
222
+ """
223
+ try:
224
+ # Split schema and table name
225
+ if "." in table_name:
226
+ schema, table = table_name.split(".", 1)
227
+ else:
228
+ schema = "USER" # Default schema
229
+ table = table_name
230
+
231
+ cursor = connection.cursor()
232
+ # Use IRIS system tables to check existence
233
+ cursor.execute(
234
+ """
235
+ SELECT COUNT(*)
236
+ FROM INFORMATION_SCHEMA.TABLES
237
+ WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
238
+ """,
239
+ [schema, table],
240
+ )
241
+
242
+ result = cursor.fetchone()
243
+ cursor.close()
244
+ return result[0] > 0
245
+
246
+ except Exception as e:
247
+ logger.error(f"Failed to check table existence for {table_name}: {e}")
248
+ return False
249
+
250
+ @staticmethod
251
+ def check_index_exists(
252
+ connection: Any, index_name: str, table_name: Optional[str] = None
253
+ ) -> bool:
254
+ """
255
+ Check if an index exists using IRIS-compatible syntax.
256
+ Uses a self-managed database connection to avoid "DataRow is inaccessible" errors.
257
+
258
+ Args:
259
+ connection: Database connection (kept for compatibility, but not used)
260
+ index_name: Name of the index
261
+ table_name: Optional table name to filter by
262
+
263
+ Returns:
264
+ True if index exists, False otherwise
265
+ """
266
+ # Use self-managed connection to avoid interference with other operations
267
+ if get_iris_dbapi_connection is None:
268
+ logger.warning(
269
+ "Self-managed connections not available, falling back to provided connection"
270
+ )
271
+ return IRISSQLUtils._check_index_exists_with_connection(
272
+ connection, index_name, table_name
273
+ )
274
+
275
+ temp_connection = None
276
+ cursor = None
277
+ try:
278
+ temp_connection = get_iris_dbapi_connection()
279
+ if not temp_connection:
280
+ logger.error(
281
+ "Failed to obtain temporary connection for index existence check"
282
+ )
283
+ return False
284
+
285
+ cursor = temp_connection.cursor()
286
+
287
+ # IRIS doesn't have INFORMATION_SCHEMA.STATISTICS, use system tables
288
+ if table_name:
289
+ # Split schema and table name
290
+ if "." in table_name:
291
+ schema, table = table_name.split(".", 1)
292
+ else:
293
+ schema = "USER"
294
+ table = table_name
295
+
296
+ # Check for index on specific table
297
+ cursor.execute(
298
+ """
299
+ SELECT COUNT(*)
300
+ FROM %Dictionary.IndexDefinition
301
+ WHERE parent = ? AND name = ?
302
+ """,
303
+ [f"{schema}.{table}", index_name],
304
+ )
305
+ else:
306
+ # Check for index globally
307
+ cursor.execute(
308
+ """
309
+ SELECT COUNT(*)
310
+ FROM %Dictionary.IndexDefinition
311
+ WHERE name = ?
312
+ """,
313
+ [index_name],
314
+ )
315
+
316
+ result = cursor.fetchone()
317
+ return result[0] > 0
318
+
319
+ except Exception as e:
320
+ logger.debug(f"Could not check index existence for {index_name}: {e}")
321
+ # Fallback: assume index doesn't exist
322
+ return False
323
+ finally:
324
+ # Ensure cleanup of temporary connection and cursor
325
+ if cursor:
326
+ try:
327
+ cursor.close()
328
+ except:
329
+ pass
330
+ if temp_connection:
331
+ try:
332
+ temp_connection.close()
333
+ except:
334
+ pass
335
+
336
+ @staticmethod
337
+ def _check_index_exists_with_connection(
338
+ connection: Any, index_name: str, table_name: Optional[str] = None
339
+ ) -> bool:
340
+ """
341
+ Fallback method using provided connection for index existence check.
342
+ """
343
+ try:
344
+ cursor = connection.cursor()
345
+
346
+ # IRIS doesn't have INFORMATION_SCHEMA.STATISTICS, use system tables
347
+ if table_name:
348
+ # Split schema and table name
349
+ if "." in table_name:
350
+ schema, table = table_name.split(".", 1)
351
+ else:
352
+ schema = "USER"
353
+ table = table_name
354
+
355
+ # Check for index on specific table
356
+ cursor.execute(
357
+ """
358
+ SELECT COUNT(*)
359
+ FROM %Dictionary.IndexDefinition
360
+ WHERE parent = ? AND name = ?
361
+ """,
362
+ [f"{schema}.{table}", index_name],
363
+ )
364
+ else:
365
+ # Check for index globally
366
+ cursor.execute(
367
+ """
368
+ SELECT COUNT(*)
369
+ FROM %Dictionary.IndexDefinition
370
+ WHERE name = ?
371
+ """,
372
+ [index_name],
373
+ )
374
+
375
+ result = cursor.fetchone()
376
+ cursor.close()
377
+ return result[0] > 0
378
+
379
+ except Exception as e:
380
+ logger.debug(f"Could not check index existence for {index_name}: {e}")
381
+ # Fallback: assume index doesn't exist
382
+ return False
383
+
384
+ @staticmethod
385
+ def get_table_columns(connection: Any, table_name: str) -> List[Dict[str, Any]]:
386
+ """
387
+ Get column information for a table using IRIS-compatible syntax.
388
+ Uses a self-managed database connection to avoid "DataRow is inaccessible" errors.
389
+
390
+ Args:
391
+ connection: Database connection (kept for compatibility, but not used)
392
+ table_name: Name of the table (schema.table format)
393
+
394
+ Returns:
395
+ List of dictionaries with column information
396
+ """
397
+ # Use self-managed connection to avoid interference with other operations
398
+ if get_iris_dbapi_connection is None:
399
+ logger.warning(
400
+ "Self-managed connections not available, falling back to provided connection"
401
+ )
402
+ return IRISSQLUtils._get_table_columns_with_connection(
403
+ connection, table_name
404
+ )
405
+
406
+ temp_connection = None
407
+ cursor = None
408
+ try:
409
+ temp_connection = get_iris_dbapi_connection()
410
+ if not temp_connection:
411
+ logger.error(
412
+ "Failed to obtain temporary connection for table columns check"
413
+ )
414
+ return []
415
+
416
+ # Split schema and table name
417
+ if "." in table_name:
418
+ schema, table = table_name.split(".", 1)
419
+ else:
420
+ schema = "USER"
421
+ table = table_name
422
+
423
+ cursor = temp_connection.cursor()
424
+ cursor.execute(
425
+ """
426
+ SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT
427
+ FROM INFORMATION_SCHEMA.COLUMNS
428
+ WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
429
+ ORDER BY ORDINAL_POSITION
430
+ """,
431
+ [schema, table],
432
+ )
433
+
434
+ columns = []
435
+ for row in cursor.fetchall():
436
+ columns.append(
437
+ {
438
+ "name": row[0],
439
+ "type": row[1],
440
+ "nullable": row[2],
441
+ "default": row[3],
442
+ }
443
+ )
444
+
445
+ return columns
446
+
447
+ except Exception as e:
448
+ logger.error(f"Failed to get columns for {table_name}: {e}")
449
+ return []
450
+ finally:
451
+ # Ensure cleanup of temporary connection and cursor
452
+ if cursor:
453
+ try:
454
+ cursor.close()
455
+ except:
456
+ pass
457
+ if temp_connection:
458
+ try:
459
+ temp_connection.close()
460
+ except:
461
+ pass
462
+
463
+ @staticmethod
464
+ def _get_table_columns_with_connection(
465
+ connection: Any, table_name: str
466
+ ) -> List[Dict[str, Any]]:
467
+ """
468
+ Fallback method using provided connection for table columns check.
469
+ """
470
+ try:
471
+ # Split schema and table name
472
+ if "." in table_name:
473
+ schema, table = table_name.split(".", 1)
474
+ else:
475
+ schema = "USER"
476
+ table = table_name
477
+
478
+ cursor = connection.cursor()
479
+ cursor.execute(
480
+ """
481
+ SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT
482
+ FROM INFORMATION_SCHEMA.COLUMNS
483
+ WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
484
+ ORDER BY ORDINAL_POSITION
485
+ """,
486
+ [schema, table],
487
+ )
488
+
489
+ columns = []
490
+ for row in cursor.fetchall():
491
+ columns.append(
492
+ {
493
+ "name": row[0],
494
+ "type": row[1],
495
+ "nullable": row[2],
496
+ "default": row[3],
497
+ }
498
+ )
499
+
500
+ cursor.close()
501
+ return columns
502
+
503
+ except Exception as e:
504
+ logger.error(f"Failed to get columns for {table_name}: {e}")
505
+ return []
506
+
507
+ @staticmethod
508
+ def optimize_vector_table(
509
+ connection: Any,
510
+ table_name: str,
511
+ vector_column: str = "embedding",
512
+ vector_config: dict = None,
513
+ ) -> bool:
514
+ """
515
+ Optimize a table for vector operations by creating appropriate indices.
516
+
517
+ Args:
518
+ connection: Database connection
519
+ table_name: Name of the table
520
+ vector_column: Name of the vector column
521
+ vector_config: Vector index configuration with HNSW parameters
522
+
523
+ Returns:
524
+ True if successful, False otherwise
525
+ """
526
+ try:
527
+ logger.info(f"Optimizing table {table_name} for vector operations...")
528
+
529
+ # Get vector index configuration with defaults
530
+ if vector_config is None:
531
+ vector_config = {
532
+ "type": "HNSW",
533
+ "M": 16,
534
+ "efConstruction": 200,
535
+ "Distance": "COSINE",
536
+ }
537
+
538
+ # Create vector index for similarity search with configurable parameters
539
+ vector_success = IRISSQLUtils.create_vector_index_with_config(
540
+ connection, table_name, vector_column, vector_config
541
+ )
542
+
543
+ # Create simple indices on commonly queried columns
544
+ common_columns = ["doc_id", "id", "source_doc_id"]
545
+ for col in common_columns:
546
+ # Check if column exists first
547
+ columns = IRISSQLUtils.get_table_columns(connection, table_name)
548
+ column_names = [c["name"].lower() for c in columns]
549
+
550
+ if col.lower() in column_names:
551
+ IRISSQLUtils.create_simple_index(connection, table_name, col)
552
+
553
+ return vector_success
554
+
555
+ except Exception as e:
556
+ logger.error(f"Failed to optimize table {table_name}: {e}")
557
+ return False
558
+
559
+ @staticmethod
560
+ def create_vector_index_with_config(
561
+ connection: Any,
562
+ table_name: str,
563
+ column_name: str,
564
+ vector_config: dict,
565
+ index_name: Optional[str] = None,
566
+ ) -> bool:
567
+ """
568
+ Create a vector index using configurable HNSW parameters.
569
+
570
+ Args:
571
+ connection: Database connection
572
+ table_name: Name of the table
573
+ column_name: Name of the vector column
574
+ vector_config: Vector index configuration with HNSW parameters
575
+ index_name: Optional custom index name
576
+
577
+ Returns:
578
+ True if successful, False otherwise
579
+ """
580
+ if not index_name:
581
+ # Clean table name for index naming
582
+ clean_table = table_name.replace(".", "_")
583
+ index_name = f"{clean_table}_{column_name}_vector_idx"
584
+
585
+ try:
586
+ # Build HNSW parameters string
587
+ hnsw_params = []
588
+ if "M" in vector_config:
589
+ hnsw_params.append(f"M={vector_config['M']}")
590
+ if "efConstruction" in vector_config:
591
+ hnsw_params.append(f"efConstruction={vector_config['efConstruction']}")
592
+ if "Distance" in vector_config:
593
+ hnsw_params.append(f"Distance='{vector_config['Distance']}'")
594
+
595
+ params_str = ", ".join(hnsw_params)
596
+
597
+ # Create HNSW vector index with proper parameters
598
+ # Note: IRIS doesn't support "IF NOT EXISTS" in CREATE INDEX statements
599
+ if params_str:
600
+ sql = f"""
601
+ CREATE INDEX {index_name}
602
+ ON {table_name} ({column_name})
603
+ AS HNSW({params_str})
604
+ """
605
+ else:
606
+ sql = f"""
607
+ CREATE INDEX {index_name}
608
+ ON {table_name} ({column_name})
609
+ AS HNSW(M=16, efConstruction=200, Distance='COSINE')
610
+ """
611
+
612
+ # Check if index already exists first
613
+ if IRISSQLUtils.check_index_exists(connection, index_name, table_name):
614
+ logger.debug(f"Vector index {index_name} already exists")
615
+ return True
616
+
617
+ cursor = connection.cursor()
618
+ cursor.execute(sql)
619
+ connection.commit()
620
+ cursor.close()
621
+ logger.info(
622
+ f"✓ Created vector index {index_name} on {table_name}.{column_name} with parameters: {params_str}"
623
+ )
624
+ return True
625
+
626
+ except Exception as e:
627
+ error_msg = str(e).lower()
628
+ # Handle IRIS-specific error codes and messages
629
+ if (
630
+ "already exists" in error_msg
631
+ or "duplicate" in error_msg
632
+ or "sqlcode: <-324>" in error_msg
633
+ or "index with this name already defined" in error_msg
634
+ ):
635
+ logger.debug(f"Vector index {index_name} already exists")
636
+ return True
637
+ else:
638
+ logger.error(f"Failed to create vector index {index_name}: {e}")
639
+ return False
640
+
641
+
642
+ def test_iris_sql_utils():
643
+ """Test the IRIS SQL utilities with self-managed connections."""
644
+ print("=== Testing IRIS SQL Utilities ===")
645
+
646
+ try:
647
+ # Test with self-managed connections (pass None as connection since functions will create their own)
648
+ utils = IRISSQLUtils()
649
+
650
+ # Test table existence check
651
+ exists = utils.check_table_exists(None, "RAG.SourceDocuments")
652
+ print(f"✓ Table existence check: {exists}")
653
+
654
+ # Test column information
655
+ columns = utils.get_table_columns(None, "RAG.SourceDocuments")
656
+ print(f"✓ Found {len(columns)} columns")
657
+
658
+ # Test index existence check
659
+ index_exists = utils.check_index_exists(
660
+ None, "RAG_SourceDocuments_embedding_vector_idx", "RAG.SourceDocuments"
661
+ )
662
+ print(f"✓ Index existence check: {index_exists}")
663
+
664
+ # For index creation, we still need a connection since it performs DDL operations
665
+ if get_iris_dbapi_connection:
666
+ connection = get_iris_dbapi_connection()
667
+ if connection:
668
+ # Test vector index creation (this should work with proper syntax)
669
+ print("Testing vector index creation...")
670
+ success = utils.create_vector_index(
671
+ connection,
672
+ "RAG.SourceDocuments",
673
+ "embedding",
674
+ "test_vector_idx",
675
+ "COSINE",
676
+ "HNSW",
677
+ )
678
+ print(f"✓ Vector index creation: {success}")
679
+
680
+ # Clean up test index
681
+ if success:
682
+ try:
683
+ cursor = connection.cursor()
684
+ cursor.execute("DROP INDEX test_vector_idx")
685
+ cursor.close()
686
+ print("✓ Test index cleaned up")
687
+ except:
688
+ pass
689
+
690
+ connection.close()
691
+ else:
692
+ print("⚠️ Could not get database connection for index creation test")
693
+ else:
694
+ print("⚠️ Self-managed connections not available for index creation test")
695
+
696
+ return True
697
+
698
+ except Exception as e:
699
+ print(f"❌ Test failed: {e}")
700
+ return False
701
+
702
+
703
+ if __name__ == "__main__":
704
+ test_iris_sql_utils()