mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Added support for qtIdent, qtTypeIdent, qtLiteral for quoting the
inputs. In order to do the proper quoting around the identifier, different type, and literal, we introduced respective functions qtIdent, qtTypeIdent, qtLiteral in psycopg2 driver. Also, introduced them as the Jinja's custom filter for using it directly inside the templates. Also, created an utility - generate_keywords.py in order to generate keyword lists from the latest PostgreSQL installation.
This commit is contained in:
@@ -104,6 +104,19 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
|
||||
return scripts
|
||||
|
||||
def register(self, app, options, first_registration=False):
|
||||
"""
|
||||
Override the default register function to automagically register
|
||||
sub-modules at once.
|
||||
"""
|
||||
if first_registration:
|
||||
from pgadmin.utils.driver import get_driver
|
||||
driver = get_driver(PG_DEFAULT_DRIVER, app)
|
||||
app.jinja_env.filters['qtLiteral'] = driver.qtLiteral
|
||||
app.jinja_env.filters['qtIdent'] = driver.qtIdent
|
||||
app.jinja_env.filters['qtTypeIdent'] = driver.qtTypeIdent
|
||||
|
||||
super(ServerModule, self).register(app, options, first_registration)
|
||||
|
||||
class ServerMenuItem(MenuItem):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
@@ -2,8 +2,12 @@ from flask import current_app
|
||||
from .registry import DriverRegistry
|
||||
|
||||
|
||||
def get_driver(type):
|
||||
drivers = getattr(current_app, '_pgadmin_server_drivers', None)
|
||||
def get_driver(type, app=None):
|
||||
|
||||
if app is not None:
|
||||
DriverRegistry.load_drivers()
|
||||
|
||||
drivers = getattr(app or current_app, '_pgadmin_server_drivers', None)
|
||||
|
||||
if drivers is None or not isinstance(drivers, dict):
|
||||
drivers = dict()
|
||||
@@ -15,7 +19,7 @@ def get_driver(type):
|
||||
|
||||
if driver is not None:
|
||||
drivers[type] = driver
|
||||
setattr(current_app, '_pgadmin_server_drivers', drivers)
|
||||
setattr(app or current_app, '_pgadmin_server_drivers', drivers)
|
||||
|
||||
return driver
|
||||
|
||||
@@ -25,6 +29,8 @@ def init_app(app):
|
||||
setattr(app, '_pgadmin_server_drivers', drivers)
|
||||
DriverRegistry.load_drivers()
|
||||
|
||||
return drivers
|
||||
|
||||
|
||||
def ping():
|
||||
drivers = getattr(current_app, '_pgadmin_server_drivers', None)
|
||||
|
||||
@@ -10,6 +10,7 @@ from datetime import datetime
|
||||
|
||||
import psycopg2
|
||||
import psycopg2.extras
|
||||
from psycopg2.extensions import adapt
|
||||
|
||||
from flask import g, current_app, session
|
||||
from flask.ext.babel import gettext
|
||||
@@ -20,6 +21,8 @@ from pgadmin.settings.settings_model import Server, User
|
||||
from pgadmin.utils.crypto import encrypt, decrypt
|
||||
import random
|
||||
|
||||
from .keywords import ScanKeyword
|
||||
|
||||
|
||||
_ = gettext
|
||||
|
||||
@@ -746,3 +749,118 @@ class Driver(BaseDriver):
|
||||
for mgr in [m for m in sess_mgr if isinstance(m,
|
||||
ServerManager)]:
|
||||
mgr.release()
|
||||
|
||||
@staticmethod
|
||||
def qtLiteral(value):
|
||||
return adapt(value).getquoted()
|
||||
|
||||
@staticmethod
|
||||
def ScanKeywordExtraLookup(key):
|
||||
# UNRESERVED_KEYWORD 0
|
||||
# COL_NAME_KEYWORD 1
|
||||
# TYPE_FUNC_NAME_KEYWORD 2
|
||||
# RESERVED_KEYWORD 3
|
||||
extraKeywords = {
|
||||
'connect': 3,
|
||||
'convert': 3,
|
||||
'distributed': 0,
|
||||
'exec': 3,
|
||||
'log': 0,
|
||||
'long': 3,
|
||||
'minus': 3,
|
||||
'nocache': 3,
|
||||
'number': 3,
|
||||
'package': 3,
|
||||
'pls_integer': 3,
|
||||
'raw': 3,
|
||||
'return': 3,
|
||||
'smalldatetime': 3,
|
||||
'smallfloat': 3,
|
||||
'smallmoney': 3,
|
||||
'sysdate': 3,
|
||||
'systimestap': 3,
|
||||
'tinyint': 3,
|
||||
'tinytext': 3,
|
||||
'varchar2': 3
|
||||
};
|
||||
|
||||
return (key in extraKeywords and extraKeywords[key]) or ScanKeyword(key)
|
||||
|
||||
@staticmethod
|
||||
def needsQuoting(key, forTypes):
|
||||
|
||||
value = key.decode()
|
||||
valNoArray = value.decode()
|
||||
|
||||
# check if the string is number or not
|
||||
if (isinstance(value, int)):
|
||||
return True;
|
||||
# certain types should not be quoted even though it contains a space. Evilness.
|
||||
elif forTypes and value[-2:] == u"[]":
|
||||
valNoArray = value[:-2]
|
||||
|
||||
if forTypes and valNoArray.lower() in [
|
||||
u"bit varying"
|
||||
u"\"char\"",
|
||||
u"character varying",
|
||||
u"double precision"
|
||||
u"timestamp without time zone"
|
||||
u"timestamp with time zone"
|
||||
u"time without time zone"
|
||||
u"time with time zone"
|
||||
u"\"trigger\""
|
||||
u"\"unknown\""
|
||||
]:
|
||||
return False
|
||||
|
||||
if u'0' <= valNoArray[0] <= u'9':
|
||||
return True
|
||||
|
||||
for c in valNoArray:
|
||||
if not (u'a' <= c <= u'z') and c != u'_':
|
||||
return True
|
||||
|
||||
# check string is keywaord or not
|
||||
category = Driver.ScanKeywordExtraLookup(value)
|
||||
|
||||
if category is None:
|
||||
return False
|
||||
|
||||
# UNRESERVED_KEYWORD
|
||||
if category == 0:
|
||||
return False
|
||||
|
||||
# COL_NAME_KEYWORD
|
||||
if forTypes and category == 3:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def qtTypeIdent(value):
|
||||
|
||||
if (len(value) == 0):
|
||||
return value
|
||||
|
||||
result = value;
|
||||
|
||||
if (Driver.needsQuoting(result, True)):
|
||||
result.replace("\"", "\"\"")
|
||||
return "\"" + result + "\""
|
||||
else:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def qtIdent(value):
|
||||
|
||||
if (len(value) == 0):
|
||||
return value
|
||||
|
||||
result = value;
|
||||
|
||||
if (Driver.needsQuoting(result, False)):
|
||||
result.replace("\"", "\"\"")
|
||||
return "\"" + result + "\""
|
||||
else:
|
||||
return result;
|
||||
|
||||
|
||||
61
web/pgadmin/utils/driver/psycopg2/generate_keywords.py
Normal file
61
web/pgadmin/utils/driver/psycopg2/generate_keywords.py
Normal file
@@ -0,0 +1,61 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
# This allows us to generate to keywords.py for PostgreSQL for used by
|
||||
# qtIdent and qtTypeIdent functions for scanning the keywords type.
|
||||
#
|
||||
# In order to generate keywords.py for specific version of PostgreSQL, put
|
||||
# pg_config executable in the PATH.
|
||||
#
|
||||
##########################################################################
|
||||
import re
|
||||
import os
|
||||
|
||||
if __name__ == '__main__':
|
||||
include_dir = os.popen('pg_config --includedir').read().rstrip()
|
||||
version = os.popen('pg_config --version').read().rstrip()
|
||||
|
||||
keywords_file = open('keywords.py', 'w')
|
||||
|
||||
keywords_file.write("""##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2015, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
""")
|
||||
keywords_file.write('# ScanKeyword function for ' + version)
|
||||
keywords_file.write('\n\ndef ScanKeyword(key):')
|
||||
keywords_file.write('\n keywordDict = {\n')
|
||||
|
||||
idx = 0
|
||||
|
||||
with open(include_dir + "/postgresql/server/parser/kwlist.h", "rb") as ins:
|
||||
|
||||
pattern = re.compile(r'"([^"]+)",\s*[^,]*\s*,\s*(.*)$')
|
||||
keyword_types = [
|
||||
u'UNRESERVED_KEYWORD', u'COL_NAME_KEYWORD',
|
||||
u'TYPE_FUNC_NAME_KEYWORD', u'RESERVED_KEYWORD'
|
||||
]
|
||||
|
||||
for line in ins:
|
||||
line = line.decode().rstrip()
|
||||
if line[0:11] == 'PG_KEYWORD(' and line[-1] == ')':
|
||||
match = pattern.match(line[11:-1])
|
||||
if idx != 0:
|
||||
keywords_file.write(", ")
|
||||
else:
|
||||
keywords_file.write(" ")
|
||||
keywords_file.write(
|
||||
'"' + match.group(1) + u'": ' +
|
||||
str(keyword_types.index(match.group(2)))
|
||||
)
|
||||
idx += 1
|
||||
keywords_file.write('\n }\n')
|
||||
keywords_file.write(' return (key in keywordDict and keywordDict[key]) or None')
|
||||
15
web/pgadmin/utils/driver/psycopg2/keywords.py
Normal file
15
web/pgadmin/utils/driver/psycopg2/keywords.py
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user