dbagent-cli 0.1.7__tar.gz → 0.1.8__tar.gz
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.
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/PKG-INFO +1 -1
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/__init__.py +1 -1
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/cli.py +177 -108
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/relational.py +10 -7
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/PKG-INFO +1 -1
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/pyproject.toml +1 -1
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/README.md +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/agent/generator.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/agent/pipeline.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/agent/validator.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/config.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/base.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/factory.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/mongo.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/auto_setup.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/base.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/factory.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/gemini_provider.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/groq_provider.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/mock_provider.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/ollama_provider.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/openrouter_provider.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/schema/formatter.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/schema/models.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/schema/selector.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/ui/console.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/ui/viewer.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/SOURCES.txt +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/dependency_links.txt +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/entry_points.txt +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/requires.txt +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/top_level.txt +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/setup.cfg +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/tests/test_cli.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/tests/test_connectors.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/tests/test_generator.py +0 -0
- {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/tests/test_schema.py +0 -0
|
@@ -524,130 +524,180 @@ def chat_command(
|
|
|
524
524
|
if not user_input:
|
|
525
525
|
continue
|
|
526
526
|
|
|
527
|
-
# --- REPL commands ---
|
|
528
|
-
if user_input.
|
|
529
|
-
|
|
530
|
-
|
|
527
|
+
# --- REPL commands (all start with :) ---
|
|
528
|
+
if user_input.startswith(":"):
|
|
529
|
+
cmd_parts = user_input.split(maxsplit=1)
|
|
530
|
+
cmd_name = cmd_parts[0].lower()
|
|
531
|
+
cmd_arg = cmd_parts[1].strip() if len(cmd_parts) > 1 else ""
|
|
532
|
+
|
|
533
|
+
if cmd_name in [":exit", ":quit", ":q"]:
|
|
534
|
+
console.print("[bold cyan]Goodbye![/bold cyan]")
|
|
535
|
+
break
|
|
536
|
+
|
|
537
|
+
if cmd_name in [":help", ":h", ":?"]:
|
|
538
|
+
console.print("\n[bold cyan]Interactive Chat Commands:[/bold cyan]")
|
|
539
|
+
console.print(" [bold]:tables[/bold] -> List all tables in this database")
|
|
540
|
+
console.print(" [bold]:table <name>[/bold] -> Inspect columns, PKs, types & sample data")
|
|
541
|
+
console.print(" [bold]:fk <name>[/bold] -> View mapped foreign keys & related tables")
|
|
542
|
+
console.print(" [bold]:provider <name>[/bold] -> Switch AI provider (ollama, gemini, groq, openrouter)")
|
|
543
|
+
console.print(" [bold]:model <name>[/bold] -> Switch active model name (e.g. gemini-3.6-flash)")
|
|
544
|
+
console.print(" [bold]:models[/bold] -> Show active AI provider and model status")
|
|
545
|
+
console.print(" [bold]:explain[/bold] -> Show generated SQL & query analysis for last turn")
|
|
546
|
+
console.print(" [bold]:history[/bold] -> View history of queries in this session")
|
|
547
|
+
console.print(" [bold]:auto[/bold] / [bold]:noauto[/bold] -> Toggle automatic execution of read queries")
|
|
548
|
+
console.print(" [bold]:run[/bold] -> Re-execute the last generated SQL query")
|
|
549
|
+
console.print(" [bold]:export <file>[/bold] -> Save the last generated SQL to a file")
|
|
550
|
+
console.print(" [bold]:exit[/bold] -> Exit chat session\n")
|
|
551
|
+
continue
|
|
531
552
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
553
|
+
if cmd_name in [":tables", ":schema", ":dt"]:
|
|
554
|
+
with console.status("[bold cyan]Fetching schema...[/bold cyan]"):
|
|
555
|
+
schema = connector.inspect_schema(include_samples=False, max_samples=0, include_row_counts=False)
|
|
556
|
+
SchemaViewer.display_schema_summary(schema)
|
|
557
|
+
continue
|
|
537
558
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
559
|
+
if cmd_name == ":table":
|
|
560
|
+
if not cmd_arg:
|
|
561
|
+
print_warning("Usage: :table <table_name> (e.g. :table ivis_users)")
|
|
562
|
+
continue
|
|
563
|
+
exact, fuzzy = connector.resolve_tables(cmd_arg)
|
|
564
|
+
target = exact[0] if exact else (fuzzy[0] if fuzzy else cmd_arg)
|
|
565
|
+
with console.status(f"[bold cyan]Inspecting {target}...[/bold cyan]"):
|
|
566
|
+
on_demand_schema = connector.inspect_schema(table_names=[target], include_samples=True)
|
|
567
|
+
tmodel = on_demand_schema.get_table(target)
|
|
568
|
+
if tmodel:
|
|
569
|
+
SchemaViewer.display_table_detail(tmodel)
|
|
570
|
+
else:
|
|
571
|
+
print_error(f"Table '{cmd_arg}' not found.")
|
|
572
|
+
continue
|
|
550
573
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
for
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
574
|
+
if cmd_name in [":fk", ":relations", ":mapped"]:
|
|
575
|
+
if not cmd_arg:
|
|
576
|
+
print_warning("Usage: :fk <table_name> (e.g. :fk ivis_users)")
|
|
577
|
+
continue
|
|
578
|
+
exact, fuzzy = connector.resolve_tables(cmd_arg)
|
|
579
|
+
target = exact[0] if exact else (fuzzy[0] if fuzzy else cmd_arg)
|
|
580
|
+
with console.status(f"[bold cyan]Finding relationships for {target}...[/bold cyan]"):
|
|
581
|
+
full_schema = connector.inspect_schema(include_samples=False, max_samples=0)
|
|
582
|
+
|
|
583
|
+
tmodel = full_schema.get_table(target)
|
|
584
|
+
outgoing = tmodel.foreign_keys if tmodel else []
|
|
585
|
+
incoming = []
|
|
586
|
+
for other in full_schema.tables:
|
|
587
|
+
for fk in other.foreign_keys:
|
|
588
|
+
if fk.referred_table.lower() == target.lower():
|
|
589
|
+
incoming.append((other.name, fk))
|
|
590
|
+
|
|
591
|
+
console.print(f"\n[bold cyan]Relationships mapped to table: [bold white]{target}[/bold white][/bold cyan]\n")
|
|
592
|
+
if outgoing:
|
|
593
|
+
console.print("[bold green]Outgoing (This table references):[/bold green]")
|
|
594
|
+
for fk in outgoing:
|
|
595
|
+
console.print(f" * ({', '.join(fk.constrained_columns)}) -> [bold]{fk.referred_table}[/bold]({', '.join(fk.referred_columns)})")
|
|
596
|
+
if incoming:
|
|
597
|
+
console.print("\n[bold yellow]Incoming (Other tables reference this table):[/bold yellow]")
|
|
598
|
+
for src_table, fk in incoming:
|
|
599
|
+
console.print(f" * [bold]{src_table}[/bold]({', '.join(fk.constrained_columns)}) -> ({', '.join(fk.referred_columns)})")
|
|
600
|
+
if not outgoing and not incoming:
|
|
601
|
+
console.print(f"[dim]No foreign key constraints found directly mapped to '{target}'.[/dim]")
|
|
602
|
+
console.print("")
|
|
603
|
+
continue
|
|
580
604
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
605
|
+
if cmd_name in [":provider", ":use"]:
|
|
606
|
+
if not cmd_arg:
|
|
607
|
+
curr_model = model or getattr(llm, "default_model", "default")
|
|
608
|
+
console.print(f"\n[bold cyan]Active AI Provider:[/bold cyan] [bold white]{llm.name}[/bold white] | Model: [bold green]{curr_model}[/bold green]")
|
|
609
|
+
console.print("[dim]Usage: [bold]:provider <ollama|gemini|groq|openrouter>[/bold][/dim]\n")
|
|
610
|
+
continue
|
|
611
|
+
prov_target = cmd_arg.lower()
|
|
612
|
+
if prov_target in ["ollama", "gemini", "groq", "openrouter", "mock"]:
|
|
613
|
+
llm = get_llm_provider(provider_name=prov_target, config_mgr=config_mgr)
|
|
587
614
|
model = None
|
|
588
615
|
print_success(f"Switched AI provider to [bold cyan]{llm.name}[/bold cyan]")
|
|
589
616
|
else:
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
else:
|
|
593
|
-
print_info(f"Active AI Provider: [bold cyan]{llm.name}[/bold cyan] | Model: [bold green]{model or getattr(llm, 'default_model', 'default')}[/bold green]")
|
|
594
|
-
continue
|
|
617
|
+
print_error(f"Unknown provider '{cmd_arg}'. Supported: ollama, gemini, groq, openrouter")
|
|
618
|
+
continue
|
|
595
619
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
620
|
+
if cmd_name == ":model":
|
|
621
|
+
if not cmd_arg:
|
|
622
|
+
curr_model = model or getattr(llm, "default_model", "default")
|
|
623
|
+
console.print(f"Active Model: [bold green]{curr_model}[/bold green] (Provider: {llm.name})")
|
|
624
|
+
console.print("[dim]Usage: [bold]:model <model_name>[/bold][/dim]")
|
|
625
|
+
continue
|
|
626
|
+
model = cmd_arg
|
|
627
|
+
print_success(f"Switched active model to [bold cyan]{model}[/bold cyan] (Provider: {llm.name})")
|
|
628
|
+
continue
|
|
602
629
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
console.print(f"[
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if last_result.fuzzy_tables:
|
|
610
|
-
console.print(f"[dim]Tables (fuzzy): {', '.join(last_result.fuzzy_tables)}[/dim]")
|
|
611
|
-
else:
|
|
612
|
-
print_warning("No previous query to explain.")
|
|
613
|
-
continue
|
|
630
|
+
if cmd_name in [":models", ":providers", ":ai"]:
|
|
631
|
+
curr_model = model or getattr(llm, "default_model", "default")
|
|
632
|
+
console.print(f"\n[bold cyan]Active AI Provider:[/bold cyan] [bold white]{llm.name}[/bold white]")
|
|
633
|
+
console.print(f"[bold cyan]Active Model:[/bold cyan] [bold green]{curr_model}[/bold green]")
|
|
634
|
+
console.print("[dim]Switch anytime: [bold]:provider <ollama|gemini|groq|openrouter>[/bold] or [bold]:model <name>[/bold][/dim]\n")
|
|
635
|
+
continue
|
|
614
636
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
637
|
+
if cmd_name == ":explain":
|
|
638
|
+
if last_result and last_result.sql:
|
|
639
|
+
print_code(last_result.sql, "sql", "Last Executed SQL")
|
|
640
|
+
console.print(f"[dim]Query type: {last_result.query_type} | Intent: {last_result.intent} | Retries: {last_result.retries}[/dim]")
|
|
641
|
+
if last_result.exact_tables:
|
|
642
|
+
console.print(f"[dim]Tables (exact): {', '.join(last_result.exact_tables)}[/dim]")
|
|
643
|
+
if last_result.fuzzy_tables:
|
|
644
|
+
console.print(f"[dim]Tables (fuzzy): {', '.join(last_result.fuzzy_tables)}[/dim]")
|
|
645
|
+
else:
|
|
646
|
+
print_warning("No previous query to explain.")
|
|
618
647
|
continue
|
|
619
|
-
for i, r in enumerate(query_history[-10:], 1):
|
|
620
|
-
status = "[green]OK[/green]" if r.success else "[red]FAIL[/red]"
|
|
621
|
-
sql_preview = (r.sql[:80] + "...") if len(r.sql) > 80 else r.sql
|
|
622
|
-
console.print(f" {i}. {status} [{r.query_type}] {sql_preview}")
|
|
623
|
-
continue
|
|
624
648
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
649
|
+
if cmd_name == ":history":
|
|
650
|
+
if not query_history:
|
|
651
|
+
print_warning("No query history in this session.")
|
|
652
|
+
continue
|
|
653
|
+
for i, r in enumerate(query_history[-10:], 1):
|
|
654
|
+
status = "[green]OK[/green]" if r.success else "[red]FAIL[/red]"
|
|
655
|
+
sql_preview = (r.sql[:80] + "...") if len(r.sql) > 80 else r.sql
|
|
656
|
+
console.print(f" {i}. {status} [{r.query_type}] {sql_preview}")
|
|
657
|
+
continue
|
|
629
658
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
659
|
+
if cmd_name == ":auto":
|
|
660
|
+
auto_execute = True
|
|
661
|
+
print_success("Auto-execute enabled. Read queries will run automatically.")
|
|
662
|
+
continue
|
|
634
663
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
664
|
+
if cmd_name == ":noauto":
|
|
665
|
+
auto_execute = False
|
|
666
|
+
print_info("Auto-execute disabled. All queries will show SQL only. Use :run to execute.")
|
|
667
|
+
continue
|
|
668
|
+
|
|
669
|
+
if cmd_name == ":run":
|
|
670
|
+
if not last_result or not last_result.sql:
|
|
671
|
+
print_warning("No generated SQL query to run.")
|
|
672
|
+
continue
|
|
673
|
+
if last_result.was_executed:
|
|
674
|
+
console.print("[dim]Re-executing last query...[/dim]")
|
|
675
|
+
cols, rows, err = connector.execute_query(last_result.sql, limit=100)
|
|
676
|
+
if err:
|
|
677
|
+
print_error(f"Execution error: {err}")
|
|
678
|
+
else:
|
|
679
|
+
print_results_table(cols, rows)
|
|
680
|
+
continue
|
|
681
|
+
|
|
682
|
+
if cmd_name == ":export":
|
|
683
|
+
if not cmd_arg:
|
|
684
|
+
print_warning("Usage: :export <file_path> (e.g. :export query.sql)")
|
|
685
|
+
continue
|
|
686
|
+
if not last_result or not last_result.sql:
|
|
687
|
+
print_warning("No code block to export.")
|
|
688
|
+
continue
|
|
689
|
+
p = Path(cmd_arg)
|
|
690
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
691
|
+
p.write_text(last_result.sql, encoding="utf-8")
|
|
692
|
+
print_success(f"SQL saved to {p}")
|
|
638
693
|
continue
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
console.print("[dim]Re-executing last query...[/dim]")
|
|
642
|
-
cols, rows, err = connector.execute_query(last_result.sql, limit=100)
|
|
643
|
-
if err:
|
|
644
|
-
print_error(f"Execution error: {err}")
|
|
645
|
-
else:
|
|
646
|
-
print_results_table(cols, rows)
|
|
694
|
+
|
|
695
|
+
print_warning(f"Unknown command '{user_input}'. Type [bold]:help[/bold] to see all in-chat commands.")
|
|
647
696
|
continue
|
|
648
697
|
|
|
649
|
-
if user_input.
|
|
650
|
-
|
|
698
|
+
if user_input.lower() in ["exit", "quit", "q"]:
|
|
699
|
+
console.print("[bold cyan]Goodbye![/bold cyan]")
|
|
700
|
+
break
|
|
651
701
|
if not last_result or not last_result.sql:
|
|
652
702
|
print_warning("No code block to export.")
|
|
653
703
|
continue
|
|
@@ -804,7 +854,7 @@ def models_command():
|
|
|
804
854
|
gemini = get_llm_provider("gemini")
|
|
805
855
|
gemini_status = "[green]Configured[/green]" if gemini.is_available() else "[yellow]Not Configured (Free Key: aistudio.google.com)[/yellow]"
|
|
806
856
|
console.print(f"\n2. [bold white]Google Gemini (Free Tier)[/bold white] - Status: {gemini_status}")
|
|
807
|
-
console.print(" Available Models: `gemini-
|
|
857
|
+
console.print(" Available Models: `gemini-3.6-flash`, `gemini-2.5-flash`, `gemini-2.5-pro`")
|
|
808
858
|
|
|
809
859
|
groq = get_llm_provider("groq")
|
|
810
860
|
groq_status = "[green]Configured[/green]" if groq.is_available() else "[yellow]Not Configured (Free Key: console.groq.com)[/yellow]"
|
|
@@ -944,5 +994,24 @@ def setup_command(
|
|
|
944
994
|
console.print(" * [bold]db-agent guide[/bold] -> View full command reference\n")
|
|
945
995
|
|
|
946
996
|
|
|
997
|
+
# ---- use ----
|
|
998
|
+
|
|
999
|
+
@app.command(name="use")
|
|
1000
|
+
def use_command(
|
|
1001
|
+
provider_name: str = typer.Argument(..., help="AI provider name (ollama, gemini, groq, openrouter)"),
|
|
1002
|
+
model: Optional[str] = typer.Option(None, "--model", "-m", help="Optional default model name"),
|
|
1003
|
+
):
|
|
1004
|
+
"""Switch the default AI provider (e.g. `db-agent use gemini` or `db-agent use ollama`)."""
|
|
1005
|
+
p = provider_name.lower()
|
|
1006
|
+
if p not in ["ollama", "gemini", "groq", "openrouter", "mock"]:
|
|
1007
|
+
print_error(f"Invalid provider '{provider_name}'. Supported: ollama, gemini, groq, openrouter")
|
|
1008
|
+
raise typer.Exit(1)
|
|
1009
|
+
|
|
1010
|
+
config_mgr.set_setting("default_provider", p)
|
|
1011
|
+
if model:
|
|
1012
|
+
config_mgr.set_setting(f"{p}_default_model", model)
|
|
1013
|
+
print_success(f"Default AI provider switched to [bold cyan]{p}[/bold cyan]!")
|
|
1014
|
+
|
|
1015
|
+
|
|
947
1016
|
if __name__ == "__main__":
|
|
948
1017
|
app()
|
|
@@ -447,19 +447,22 @@ class RelationalConnector(BaseConnector):
|
|
|
447
447
|
limit: int = 100,
|
|
448
448
|
) -> Tuple[List[str], List[Dict[str, Any]], Optional[str]]:
|
|
449
449
|
"""Safely execute a query with row limit."""
|
|
450
|
+
clean_q = query.strip()
|
|
450
451
|
try:
|
|
451
452
|
with self.engine.connect() as conn:
|
|
452
453
|
try:
|
|
453
|
-
|
|
454
|
+
conn = conn.execution_options(isolation_level="AUTOCOMMIT")
|
|
454
455
|
except Exception:
|
|
455
|
-
|
|
456
|
+
pass
|
|
457
|
+
|
|
458
|
+
try:
|
|
459
|
+
result = conn.exec_driver_sql(clean_q)
|
|
460
|
+
except Exception:
|
|
461
|
+
result = conn.execute(text(clean_q))
|
|
462
|
+
|
|
456
463
|
if not result.returns_rows:
|
|
457
|
-
# DML: commit and report affected rows
|
|
458
|
-
try:
|
|
459
|
-
conn.commit()
|
|
460
|
-
except Exception:
|
|
461
|
-
pass
|
|
462
464
|
return ["status"], [{"status": "Query executed successfully."}], None
|
|
465
|
+
|
|
463
466
|
columns = list(result.keys())
|
|
464
467
|
raw_rows = result.fetchmany(limit)
|
|
465
468
|
rows = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|