postgresql.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. # -*- coding:utf-8 -*-
  2. """PG 连接工厂 + 薄查询封装(pg8000)。
  3. ds_ref(形如 postgresql/prd-hobby)→ 解析项目同级 ../datasource/{ds_ref}.ini
  4. → pg8000 活连接。ds_ref → 凭据 的解析复用 datax 的 DataSourceFactory。
  5. """
  6. import os
  7. import re
  8. from dw_base.datax.datasources.data_source_factory import DataSourceFactory
  9. from dw_base.datax.datax_constants import DS_POSTGRE_SQL_JDBC_URL
  10. # dw_base/io/db/postgresql.py → 上 4 层到项目根
  11. _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(
  12. os.path.dirname(os.path.abspath(__file__)))))
  13. def parse_jdbc_url(jdbc_url):
  14. """从 jdbc:postgresql://host:port/database 抽 (host, port, database)。"""
  15. m = re.match(r'jdbc:postgresql://([^:/]+)(?::(\d+))?/(.+)', jdbc_url)
  16. if not m:
  17. raise ValueError('无法解析 PG jdbcUrl: ' + jdbc_url)
  18. return m.group(1), int(m.group(2) or 5432), m.group(3)
  19. def _resolve_datasource(ds_ref):
  20. """ds_ref → DataSource。
  21. ds_ref 形如 'postgresql/prd-hobby',首段为 db_type(同父目录名)。
  22. datasource ini 落点:项目同级 ../datasource/{ds_ref}.ini。
  23. """
  24. ds_type = ds_ref.split('/')[0]
  25. if ds_type != 'postgresql':
  26. raise NotImplementedError('暂只支持 postgresql 数据源,收到: ' + ds_type)
  27. ds_file_path = os.path.normpath(
  28. os.path.join(_PROJECT_ROOT, '..', 'datasource', ds_ref + '.ini'))
  29. if not os.path.isfile(ds_file_path):
  30. raise FileNotFoundError('数据源 ini 不存在: ' + ds_file_path)
  31. return DataSourceFactory.get_data_source(ds_type, ds_file_path)
  32. def resolve(ds_ref):
  33. """ds_ref → {host, port, database, username, password}。"""
  34. d = _resolve_datasource(ds_ref).parse()
  35. host, port, database = parse_jdbc_url(d[DS_POSTGRE_SQL_JDBC_URL])
  36. return {
  37. 'host': host,
  38. 'port': port,
  39. 'database': database,
  40. 'username': d['username'],
  41. 'password': d['password'],
  42. }
  43. def connect(ds_ref):
  44. """ds_ref → pg8000 活连接。调用方负责 close。"""
  45. info = resolve(ds_ref)
  46. import pg8000.dbapi
  47. return pg8000.dbapi.connect(
  48. host=info['host'], port=info['port'], database=info['database'],
  49. user=info['username'], password=info['password'],
  50. )
  51. def query(conn, sql, params=None):
  52. """跑 SQL 返回 fetchall。params 为 None 时不传参(避开空参数风格差异)。"""
  53. cur = conn.cursor()
  54. try:
  55. if params is None:
  56. cur.execute(sql)
  57. else:
  58. cur.execute(sql, params)
  59. return cur.fetchall()
  60. finally:
  61. cur.close()