bugfix
This commit is contained in:
parent
0859f8162d
commit
472ce1647a
0
sqlor/__init__.py
Executable file → Normal file
0
sqlor/__init__.py
Executable file → Normal file
0
sqlor/aiopostgresqlor.py
Executable file → Normal file
0
sqlor/aiopostgresqlor.py
Executable file → Normal file
84
sqlor/aiosqliteor.py
Executable file → Normal file
84
sqlor/aiosqliteor.py
Executable file → Normal file
@ -1,7 +1,85 @@
|
|||||||
import re
|
import aiosqlite
|
||||||
from .sqlite3or import SQLite3or
|
from .sor import SQLor
|
||||||
|
|
||||||
class Aiosqliteor(SQLite3or):
|
select_stmt = """
|
||||||
|
select
|
||||||
|
$[fields]$
|
||||||
|
from
|
||||||
|
$[tables]$
|
||||||
|
$[whereclause]$
|
||||||
|
$[groupbyclause]$
|
||||||
|
$[havingclause]$
|
||||||
|
$[orderbyclause]$
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Aiosqliteor(SQLor):
|
||||||
@classmethod
|
@classmethod
|
||||||
def isMe(self,name):
|
def isMe(self,name):
|
||||||
return name=='aiosqlite'
|
return name=='aiosqlite'
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
"""
|
||||||
|
dbdesc:
|
||||||
|
path: 数据库文件路径(或 :memory:)
|
||||||
|
"""
|
||||||
|
dbdesc = self.dbdesc
|
||||||
|
self.dbpath = dbdesc.get('path', ':memory:')
|
||||||
|
self.conn = await aiosqlite.connect(self.dbpath)
|
||||||
|
self.conn.row_factory = aiosqlite.Row # 支持 dict 访问
|
||||||
|
self.dbname = self.dbpath
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
await self.conn.close()
|
||||||
|
|
||||||
|
async def enter(self):
|
||||||
|
"""开启事务"""
|
||||||
|
self.cur = await self.conn.cursor()
|
||||||
|
|
||||||
|
async def exit(self):
|
||||||
|
"""释放 cursor"""
|
||||||
|
try:
|
||||||
|
await self.cur.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.cur = None
|
||||||
|
|
||||||
|
def grammar(self):
|
||||||
|
return {
|
||||||
|
'select':select_stmt,
|
||||||
|
}
|
||||||
|
|
||||||
|
def placeHolder(self,varname,i):
|
||||||
|
if varname=='__mainsql__' :
|
||||||
|
return ''
|
||||||
|
return '?'
|
||||||
|
|
||||||
|
def dataConvert(self,dataList):
|
||||||
|
if type(dataList) == type({}):
|
||||||
|
return dataList
|
||||||
|
d = { i['name']:i['value'] for i in dataList }
|
||||||
|
return d
|
||||||
|
|
||||||
|
def pagingSQLmodel(self):
|
||||||
|
return u"""select * from (%s) page_s limit $[page_size]$ offset $[offset]$"""
|
||||||
|
|
||||||
|
def tablesSQL(self):
|
||||||
|
sqlcmd = """SELECT name,sql as title FROM sqlite_master WHERE type='table'"""
|
||||||
|
return sqlcmd
|
||||||
|
|
||||||
|
def fieldsSQL(self,tablename=None):
|
||||||
|
sqlcmd="""PRAGMA table_info(%s);""" % tablename
|
||||||
|
return sqlcmd
|
||||||
|
|
||||||
|
def fkSQL(self,tablename=None):
|
||||||
|
tablename = tablename.lower()
|
||||||
|
sqlcmd = """PRAGMA foreign_key_list('%s');""" % tablename
|
||||||
|
return sqlcmd
|
||||||
|
|
||||||
|
def pkSQL(self,tablename=None):
|
||||||
|
tablename = tablename.lower()
|
||||||
|
sqlcmd="""PRAGMA table_info('%s');""" % tablename
|
||||||
|
return sqlcmd
|
||||||
|
|
||||||
|
def indexesSQL(self,tablename=None):
|
||||||
|
sqlcmd = """PRAGMA index_list('%s');""" % tablename
|
||||||
|
return sqlcmd
|
||||||
0
sqlor/const.py
Executable file → Normal file
0
sqlor/const.py
Executable file → Normal file
0
sqlor/dbpools.old.py
Executable file → Normal file
0
sqlor/dbpools.old.py
Executable file → Normal file
0
sqlor/dbpools.py
Executable file → Normal file
0
sqlor/dbpools.py
Executable file → Normal file
0
sqlor/ddl_template_mysql.py
Executable file → Normal file
0
sqlor/ddl_template_mysql.py
Executable file → Normal file
0
sqlor/ddl_template_oracle.py
Executable file → Normal file
0
sqlor/ddl_template_oracle.py
Executable file → Normal file
0
sqlor/ddl_template_postgresql.py
Executable file → Normal file
0
sqlor/ddl_template_postgresql.py
Executable file → Normal file
0
sqlor/ddl_template_sqlite3.py
Executable file → Normal file
0
sqlor/ddl_template_sqlite3.py
Executable file → Normal file
0
sqlor/ddl_template_sqlserver.py
Executable file → Normal file
0
sqlor/ddl_template_sqlserver.py
Executable file → Normal file
0
sqlor/filter.py
Executable file → Normal file
0
sqlor/filter.py
Executable file → Normal file
53
sqlor/mssqlor.py
Executable file → Normal file
53
sqlor/mssqlor.py
Executable file → Normal file
@ -2,6 +2,17 @@
|
|||||||
from .sor import SQLor
|
from .sor import SQLor
|
||||||
from .ddl_template_sqlserver import sqlserver_ddl_tmpl
|
from .ddl_template_sqlserver import sqlserver_ddl_tmpl
|
||||||
|
|
||||||
|
select_stmt = """
|
||||||
|
select
|
||||||
|
$[fields]$
|
||||||
|
from
|
||||||
|
$[tables]$
|
||||||
|
$[whereclause]$
|
||||||
|
$[groupbyclause]$
|
||||||
|
$[havingclause]$
|
||||||
|
$[orderbyclause]$
|
||||||
|
"""
|
||||||
|
|
||||||
class MsSqlor(SQLor):
|
class MsSqlor(SQLor):
|
||||||
ddl_template = sqlserver_ddl_tmpl
|
ddl_template = sqlserver_ddl_tmpl
|
||||||
db2modelTypeMapping = {
|
db2modelTypeMapping = {
|
||||||
@ -45,7 +56,7 @@ class MsSqlor(SQLor):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def isMe(self,name):
|
def isMe(self,name):
|
||||||
return name=='pymssql'
|
return name=='pymssql'
|
||||||
|
|
||||||
def grammar(self):
|
def grammar(self):
|
||||||
return {
|
return {
|
||||||
'select':select_stmt,
|
'select':select_stmt,
|
||||||
@ -55,7 +66,7 @@ class MsSqlor(SQLor):
|
|||||||
if varname=='__mainsql__' :
|
if varname=='__mainsql__' :
|
||||||
return ''
|
return ''
|
||||||
return '%s'
|
return '%s'
|
||||||
|
|
||||||
def dataConvert(self,dataList):
|
def dataConvert(self,dataList):
|
||||||
if type(dataList) == type({}):
|
if type(dataList) == type({}):
|
||||||
d = [ i for i in dataList.values()]
|
d = [ i for i in dataList.values()]
|
||||||
@ -86,9 +97,9 @@ where _row_id >= $[from_line]$ and _row_id < $[end_line]$"""
|
|||||||
,length = Columnproperty(a.id,a.name,'PRECISION')
|
,length = Columnproperty(a.id,a.name,'PRECISION')
|
||||||
,dec = Isnull(Columnproperty(a.id,a.name,'Scale'),null)
|
,dec = Isnull(Columnproperty(a.id,a.name,'Scale'),null)
|
||||||
,nullable = CASE
|
,nullable = CASE
|
||||||
WHEN a.isnullable = 1 THEN 'yes'
|
WHEN a.isnullable = 1 THEN 'yes'
|
||||||
ELSE 'no'
|
ELSE 'no'
|
||||||
END
|
END
|
||||||
,title = lower(cast(Isnull(g.[value],a.name) as nvarchar) )
|
,title = lower(cast(Isnull(g.[value],a.name) as nvarchar) )
|
||||||
,table_name = lower(d.name)
|
,table_name = lower(d.name)
|
||||||
FROM syscolumns a
|
FROM syscolumns a
|
||||||
@ -98,7 +109,7 @@ where _row_id >= $[from_line]$ and _row_id < $[end_line]$"""
|
|||||||
ON (a.id = d.id)
|
ON (a.id = d.id)
|
||||||
AND (d.xtype = 'U')
|
AND (d.xtype = 'U')
|
||||||
AND (d.name <> 'dtproperties')
|
AND (d.name <> 'dtproperties')
|
||||||
INNER JOIN sys.all_objects c
|
INNER JOIN sys.all_objects c
|
||||||
ON d.id=c.object_id
|
ON d.id=c.object_id
|
||||||
AND schema_name(schema_id)='dbo'
|
AND schema_name(schema_id)='dbo'
|
||||||
LEFT JOIN sys.extended_properties g
|
LEFT JOIN sys.extended_properties g
|
||||||
@ -172,3 +183,33 @@ AND IDXC.Column_id=C.Column_id"""
|
|||||||
if tablename is not None:
|
if tablename is not None:
|
||||||
sqlcmd = sqlcmd + """ where lower(O.name)='%s'""" % tablename.lower()
|
sqlcmd = sqlcmd + """ where lower(O.name)='%s'""" % tablename.lower()
|
||||||
return sqlcmd
|
return sqlcmd
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
"""
|
||||||
|
Note: pymssql is synchronous. For async support, consider using aioodbc.
|
||||||
|
This implementation uses threading for now.
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import pymssql
|
||||||
|
|
||||||
|
dbdesc = self.dbdesc
|
||||||
|
# pymssql uses different parameter names
|
||||||
|
conn_params = {
|
||||||
|
'server': dbdesc.get('host', 'localhost'),
|
||||||
|
'user': dbdesc.get('user'),
|
||||||
|
'password': dbdesc.get('password'),
|
||||||
|
'database': dbdesc.get('db'),
|
||||||
|
'port': dbdesc.get('port', 1433)
|
||||||
|
}
|
||||||
|
# Remove None values
|
||||||
|
conn_params = {k: v for k, v in conn_params.items() if v is not None}
|
||||||
|
|
||||||
|
# Use thread pool for synchronous pymssql
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
self.conn = await loop.run_in_executor(None, pymssql.connect, **conn_params)
|
||||||
|
self.dbname = dbdesc.get('db', '')
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
import asyncio
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
await loop.run_in_executor(None, self.conn.close)
|
||||||
0
sqlor/mysqlor.py
Executable file → Normal file
0
sqlor/mysqlor.py
Executable file → Normal file
47
sqlor/oracleor.py
Executable file → Normal file
47
sqlor/oracleor.py
Executable file → Normal file
@ -1,5 +1,17 @@
|
|||||||
from .sor import SQLor
|
from .sor import SQLor
|
||||||
from .ddl_template_oracle import oracle_ddl_tmpl
|
from .ddl_template_oracle import oracle_ddl_tmpl
|
||||||
|
|
||||||
|
select_stmt = """
|
||||||
|
select
|
||||||
|
$[fields]$
|
||||||
|
from
|
||||||
|
$[tables]$
|
||||||
|
$[whereclause]$
|
||||||
|
$[groupbyclause]$
|
||||||
|
$[havingclause]$
|
||||||
|
$[orderbyclause]$
|
||||||
|
"""
|
||||||
|
|
||||||
class Oracleor(SQLor):
|
class Oracleor(SQLor):
|
||||||
ddl_template = oracle_ddl_tmpl
|
ddl_template = oracle_ddl_tmpl
|
||||||
db2modelTypeMapping = {
|
db2modelTypeMapping = {
|
||||||
@ -49,7 +61,7 @@ class Oracleor(SQLor):
|
|||||||
if varname=='__mainsql__' :
|
if varname=='__mainsql__' :
|
||||||
return ''
|
return ''
|
||||||
return ':%s' % varname
|
return ':%s' % varname
|
||||||
|
|
||||||
def dataConvert(self,dataList):
|
def dataConvert(self,dataList):
|
||||||
if type(dataList) == type({}):
|
if type(dataList) == type({}):
|
||||||
return dataList
|
return dataList
|
||||||
@ -88,7 +100,7 @@ from USER_TAB_COMMENTS where table_type = 'TABLE'"""
|
|||||||
if tablename is not None:
|
if tablename is not None:
|
||||||
sqlcmd = sqlcmd + """ where lower(utc.table_name) = '%s'""" % tablename.lower()
|
sqlcmd = sqlcmd + """ where lower(utc.table_name) = '%s'""" % tablename.lower()
|
||||||
return sqlcmd
|
return sqlcmd
|
||||||
|
|
||||||
def fkSQL(self,tablename=None):
|
def fkSQL(self,tablename=None):
|
||||||
tablename = tablename.lower()
|
tablename = tablename.lower()
|
||||||
sqlcmd = """select
|
sqlcmd = """select
|
||||||
@ -106,7 +118,7 @@ where
|
|||||||
if tablename is not None:
|
if tablename is not None:
|
||||||
sqlcmd = sqlcmd + """ and lower(uc.table_name)='%s'""" % tablename.lower()
|
sqlcmd = sqlcmd + """ and lower(uc.table_name)='%s'""" % tablename.lower()
|
||||||
return sqlcmd
|
return sqlcmd
|
||||||
|
|
||||||
def pkSQL(self,tablename=None):
|
def pkSQL(self,tablename=None):
|
||||||
sqlcmd = """
|
sqlcmd = """
|
||||||
select
|
select
|
||||||
@ -130,4 +142,33 @@ where a.index_name = b.index_name"""
|
|||||||
if tablename is not None:
|
if tablename is not None:
|
||||||
sqlcmd += """ and lower(a.table_name) = lower('%s')""" % tablename.lower()
|
sqlcmd += """ and lower(a.table_name) = lower('%s')""" % tablename.lower()
|
||||||
return sqlcmd
|
return sqlcmd
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
"""
|
||||||
|
Note: cx_Oracle is synchronous. Using thread pool for async support.
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import cx_Oracle
|
||||||
|
|
||||||
|
dbdesc = self.dbdesc
|
||||||
|
# cx_Oracle connection string format
|
||||||
|
dsn = cx_Oracle.makedsn(
|
||||||
|
host=dbdesc.get('host', 'localhost'),
|
||||||
|
port=dbdesc.get('port', 1521),
|
||||||
|
service_name=dbdesc.get('service_name', dbdesc.get('sid', 'XE'))
|
||||||
|
)
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
self.conn = await loop.run_in_executor(
|
||||||
|
None,
|
||||||
|
cx_Oracle.connect,
|
||||||
|
dbdesc.get('user'),
|
||||||
|
dbdesc.get('password'),
|
||||||
|
dsn
|
||||||
|
)
|
||||||
|
self.dbname = dbdesc.get('service_name', dbdesc.get('sid', ''))
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
import asyncio
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
await loop.run_in_executor(None, self.conn.close)
|
||||||
25
sqlor/postgresqlor.py
Executable file → Normal file
25
sqlor/postgresqlor.py
Executable file → Normal file
@ -170,7 +170,7 @@ order by
|
|||||||
i.relname""" % tablename.lower()
|
i.relname""" % tablename.lower()
|
||||||
return sqlcmd
|
return sqlcmd
|
||||||
|
|
||||||
async def connect():
|
async def connect(self):
|
||||||
"""
|
"""
|
||||||
kwargs:
|
kwargs:
|
||||||
dbname:
|
dbname:
|
||||||
@ -179,13 +179,22 @@ order by
|
|||||||
host:
|
host:
|
||||||
port:
|
port:
|
||||||
"""
|
"""
|
||||||
kwargs = self.dbdesc
|
dbdesc = self.dbdesc
|
||||||
dns = ' '.join([f'{k}={v}' for k, v in kwargs.items()])
|
self.conn = await aiopg.connect(**dbdesc)
|
||||||
self.conn = await self.connect(dns)
|
self.dbname = dbdesc.get('dbname', '').lower()
|
||||||
self.cur = await self.conn.cursor()
|
|
||||||
self.dbname = kwargs.dbname.lower()
|
async def close(self):
|
||||||
|
|
||||||
async def close():
|
|
||||||
await self.cur.close()
|
await self.cur.close()
|
||||||
await self.conn.close()
|
await self.conn.close()
|
||||||
|
|
||||||
|
async def enter(self):
|
||||||
|
self.cur = await self.conn.cursor()
|
||||||
|
|
||||||
|
async def exit(self):
|
||||||
|
try:
|
||||||
|
await self.cur.fetchall()
|
||||||
|
await self.cur.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.cur = None
|
||||||
|
|
||||||
|
|||||||
0
sqlor/records.py
Executable file → Normal file
0
sqlor/records.py
Executable file → Normal file
0
sqlor/sor.py
Executable file → Normal file
0
sqlor/sor.py
Executable file → Normal file
0
sqlor/sqlite3or.py
Executable file → Normal file
0
sqlor/sqlite3or.py
Executable file → Normal file
@ -4,6 +4,17 @@ from .sor import SQLor
|
|||||||
from .const import ROWS
|
from .const import ROWS
|
||||||
from .ddl_template_mysql import mysql_ddl_tmpl # ✅ 直接复用 MySQL 模板
|
from .ddl_template_mysql import mysql_ddl_tmpl # ✅ 直接复用 MySQL 模板
|
||||||
|
|
||||||
|
select_stmt = """
|
||||||
|
select
|
||||||
|
$[fields]$
|
||||||
|
from
|
||||||
|
$[tables]$
|
||||||
|
$[whereclause]$
|
||||||
|
$[groupbyclause]$
|
||||||
|
$[havingclause]$
|
||||||
|
$[orderbyclause]$
|
||||||
|
"""
|
||||||
|
|
||||||
class TiDBor(SQLor):
|
class TiDBor(SQLor):
|
||||||
ddl_template = mysql_ddl_tmpl
|
ddl_template = mysql_ddl_tmpl
|
||||||
|
|
||||||
@ -50,7 +61,7 @@ class TiDBor(SQLor):
|
|||||||
|
|
||||||
def grammar(self):
|
def grammar(self):
|
||||||
return {
|
return {
|
||||||
'select': 'select * from {table} where {condition}',
|
'select': select_stmt,
|
||||||
}
|
}
|
||||||
|
|
||||||
def placeHolder(self, varname, pos=None):
|
def placeHolder(self, varname, pos=None):
|
||||||
@ -71,14 +82,14 @@ class TiDBor(SQLor):
|
|||||||
|
|
||||||
def tablesSQL(self):
|
def tablesSQL(self):
|
||||||
# ✅ TiDB 支持 INFORMATION_SCHEMA.TABLES
|
# ✅ TiDB 支持 INFORMATION_SCHEMA.TABLES
|
||||||
dbname = self.dbdesc.get('dbname', 'unknown')
|
dbname = self.dbdesc.get('db', 'unknown') # MySQL uses 'db', not 'dbname'
|
||||||
sqlcmd = f"""SELECT lower(TABLE_NAME) AS name, TABLE_COMMENT AS title
|
sqlcmd = f"""SELECT lower(TABLE_NAME) AS name, TABLE_COMMENT AS title
|
||||||
FROM INFORMATION_SCHEMA.TABLES
|
FROM INFORMATION_SCHEMA.TABLES
|
||||||
WHERE TABLE_SCHEMA = '{dbname}'"""
|
WHERE TABLE_SCHEMA = '{dbname}'"""
|
||||||
return sqlcmd
|
return sqlcmd
|
||||||
|
|
||||||
def fieldsSQL(self, tablename=None):
|
def fieldsSQL(self, tablename=None):
|
||||||
dbname = self.dbdesc.get('dbname', 'unknown').lower()
|
dbname = self.dbdesc.get('db', 'unknown').lower() # MySQL uses 'db'
|
||||||
sqlcmd = f"""
|
sqlcmd = f"""
|
||||||
SELECT
|
SELECT
|
||||||
lower(column_name) AS name,
|
lower(column_name) AS name,
|
||||||
@ -98,7 +109,7 @@ WHERE lower(TABLE_SCHEMA) = '{dbname}'
|
|||||||
|
|
||||||
def fkSQL(self, tablename=None):
|
def fkSQL(self, tablename=None):
|
||||||
# ✅ TiDB 兼容 MySQL 的 FK 元信息
|
# ✅ TiDB 兼容 MySQL 的 FK 元信息
|
||||||
dbname = self.dbdesc.get('dbname', 'unknown').lower()
|
dbname = self.dbdesc.get('db', 'unknown').lower()
|
||||||
sqlcmd = f"""
|
sqlcmd = f"""
|
||||||
SELECT
|
SELECT
|
||||||
C.TABLE_SCHEMA AS owner,
|
C.TABLE_SCHEMA AS owner,
|
||||||
@ -121,7 +132,7 @@ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|||||||
WHERE table_name='{tablename.lower()}' AND constraint_name='PRIMARY'"""
|
WHERE table_name='{tablename.lower()}' AND constraint_name='PRIMARY'"""
|
||||||
|
|
||||||
def indexesSQL(self, tablename=None):
|
def indexesSQL(self, tablename=None):
|
||||||
dbname = self.dbdesc.get('dbname', 'unknown')
|
dbname = self.dbdesc.get('db', 'unknown')
|
||||||
sqlcmd = f"""SELECT DISTINCT
|
sqlcmd = f"""SELECT DISTINCT
|
||||||
lower(index_name) AS index_name,
|
lower(index_name) AS index_name,
|
||||||
CASE NON_UNIQUE WHEN 0 THEN 'unique' ELSE '' END AS is_unique,
|
CASE NON_UNIQUE WHEN 0 THEN 'unique' ELSE '' END AS is_unique,
|
||||||
@ -132,3 +143,28 @@ WHERE table_schema = '{dbname}'"""
|
|||||||
sqlcmd += f" AND table_name = '{tablename.lower()}'"
|
sqlcmd += f" AND table_name = '{tablename.lower()}'"
|
||||||
return sqlcmd
|
return sqlcmd
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
"""
|
||||||
|
TiDB 兼容 MySQL 协议,使用 aiomysql
|
||||||
|
"""
|
||||||
|
import aiomysql
|
||||||
|
|
||||||
|
dbdesc = self.dbdesc
|
||||||
|
# TiDB 使用与 MySQL 相同的连接参数
|
||||||
|
self.conn = await aiomysql.connect(**dbdesc)
|
||||||
|
self.dbname = dbdesc.get('db', '')
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
await self.cur.close()
|
||||||
|
await self.conn.close()
|
||||||
|
|
||||||
|
async def enter(self):
|
||||||
|
self.cur = await self.conn.cursor()
|
||||||
|
|
||||||
|
async def exit(self):
|
||||||
|
try:
|
||||||
|
await self.cur.fetchall()
|
||||||
|
await self.cur.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.cur = None
|
||||||
Loading…
x
Reference in New Issue
Block a user