Merge branch 'master' into main

This commit is contained in:
cecilkorik 2025-03-14 20:09:22 -04:00
commit 11d1609d4a

136
sql.py
View file

@ -7,18 +7,40 @@ import readline
import traceback import traceback
def softpad(s, l, padchar=" "):
def softpad(s, l, padchar = " "):
padding = padchar * l padding = padchar * l
if len(s) >= l: if len(s) >= l:
return s + padchar return s + padchar
return (s + padding)[:l] return (s + padding)[:l]
def pad(s, l, padchar = " "):
def pad(s, l, padchar=" "):
padding = padchar * l padding = padchar * l
return (s + padding)[:l] return (s + padding)[:l]
rowbuffer = None rowbuffer = None
def execute_cmdline_query(v):
global rowbuffer
rowbuffer = None
try:
v = v.rstrip(';')
cur.execute(v)
print_row()
except:
try:
c2 = db.cursor()
c2.execute(
"SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE 1 IS NULL")
except:
print("Database connection lost!")
sys.exit(1)
traceback.print_exc()
sys.stdout.write('\n')
def print_row(): def print_row():
global rowbuffer, cur, db global rowbuffer, cur, db
if not cur or not cur.description: if not cur or not cur.description:
@ -84,20 +106,24 @@ opts = {
'hide_null_tablespace': '1', 'hide_null_tablespace': '1',
'hide_tablespaces': 'SYSTEM;SYSAUX;SDE;SPATIAL_DATA' 'hide_tablespaces': 'SYSTEM;SYSAUX;SDE;SPATIAL_DATA'
} }
connstr = "" connstr = ""
if len(sys.argv) < 2: if os.path.exists('settings.ini'):
if os.path.exists('settings.ini'):
try: try:
from cecil.core import inifile from cecil.core import inifile
config = inifile.inifile('settings.ini') config = inifile.inifile('settings.ini')
connstr = config['settings']['db'] connstr = config['settings']['db']
except: except None:
pass pass
cmdline_query = None
if not connstr:
if len(sys.argv) < 2:
if not connstr: if not connstr:
connstr = input('Connect string: ') connstr = input('Connect string: ')
else: else:
connstr = sys.argv[1] connstr = sys.argv[-1]
elif len(sys.argv) > 1:
cmdline_query = sys.argv[-1]
e = sqlalchemy.create_engine(connstr) e = sqlalchemy.create_engine(connstr)
pool = e.connect() pool = e.connect()
@ -105,6 +131,11 @@ db = pool.connection
cur = db.cursor() cur = db.cursor()
c2 = db.cursor() c2 = db.cursor()
if cmdline_query != None:
execute_cmdline_query(cmdline_query)
db.commit()
sys.exit(0)
do_quit = False do_quit = False
while True: while True:
try: try:
@ -123,18 +154,82 @@ while True:
db.commit() db.commit()
elif vl == 'rollback': elif vl == 'rollback':
db.rollback() db.rollback()
elif vl[:4] == 'copy' or vl[:5] == 'copyi':
vs = v.split(' ')
try:
configsrc = inifile.inifile(vs[1])
connstrsrc = configsrc['settings']['db']
esrc = sqlalchemy.create_engine(connstrsrc)
poolsrc = e.connect()
dbsrc = pool.connection
cursrc = db.cursor()
c2 = db.cursor()
#c2.execute("select * from %s where 1 is null" % (vs[2],))
cursrc.execute("select * from %s" % (vs[2],))
colnames = []
dstart = 1
if vs[0] == "copyi":
dstart = 0
for coldata in cursrc.description[dstart:]:
colnames.append(coldata[0])
rowload = 0
rowerror = 0
for r in cursrc:
try:
colnamesql = ", ".join(colnames)
colmarks = ", ".join("%s" for cn in colnames)
srcq = "insert into %s (%s) values (%s)" % (vs[2], colnamesql, colmarks)
print(srcq)
print(r[0])
print(r[1])
print(r[2])
print(len(r))
c2.execute(srcq, tuple(r[dstart:]))
except:
traceback.print_exc()
rowerror += 1
print(f"Rows loaded {rowload}, errors {rowerror}")
except:
traceback.print_exc()
elif vl == 'tables': elif vl == 'tables':
rowbuffer = None rowbuffer = None
cur.execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES") cur.execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES")
print_row() print_row()
elif vl[:7] == 'tables ':
v2 = v[7:]
rowbuffer = None
cur.execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE %s" % (v2,))
print_row()
elif vl[:5] == 'cols ': elif vl[:5] == 'cols ':
rowbuffer = None rowbuffer = None
vs = v.split(' ') vs = v.split(' ')
c2 = db.cursor() c2 = db.cursor()
try: try:
c2.execute("select * from %s where 1 is null" % (vs[1],)) c2.execute("select * from %s where 1 is null" % (vs[1],))
for coldata in c2.description: for coldata in c2.description:
print("%s%s" % (softpad(coldata[0], 40), coldata[1])) typedata = coldata[1]
try:
import pytds.tds_base
tdlist = []
for x in dir(pytds.tds_base):
if getattr(pytds.tds_base, x) == typedata:
tdlist.append(x)
if tdlist:
tdlist2 = [x.replace("NTYPE", "").replace(
"TYPE", "") for x in tdlist if "TYPE" in x]
if tdlist2:
tdlist = tdlist2
if tdlist:
tdlist.sort()
tdlist.sort(key=len)
typedata = " ".join(tdlist)
except:
pass
print("%s%s" % (softpad(coldata[0], 40), typedata))
except: except:
traceback.print_exc() traceback.print_exc()
sys.stdout.write('\n') sys.stdout.write('\n')
@ -153,21 +248,14 @@ commands:
cols <table> lists columns of table cols <table> lists columns of table
commit commits any pending updates or inserts commit commits any pending updates or inserts
rollback aborts and pending updates or inserts rollback aborts and pending updates or inserts
set <key>=<val> sets internal options, like "set page=40" to page at 40 rows
help displays this help help displays this help
copy <path> <tbl> reads the config from <path> connects to that database and copies the contents of <tbl>
quit exits sql.py quit exits sql.py
<empty line> next page if there are (MORE) pages, just hit "ENTER"
<anything else> executes SQL query on the server
""") """)
else: else:
rowbuffer = None execute_cmdline_query(v)
try:
v = v.rstrip(';')
cur.execute(v)
print_row()
except:
try:
c2 = db.cursor()
c2.execute("SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE 1 IS NULL")
except:
print("Database connection lost!")
sys.exit(1)
sys.stdout.write(str(sys.exc_info))