notebookVb

This commit is contained in:
administrator
2026-05-24 06:55:47 +02:00
parent c0aa4fb684
commit d62b1a801c
12 changed files with 655 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
import psycopg2
conn = psycopg2.connect(host="192.168.1.76", port=5432, user="vladimir.buzalka",
password="Vlado7309208104++", database="fotky_buzalkovi")
conn.autocommit = True
cur = conn.cursor()
cur.execute("TRUNCATE TABLE zdrojove_soubory, zaloha_obrazku RESTART IDENTITY CASCADE")
print("Tabulky vyprazdneny.")
cur.execute("SELECT COUNT(*) FROM zaloha_obrazku")
print(f"zaloha_obrazku: {cur.fetchone()[0]} radku")
cur.execute("SELECT COUNT(*) FROM zdrojove_soubory")
print(f"zdrojove_soubory: {cur.fetchone()[0]} radku")
conn.close()
+284
View File
@@ -0,0 +1,284 @@
"""
collect_pictures.py
-------------------
Prochází všechny shares pod /mnt/user/ (kromě ZalohaVsechObrazku),
najde JPG/JPEG soubory, zkopíruje je (deduplikace BLAKE3) do
/mnt/user/ZalohaVsechObrazku/ a zapíše záznamy do PostgreSQL.
Tabulky:
zaloha_obrazku jedna fyzická záloha na unikátní BLAKE3 hash
zdrojove_soubory všechny nalezené zdrojové soubory (i duplikáty)
Bezpečné pro opakované spuštění (pokračuje tam, kde skončilo).
"""
import os
import sys
import shutil
import socket
import logging
from pathlib import Path
from datetime import datetime
import blake3
import psycopg2
from psycopg2.extras import execute_values
# ── Konfigurace ──────────────────────────────────────────────────────────────
DB_CONFIG = {
"host": "192.168.1.76",
"port": 5432,
"user": "vladimir.buzalka",
"password": "Vlado7309208104++",
"database": "fotky_buzalkovi",
}
SOURCE_BASE = Path("/mnt/user")
JPEG_EXTENSIONS = {".jpg", ".jpeg"}
# Cílová zálohovací složka podle hostname — vždy fyzicky na Tower1
# Klíč = socket.gethostname(), hodnota = lokální cesta k záloze
ZALOHA_DIR_MAP = {
"Tower1": Path("/mnt/user/ZalohaVsechObrazku"), # Tower1: lokální share
"tower": Path("/mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku"), # tower: NFS mount na Tower1
}
ZALOHA_DIR_DEFAULT = Path("/mnt/remotes/TOWER1.LAN_ZalohaVsechObrazku")
# Adresáře které se NIKDY nepoužijí jako zdroj (porovnává se jméno složky, kdekoliv ve stromě)
EXCLUDED_DIR_NAMES = {
"ZalohaVsechObrazku",
"ZalohaVšechObrázků",
"zalohavsechobrazku", # lowercase varianta pro jistotu
}
LOG_FILE = Path(__file__).parent / "collect_pictures.log"
# ── Logging ───────────────────────────────────────────────────────────────────
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)-7s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler(LOG_FILE, encoding="utf-8"),
],
)
log = logging.getLogger(__name__)
# ── SQL ───────────────────────────────────────────────────────────────────────
SQL_CREATE_TABLES = """
CREATE TABLE IF NOT EXISTS zaloha_obrazku (
id SERIAL PRIMARY KEY,
blake3_hash VARCHAR(64) UNIQUE NOT NULL,
cesta_zalohy TEXT NOT NULL,
nazev_souboru VARCHAR(512) NOT NULL,
velikost BIGINT,
datum_kopirovani TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS zdrojove_soubory (
id SERIAL PRIMARY KEY,
hostname VARCHAR(255) NOT NULL,
cesta_zdroje TEXT NOT NULL,
nazev_souboru VARCHAR(512) NOT NULL,
velikost BIGINT,
datum_nalezeni TIMESTAMP DEFAULT NOW(),
blake3_hash VARCHAR(64) NOT NULL,
zaloha_id INTEGER REFERENCES zaloha_obrazku(id),
UNIQUE (hostname, cesta_zdroje)
);
CREATE INDEX IF NOT EXISTS idx_zaloha_hash ON zaloha_obrazku (blake3_hash);
CREATE INDEX IF NOT EXISTS idx_zdroj_hash ON zdrojove_soubory (blake3_hash);
CREATE INDEX IF NOT EXISTS idx_zdroj_zaloha ON zdrojove_soubory (zaloha_id);
CREATE INDEX IF NOT EXISTS idx_zdroj_host ON zdrojove_soubory (hostname);
"""
SQL_HASH_EXISTS = "SELECT id, cesta_zalohy FROM zaloha_obrazku WHERE blake3_hash = %s"
SQL_SOURCE_EXISTS = "SELECT id FROM zdrojove_soubory WHERE hostname = %s AND cesta_zdroje = %s"
SQL_INSERT_ZALOHA = """
INSERT INTO zaloha_obrazku (blake3_hash, cesta_zalohy, nazev_souboru, velikost)
VALUES (%s, %s, %s, %s)
RETURNING id
"""
SQL_INSERT_ZDROJ = """
INSERT INTO zdrojove_soubory (hostname, cesta_zdroje, nazev_souboru, velikost, blake3_hash, zaloha_id)
VALUES (%s, %s, %s, %s, %s, %s)
ON CONFLICT (hostname, cesta_zdroje) DO NOTHING
"""
# ── Pomocné funkce ────────────────────────────────────────────────────────────
def compute_blake3(path: Path, chunk: int = 1 << 20) -> str:
h = blake3.blake3()
with open(path, "rb") as f:
while data := f.read(chunk):
h.update(data)
return h.hexdigest()
def dest_path_for(source: Path, hostname: str) -> Path:
"""
Záloha vždy na TOWER1 pod /mnt/user/ZalohaVsechObrazku/{hostname}/...
Příklad:
tower /mnt/user/Foto/2023/img.jpg → /mnt/user/ZalohaVsechObrazku/tower/Foto/2023/img.jpg
tower1 /mnt/user/Foto/2023/img.jpg → /mnt/user/ZalohaVsechObrazku/tower1/Foto/2023/img.jpg
"""
try:
relative = source.relative_to(SOURCE_BASE)
except ValueError:
relative = Path(source.name)
return ZALOHA_DIR / hostname / relative
def copy_to_backup(source: Path, dest: Path) -> None:
dest.parent.mkdir(parents=True, exist_ok=True)
if dest.exists():
# Soubor na cílovém místě už je — nepřepisujeme, záloha platí
return
shutil.copy2(source, dest)
def is_excluded_dir(name: str) -> bool:
"""Vrátí True pokud jméno adresáře patří do seznamu vyloučených (case-insensitive)."""
return name.lower() in {n.lower() for n in EXCLUDED_DIR_NAMES}
def iter_jpeg_files(base: Path):
"""Generátor: vrací Path na každý JPG/JPEG v base (rekurzivně).
Přeskočí ZALOHA_DIR a jakýkoliv adresář jehož jméno je v EXCLUDED_DIR_NAMES.
"""
for root, dirs, files in os.walk(base, followlinks=False):
root_path = Path(root)
# Neprocházet zálohovací složku (podle plné cesty)
if ZALOHA_DIR in (root_path, *root_path.parents) or root_path == ZALOHA_DIR:
dirs.clear()
continue
# Odfiltrovat vyloučené adresáře ze subadresářů (podle jména, kdekoliv ve stromě)
dirs[:] = [
d for d in dirs
if root_path / d != ZALOHA_DIR and not is_excluded_dir(d)
]
for fname in files:
if Path(fname).suffix.lower() in JPEG_EXTENSIONS:
yield root_path / fname
# ── Hlavní logika ─────────────────────────────────────────────────────────────
def process(conn, hostname):
cur = conn.cursor()
log.info(f"Hostname zdroje: {hostname}")
stats = {"nalezeno": 0, "kopirovano": 0, "duplicit": 0, "chyb": 0, "preskoceno": 0}
for source in iter_jpeg_files(SOURCE_BASE):
stats["nalezeno"] += 1
src_str = str(source)
# Přeskočit zdroje, které už jsou v DB zpracovány (pro tento hostname)
cur.execute(SQL_SOURCE_EXISTS, (hostname, src_str))
if cur.fetchone():
stats["preskoceno"] += 1
if stats["preskoceno"] % 500 == 0:
log.info(f"Přeskočeno (již v DB): {stats['preskoceno']}")
continue
try:
velikost = source.stat().st_size
hash_val = compute_blake3(source)
except (OSError, PermissionError) as e:
log.warning(f"CHYBA čtení: {source}{e}")
stats["chyb"] += 1
continue
# Existuje už záloha s tímto hashem?
cur.execute(SQL_HASH_EXISTS, (hash_val,))
row = cur.fetchone()
if row:
# Duplikát — jen zapíšeme zdroj, nekopírujeme
zaloha_id = row[0]
cur.execute(SQL_INSERT_ZDROJ, (hostname, src_str, source.name, velikost, hash_val, zaloha_id))
conn.commit()
stats["duplicit"] += 1
log.debug(f"DUPLIKÁT {source.name} (zaloha_id={zaloha_id})")
else:
# Nový unikátní soubor — zkopírovat a zapsat
dest = dest_path_for(source, hostname)
try:
copy_to_backup(source, dest)
except (OSError, shutil.Error) as e:
log.warning(f"CHYBA kopírování: {source}{e}")
stats["chyb"] += 1
continue
cur.execute(SQL_INSERT_ZALOHA, (hash_val, str(dest), source.name, velikost))
zaloha_id = cur.fetchone()[0]
cur.execute(SQL_INSERT_ZDROJ, (hostname, src_str, source.name, velikost, hash_val, zaloha_id))
conn.commit()
stats["kopirovano"] += 1
log.info(f"ZKOPÍROVÁNO [{stats['kopirovano']:>6}] {source}")
if stats["nalezeno"] % 1000 == 0:
log.info(
f"Průběh: nalezeno={stats['nalezeno']} "
f"nových={stats['kopirovano']} duplikátů={stats['duplicit']} "
f"chyb={stats['chyb']} přeskočeno={stats['preskoceno']}"
)
cur.close()
return stats
def main():
global ZALOHA_DIR
hostname = socket.gethostname()
ZALOHA_DIR = ZALOHA_DIR_MAP.get(hostname, ZALOHA_DIR_DEFAULT)
log.info("=" * 60)
log.info(f"Spuštění: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
log.info(f"Hostname: {hostname}")
log.info(f"Zdroj: {SOURCE_BASE}")
log.info(f"Záloha: {ZALOHA_DIR}/{hostname}/")
try:
conn = psycopg2.connect(**DB_CONFIG)
conn.autocommit = False
log.info("PostgreSQL: připojeno")
except Exception as e:
log.error(f"Nelze se připojit k DB: {e}")
sys.exit(1)
# Vytvoř tabulky pokud neexistují
with conn.cursor() as cur:
cur.execute(SQL_CREATE_TABLES)
conn.commit()
log.info("Tabulky: OK")
try:
stats = process(conn, hostname)
except KeyboardInterrupt:
log.warning("Přerušeno uživatelem (Ctrl+C) — dosavadní záznamy jsou uloženy.")
conn.rollback()
except Exception as e:
log.error(f"Neočekávaná chyba: {e}", exc_info=True)
conn.rollback()
finally:
conn.close()
log.info("-" * 60)
log.info(f"Nalezeno JPG/JPEG: {stats['nalezeno']}")
log.info(f"Zkopírováno nových: {stats['kopirovano']}")
log.info(f"Duplikátů (hash): {stats['duplicit']}")
log.info(f"Přeskočeno (v DB): {stats['preskoceno']}")
log.info(f"Chyb: {stats['chyb']}")
log.info("Hotovo.")
if __name__ == "__main__":
main()
+44
View File
@@ -0,0 +1,44 @@
import psycopg2
DB_CONFIG = {
"host": "192.168.1.76",
"port": 5432,
"user": "vladimir.buzalka",
"password": "Vlado7309208104++",
"database": "fotky_buzalkovi",
}
SQL = """
CREATE TABLE IF NOT EXISTS zaloha_obrazku (
id SERIAL PRIMARY KEY,
blake3_hash VARCHAR(64) UNIQUE NOT NULL,
cesta_zalohy TEXT NOT NULL,
nazev_souboru VARCHAR(512) NOT NULL,
velikost BIGINT,
datum_kopirovani TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS zdrojove_soubory (
id SERIAL PRIMARY KEY,
hostname VARCHAR(255) NOT NULL,
cesta_zdroje TEXT NOT NULL,
nazev_souboru VARCHAR(512) NOT NULL,
velikost BIGINT,
datum_nalezeni TIMESTAMP DEFAULT NOW(),
blake3_hash VARCHAR(64) NOT NULL,
zaloha_id INTEGER REFERENCES zaloha_obrazku(id),
UNIQUE (hostname, cesta_zdroje)
);
CREATE INDEX IF NOT EXISTS idx_zaloha_hash ON zaloha_obrazku (blake3_hash);
CREATE INDEX IF NOT EXISTS idx_zdroj_hash ON zdrojove_soubory (blake3_hash);
CREATE INDEX IF NOT EXISTS idx_zdroj_zaloha ON zdrojove_soubory (zaloha_id);
CREATE INDEX IF NOT EXISTS idx_zdroj_host ON zdrojove_soubory (hostname);
"""
conn = psycopg2.connect(**DB_CONFIG)
conn.autocommit = True
with conn.cursor() as cur:
cur.execute(SQL)
conn.close()
print("Tabulky vytvoreny.")
+17
View File
@@ -0,0 +1,17 @@
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("192.168.1.76", username="root", password="7309208104",
look_for_keys=False, allow_agent=False)
def run(cmd):
_, stdout, stderr = client.exec_command(cmd)
out = stdout.read().decode().strip()
if out: print(out)
run("mount | grep -i zaloha")
run("ls /mnt/remotes/ 2>/dev/null | grep -i zaloha")
run("ls /mnt/user/ 2>/dev/null | grep -i zaloha")
client.close()
+32
View File
@@ -0,0 +1,32 @@
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("192.168.1.50", username="root", password="Vlado7309208104++",
look_for_keys=False, allow_agent=False)
def run(cmd):
_, stdout, stderr = client.exec_command(cmd)
out = stdout.read().decode().strip()
err = stderr.read().decode().strip()
if out: print(out)
if err: print(f"[err] {err}")
print("--- Hostname ---")
run("hostname")
print("\n--- Python ---")
run("python3 --version")
run("pip3 --version")
print("\n--- Balicky (blake3, psycopg2) ---")
run("pip3 list 2>/dev/null | grep -iE 'blake3|psycopg2'")
print("\n--- ZalohaVsechObrazku ---")
run("ls /mnt/user/ | grep -i zaloha")
run("ls /mnt/remotes/ 2>/dev/null | grep -i zaloha")
print("\n--- User Scripts ---")
run("ls /boot/config/plugins/user.scripts/scripts/ 2>/dev/null | head -5")
client.close()
+49
View File
@@ -0,0 +1,49 @@
import paramiko
import stat
HOST = "192.168.1.76"
USER = "root"
PASSWORD = "7309208104"
SCRIPT_NAME = "CollectPictures"
REMOTE_BASE = f"/boot/config/plugins/user.scripts/scripts/{SCRIPT_NAME}"
REMOTE_PY = f"{REMOTE_BASE}/collect_pictures.py"
REMOTE_SCRIPT = f"{REMOTE_BASE}/script"
LOCAL_SCRIPT = "00 PictureCollector/collect_pictures.py"
# -u = unbuffered stdout, každý řádek se okamžitě zobrazí v konzoli Unraid
BASH_WRAPPER = """#!/bin/bash
python3 -u /boot/config/plugins/user.scripts/scripts/CollectPictures/collect_pictures.py
"""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(HOST, username=USER, password=PASSWORD, look_for_keys=False, allow_agent=False)
def run(cmd):
_, stdout, stderr = client.exec_command(cmd)
out = stdout.read().decode().strip()
err = stderr.read().decode().strip()
if out: print(out)
if err: print(f"[err] {err}")
sftp = client.open_sftp()
sftp.put(LOCAL_SCRIPT, REMOTE_PY)
sftp.chmod(REMOTE_PY, stat.S_IRUSR | stat.S_IWUSR)
print(f"Python skript: {REMOTE_PY}")
with sftp.open(REMOTE_SCRIPT, "w") as f:
f.write(BASH_WRAPPER)
sftp.chmod(REMOTE_SCRIPT, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP)
print(f"Bash wrapper: {REMOTE_SCRIPT}")
with sftp.open(f"{REMOTE_BASE}/name", "w") as f:
f.write("CollectPictures")
sftp.close()
print("\n--- Výsledek ---")
run(f"cat {REMOTE_SCRIPT}")
client.close()
print("Hotovo.")
+49
View File
@@ -0,0 +1,49 @@
import paramiko
import stat
HOST = "192.168.1.50"
USER = "root"
PASSWORD = "Vlado7309208104++"
SCRIPT_NAME = "CollectPictures"
REMOTE_BASE = f"/boot/config/plugins/user.scripts/scripts/{SCRIPT_NAME}"
REMOTE_PY = f"{REMOTE_BASE}/collect_pictures.py"
REMOTE_SCRIPT = f"{REMOTE_BASE}/script"
LOCAL_SCRIPT = "00 PictureCollector/collect_pictures.py"
BASH_WRAPPER = """#!/bin/bash
python3 -u /boot/config/plugins/user.scripts/scripts/CollectPictures/collect_pictures.py
"""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(HOST, username=USER, password=PASSWORD, look_for_keys=False, allow_agent=False)
def run(cmd):
_, stdout, stderr = client.exec_command(cmd)
out = stdout.read().decode().strip()
err = stderr.read().decode().strip()
if out: print(out)
if err: print(f"[err] {err}")
run(f"mkdir -p {REMOTE_BASE}")
sftp = client.open_sftp()
sftp.put(LOCAL_SCRIPT, REMOTE_PY)
sftp.chmod(REMOTE_PY, stat.S_IRUSR | stat.S_IWUSR)
print(f"Python skript: {REMOTE_PY}")
with sftp.open(REMOTE_SCRIPT, "w") as f:
f.write(BASH_WRAPPER)
sftp.chmod(REMOTE_SCRIPT, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP)
print(f"Bash wrapper: {REMOTE_SCRIPT}")
with sftp.open(f"{REMOTE_BASE}/name", "w") as f:
f.write("CollectPictures")
sftp.close()
print("\n--- Vysledek ---")
run(f"ls -la {REMOTE_BASE}/")
run(f"cat {REMOTE_SCRIPT}")
client.close()
print("Hotovo.")
@@ -0,0 +1,18 @@
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("192.168.1.76", username="root", password="7309208104",
look_for_keys=False, allow_agent=False)
def run(cmd):
_, stdout, stderr = client.exec_command(cmd)
out = stdout.read().decode().strip()
err = stderr.read().decode().strip()
if out: print(out)
if err: print(f"[err] {err}")
run("find /boot/config/plugins/user.scripts/scripts -maxdepth 2 -type d 2>/dev/null || echo 'NENALEZENO'")
run("ls /boot/config/plugins/user.scripts/scripts/ 2>/dev/null || echo 'prazdne nebo neexistuje'")
client.close()
+49
View File
@@ -0,0 +1,49 @@
import paramiko
import sys
HOST = "192.168.1.76"
USER = "root"
PASSWORD = "7309208104"
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(HOST, username=USER, password=PASSWORD, look_for_keys=False, allow_agent=False)
print(f"Připojeno na {HOST}")
def run(cmd, show=True):
stdin, stdout, stderr = client.exec_command(cmd, get_pty=False)
out = stdout.read().decode().strip()
err = stderr.read().decode().strip()
if show:
if out:
print(out)
if err:
print(f"[stderr] {err}", file=sys.stderr)
return out, err
# 1. Ověř Python
print("\n--- Python ---")
run("python3 --version")
run("pip3 --version || pip --version")
# 2. Co už je nainstalováno
print("\n--- Nainstalované balíčky (blake3, psycopg2) ---")
out, _ = run("pip3 list 2>/dev/null || pip list 2>/dev/null")
for line in out.splitlines():
if any(pkg in line.lower() for pkg in ("blake3", "psycopg2")):
print(f" FOUND: {line}")
# 3. Instalace chybějících
print("\n--- Instalace blake3 ---")
run("pip3 install blake3 || pip install blake3")
print("\n--- Instalace psycopg2-binary ---")
run("pip3 install psycopg2-binary || pip install psycopg2-binary")
# 4. Ověření
print("\n--- Ověření importů ---")
run("python3 -c \"import blake3; print('blake3 OK:', blake3.__version__)\"")
run("python3 -c \"import psycopg2; print('psycopg2 OK:', psycopg2.__version__)\"")
client.close()
print("\nHotovo.")
+22
View File
@@ -0,0 +1,22 @@
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("192.168.1.50", username="root", password="Vlado7309208104++",
look_for_keys=False, allow_agent=False)
def run(cmd):
_, stdout, stderr = client.exec_command(cmd)
out = stdout.read().decode().strip()
err = stderr.read().decode().strip()
if out: print(out)
if err: print(f"[err] {err}")
print("--- Instalace psycopg2-binary ---")
run("pip3 install psycopg2-binary")
print("\n--- Overeni ---")
run("python3 -c \"import psycopg2; print('psycopg2 OK:', psycopg2.__version__)\"")
run("python3 -c \"import blake3; print('blake3 OK:', blake3.__version__)\"")
client.close()
+48
View File
@@ -0,0 +1,48 @@
import psycopg2
conn = psycopg2.connect(host="192.168.1.76", port=5432, user="vladimir.buzalka",
password="Vlado7309208104++", database="fotky_buzalkovi")
cur = conn.cursor()
cur.execute("""
SELECT
COUNT(*) AS unikatnich_souboru,
SUM(velikost) AS celkova_velikost,
AVG(velikost) AS prumerna_velikost,
MIN(velikost) AS nejmensi,
MAX(velikost) AS nejvetsi
FROM zaloha_obrazku
""")
z = cur.fetchone()
cur.execute("SELECT COUNT(*), COUNT(DISTINCT hostname) FROM zdrojove_soubory")
s = cur.fetchone()
cur.execute("SELECT hostname, COUNT(*) FROM zdrojove_soubory GROUP BY hostname ORDER BY hostname")
hosts = cur.fetchall()
conn.close()
def fmt(b):
if b is None: return "N/A"
for unit in ("B", "KB", "MB", "GB", "TB"):
if b < 1024: return f"{b:.1f} {unit}"
b /= 1024
return f"{b:.1f} PB"
print("=" * 45)
print(" ZÁLOHA — statistiky")
print("=" * 45)
print(f" Unikátních souborů (záloha): {z[0]:>10,}")
print(f" Celková velikost: {fmt(z[1]):>10}")
print(f" Průměrná velikost: {fmt(z[2]):>10}")
print(f" Nejmenší soubor: {fmt(z[3]):>10}")
print(f" Největší soubor: {fmt(z[4]):>10}")
print()
print(f" Zdrojových záznamů celkem: {s[0]:>10,}")
print(f" Počet zdrojových serverů: {s[1]:>10,}")
print()
print(" Záznamy podle hostname:")
for host, count in hosts:
print(f" {host:<20} {count:>8,} souborů")
print("=" * 45)
+27
View File
@@ -0,0 +1,27 @@
import psycopg2
conn = psycopg2.connect(host="192.168.1.76", port=5432, user="vladimir.buzalka",
password="Vlado7309208104++", database="fotky_buzalkovi")
cur = conn.cursor()
cur.execute("SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name")
print("Tabulky:")
for r in cur.fetchall():
print(f" {r[0]}")
cur.execute("SELECT indexname FROM pg_indexes WHERE schemaname='public' ORDER BY indexname")
print("Indexy:")
for r in cur.fetchall():
print(f" {r[0]}")
cur.execute("""
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema='public' AND table_name='zdrojove_soubory'
ORDER BY ordinal_position
""")
print("\nSloupce zdrojove_soubory:")
for r in cur.fetchall():
print(f" {r[0]:20s} {r[1]:20s} nullable={r[2]}")
conn.close()