diff --git a/docker-compose.yml b/docker-compose.yml
index 1e43cfe08..37009aeb9 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -25,13 +25,15 @@ services:
     networks:
       - nocobase
   postgres:
-    image: postgres:10
+    image: postgres:latest
     restart: always
     networks:
       - nocobase
     command: postgres -c wal_level=logical
     ports:
       - "${DB_POSTGRES_PORT}:5432"
+    volumes:
+      - ./storage/db/postgres/backups:/backups
     environment:
       POSTGRES_USER: ${DB_USER}
       POSTGRES_DB: ${DB_DATABASE}
diff --git a/packages/core/actions/src/__tests__/create-action.test.ts b/packages/core/actions/src/__tests__/create-action.test.ts
index 3b44e0402..43e8b7491 100644
--- a/packages/core/actions/src/__tests__/create-action.test.ts
+++ b/packages/core/actions/src/__tests__/create-action.test.ts
@@ -9,6 +9,7 @@ describe('create action', () => {
 
   beforeEach(async () => {
     app = mockServer();
+    await app.db.clean({ drop: true });
     registerActions(app);
 
     Post = app.collection({
diff --git a/packages/core/actions/src/__tests__/remove-action.test.ts b/packages/core/actions/src/__tests__/remove-action.test.ts
index 1b888ee7f..080e7d3e8 100644
--- a/packages/core/actions/src/__tests__/remove-action.test.ts
+++ b/packages/core/actions/src/__tests__/remove-action.test.ts
@@ -13,6 +13,8 @@ describe('remove action', () => {
     app = mockServer();
     registerActions(app);
 
+    await app.db.clean({ drop: true });
+
     PostTag = app.collection({
       name: 'posts_tags',
       fields: [{ type: 'string', name: 'tagged_at' }],
diff --git a/packages/core/actions/src/__tests__/set-action.test.ts b/packages/core/actions/src/__tests__/set-action.test.ts
index 5bf4e48a8..117a085aa 100644
--- a/packages/core/actions/src/__tests__/set-action.test.ts
+++ b/packages/core/actions/src/__tests__/set-action.test.ts
@@ -10,6 +10,7 @@ describe('set action', () => {
 
   beforeEach(async () => {
     app = mockServer();
+    await app.db.clean({ drop: true });
     registerActions(app);
 
     PostTag = app.collection({
diff --git a/packages/core/actions/src/__tests__/toggle-action.test.ts b/packages/core/actions/src/__tests__/toggle-action.test.ts
index 451cc076e..dcfea48e9 100644
--- a/packages/core/actions/src/__tests__/toggle-action.test.ts
+++ b/packages/core/actions/src/__tests__/toggle-action.test.ts
@@ -10,6 +10,7 @@ describe('toggle action', () => {
 
   beforeEach(async () => {
     app = mockServer();
+    await app.db.clean({ drop: true });
     registerActions(app);
 
     PostTag = app.collection({
diff --git a/packages/core/client/src/block-provider/BlockProvider.tsx b/packages/core/client/src/block-provider/BlockProvider.tsx
index 69925b641..9fdcd3e1c 100644
--- a/packages/core/client/src/block-provider/BlockProvider.tsx
+++ b/packages/core/client/src/block-provider/BlockProvider.tsx
@@ -292,9 +292,27 @@ export const useSourceIdFromParentRecord = () => {
 
 export const useParamsFromRecord = () => {
   const filterByTk = useFilterByTk();
-  return {
+  const record = useRecord();
+  const { fields } = useCollection();
+  const filterFields = fields
+    .filter((v) => {
+      return ['boolean', 'date', 'integer', 'radio', 'sort', 'string', 'time', 'uid', 'uuid'].includes(v.type);
+    })
+    .map((v) => v.name);
+  const filter = Object.keys(record)
+    .filter((key) => filterFields.includes(key))
+    .reduce((result, key) => {
+      result[key] = record[key];
+      return result;
+    }, {});
+
+  const obj = {
     filterByTk: filterByTk,
   };
+  if (!filterByTk) {
+    obj['filter'] = filter;
+  }
+  return obj;
 };
 
 export const RecordLink = (props) => {
diff --git a/packages/core/client/src/collection-manager/CollectionField.tsx b/packages/core/client/src/collection-manager/CollectionField.tsx
index d353847b1..00e39271b 100644
--- a/packages/core/client/src/collection-manager/CollectionField.tsx
+++ b/packages/core/client/src/collection-manager/CollectionField.tsx
@@ -13,7 +13,7 @@ const InternalField: React.FC = (props) => {
   const fieldSchema = useFieldSchema();
   const { name, interface: interfaceType, uiSchema, defaultValue } = useCollectionField();
   const collectionField = useCollectionField();
-  const component = useComponent(uiSchema?.['x-component']);
+  const component = useComponent(uiSchema?.['x-component'] || 'Input');
   const compile = useCompile();
   const setFieldProps = (key, value) => {
     field[key] = typeof field[key] === 'undefined' ? value : field[key];
@@ -73,7 +73,6 @@ const InternalField: React.FC = (props) => {
   if (!uiSchema) {
     return null;
   }
-
   return React.createElement(component, props, props.children);
 };
 
@@ -107,7 +106,6 @@ export const CollectionField = connect((props) => {
   const fieldSchema = useFieldSchema();
   const field = fieldSchema?.['x-component-props']?.['field'];
   const { snapshot } = useActionContext();
-
   return (
     <CollectionFieldProvider
       name={fieldSchema.name}
diff --git a/packages/core/client/src/collection-manager/CollectionManagerShortcut.tsx b/packages/core/client/src/collection-manager/CollectionManagerShortcut.tsx
index 656fdcd47..b072d7542 100644
--- a/packages/core/client/src/collection-manager/CollectionManagerShortcut.tsx
+++ b/packages/core/client/src/collection-manager/CollectionManagerShortcut.tsx
@@ -26,6 +26,8 @@ import {
   ConfigurationTabs,
   EditCategory,
   EditCategoryAction,
+  SyncFieldsAction,
+  SyncFieldsActionCom
 } from './Configuration';
 
 import { CollectionCategroriesProvider } from './CollectionManagerProvider';
@@ -81,6 +83,8 @@ export const CollectionManagerPane = () => {
           ViewFieldAction,
           EditCategory,
           EditCategoryAction,
+          SyncFieldsAction,
+          SyncFieldsActionCom
         }}
       />
     // </Card>
diff --git a/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx b/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx
index 844425f97..7e8b64617 100644
--- a/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx
+++ b/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx
@@ -28,8 +28,9 @@ const getSchema = (schema, category, compile): ISchema => {
     properties['defaultValue']['x-decorator'] = 'FormItem';
   }
   const initialValue: any = {
-    name: `t_${uid()}`,
+    name: schema.name !== 'view' ? `t_${uid()}` : null,
     template: schema.name,
+    view: schema.name === 'view',
     category,
     ...cloneDeep(schema.default),
   };
@@ -201,7 +202,7 @@ const useCreateCollection = (schema?: any) => {
       if (schema?.events?.beforeSubmit) {
         schema.events.beforeSubmit(values);
       }
-      const fields = useDefaultCollectionFields(values);
+      const fields = values?.template !== 'view' ? useDefaultCollectionFields(values) : values.fields;
       if (values.autoCreateReverseField) {
       } else {
         delete values.reverseField;
@@ -235,8 +236,15 @@ export const AddCollectionAction = (props) => {
   const [schema, setSchema] = useState({});
   const compile = useCompile();
   const { t } = useTranslation();
-  const items = templateOptions().map((option) => {
-    return { label: compile(option.title), key: option.name };
+  const collectionTemplates = templateOptions();
+  const items = [];
+  collectionTemplates.forEach((item) => {
+    if (item.divider) {
+      items.push({
+        type: 'divider',
+      });
+    }
+    items.push({ label: compile(item.title), key: item.name });
   });
   const {
     state: { category },
diff --git a/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx
index 3d6b83efa..77b77c293 100644
--- a/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx
+++ b/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx
@@ -212,72 +212,74 @@ export const AddFieldAction = (props) => {
     return optionArr;
   };
   return (
-    <RecordProvider record={record}>
-      <ActionContext.Provider value={{ visible, setVisible }}>
-        <Dropdown
-          getPopupContainer={getContainer}
-          trigger={trigger}
-          align={align}
-          overlay={
-            <Menu
-              style={{
-                maxHeight: '60vh',
-                overflow: 'auto',
-              }}
-              onClick={(e) => {
-                //@ts-ignore
-                const targetScope = e.item.props['data-targetScope'];
-                targetScope && setTargetScope(targetScope);
-                const schema = getSchema(getInterface(e.key), record, compile);
-                if (schema) {
-                  setSchema(schema);
-                  setVisible(true);
-                }
-              }}
-            >
-              {getFieldOptions().map((option) => {
-                return (
-                  option.children.length > 0 && (
-                    <Menu.ItemGroup key={option.label} title={compile(option.label)}>
-                      {option.children
-                        .filter((child) => !['o2o', 'subTable'].includes(child.name))
-                        .map((child) => {
-                          return (
-                            <Menu.Item key={child.name} data-targetScope={child.targetScope}>
-                              {compile(child.title)}
-                            </Menu.Item>
-                          );
-                        })}
-                    </Menu.ItemGroup>
-                  )
-                );
-              })}
-            </Menu>
-          }
-        >
-          {children || (
-            <Button icon={<PlusOutlined />} type={'primary'}>
-              {t('Add field')}
-            </Button>
-          )}
-        </Dropdown>
-        <SchemaComponent
-          schema={schema}
-          components={{ ...components, ArrayTable }}
-          scope={{
-            getContainer,
-            useCancelAction,
-            createOnly: true,
-            isOverride: false,
-            override: false,
-            useCreateCollectionField,
-            record,
-            showReverseFieldConfig: true,
-            targetScope,
-            ...scope,
-          }}
-        />
-      </ActionContext.Provider>
-    </RecordProvider>
+    record.template !== 'view' && (
+      <RecordProvider record={record}>
+        <ActionContext.Provider value={{ visible, setVisible }}>
+          <Dropdown
+            getPopupContainer={getContainer}
+            trigger={trigger}
+            align={align}
+            overlay={
+              <Menu
+                style={{
+                  maxHeight: '60vh',
+                  overflow: 'auto',
+                }}
+                onClick={(e) => {
+                  //@ts-ignore
+                  const targetScope = e.item.props['data-targetScope'];
+                  targetScope && setTargetScope(targetScope);
+                  const schema = getSchema(getInterface(e.key), record, compile);
+                  if (schema) {
+                    setSchema(schema);
+                    setVisible(true);
+                  }
+                }}
+              >
+                {getFieldOptions().map((option) => {
+                  return (
+                    option.children.length > 0 && (
+                      <Menu.ItemGroup key={option.label} title={compile(option.label)}>
+                        {option.children
+                          .filter((child) => !['o2o', 'subTable'].includes(child.name))
+                          .map((child) => {
+                            return (
+                              <Menu.Item key={child.name} data-targetScope={child.targetScope}>
+                                {compile(child.title)}
+                              </Menu.Item>
+                            );
+                          })}
+                      </Menu.ItemGroup>
+                    )
+                  );
+                })}
+              </Menu>
+            }
+          >
+            {children || (
+              <Button icon={<PlusOutlined />} type={'primary'}>
+                {t('Add field')}
+              </Button>
+            )}
+          </Dropdown>
+          <SchemaComponent
+            schema={schema}
+            components={{ ...components, ArrayTable }}
+            scope={{
+              getContainer,
+              useCancelAction,
+              createOnly: true,
+              isOverride: false,
+              override: false,
+              useCreateCollectionField,
+              record,
+              showReverseFieldConfig: true,
+              targetScope,
+              ...scope,
+            }}
+          />
+        </ActionContext.Provider>
+      </RecordProvider>
+    )
   );
 };
diff --git a/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx b/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx
index ec7981ab2..9036d2c38 100644
--- a/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx
+++ b/packages/core/client/src/collection-manager/Configuration/ConfigurationTable.tsx
@@ -14,6 +14,7 @@ import { AddSubFieldAction } from './AddSubFieldAction';
 import { FieldSummary } from './components/FieldSummary';
 import { EditSubFieldAction } from './EditSubFieldAction';
 import { collectionSchema } from './schemas/collections';
+import { useAPIClient } from '../../api-client';
 
 const useAsyncDataSource = (service: any) => {
   return (field: any, options?: any) => {
@@ -77,23 +78,32 @@ export const ConfigurationTable = () => {
   const {
     data: { database },
   } = useCurrentAppInfo();
+
   const data = useContext(CollectionCategroriesContext);
+  const api = useAPIClient();
+  const resource = api.resource('dbViews');
   const collectonsRef: any = useRef();
   collectonsRef.current = collections;
   const compile = useCompile();
   const loadCollections = async (field, options) => {
     const { targetScope } = options;
-    return collectonsRef.current
-      ?.filter((item) => !(item.autoCreate && item.isThrough))
-      .filter((item) =>
-        targetScope
-          ? targetScope['template']?.includes(item.template) || targetScope[field.props.name]?.includes(item.name)
-          : true,
-      )
-      .map((item: any) => ({
-        label: compile(item.title),
-        value: item.name,
-      }));
+    const isFieldInherits = field.props?.name === 'inherits';
+    const filteredItems = collectonsRef.current.filter((item) => {
+      const isAutoCreateAndThrough = item.autoCreate && item.isThrough;
+      if (isAutoCreateAndThrough) {
+        return false;
+      }
+      if (isFieldInherits && item.template === 'view') {
+        return false;
+      }
+      const templateIncluded = !targetScope?.template || targetScope.template.includes(item.template);
+      const nameIncluded = !targetScope?.[field.props?.name] || targetScope[field.props.name].includes(item.name);
+      return templateIncluded && nameIncluded;
+    });
+    return filteredItems.map((item) => ({
+      label: compile(item.title),
+      value: item.name,
+    }));
   };
   const loadCategories = async () => {
     return data.data.map((item: any) => ({
@@ -101,31 +111,45 @@ export const ConfigurationTable = () => {
       value: item.id,
     }));
   };
+
+  const loadDBViews = async () => {
+    return resource.list().then(({ data }) => {
+      return data?.data?.map((item: any) => {
+        const schema = item.schema;
+        return {
+          label: schema ? `${schema}.${compile(item.name)}` : item.name,
+          value: schema?`${schema}_${item.name}`:item.name 
+        };
+      });
+    });
+  };
   const ctx = useContext(SchemaComponentContext);
   return (
-      <SchemaComponentContext.Provider value={{ ...ctx, designable: false }}>
-        <SchemaComponent
-          schema={collectionSchema}
-          components={{
-            AddSubFieldAction,
-            EditSubFieldAction,
-            FieldSummary,
-            CollectionFieldsTable,
-          }}
-          scope={{
-            useDestroySubField,
-            useBulkDestroySubField,
-            useSelectedRowKeys,
-            useAsyncDataSource,
-            loadCollections,
-            loadCategories,
-            useCurrentFields,
-            useNewId,
-            useCancelAction,
-            interfaces,
-            enableInherits: database?.dialect === 'postgres',
-          }}
-        />
-      </SchemaComponentContext.Provider>
+    <SchemaComponentContext.Provider value={{ ...ctx, designable: false }}>
+      <SchemaComponent
+        schema={collectionSchema}
+        components={{
+          AddSubFieldAction,
+          EditSubFieldAction,
+          FieldSummary,
+          CollectionFieldsTable,
+        }}
+        scope={{
+          useDestroySubField,
+          useBulkDestroySubField,
+          useSelectedRowKeys,
+          useAsyncDataSource,
+          loadCollections,
+          loadCategories,
+          loadDBViews,
+          useCurrentFields,
+          useNewId,
+          useCancelAction,
+          interfaces,
+          enableInherits: database?.dialect === 'postgres',
+          isPG:database?.dialect === 'postgres',
+        }}
+      />
+    </SchemaComponentContext.Provider>
   );
 };
diff --git a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx
index 233fa3631..624b27af4 100644
--- a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx
+++ b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx
@@ -19,10 +19,12 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema
     return;
   }
   const properties = cloneDeep(schema.properties) as any;
-  properties.name['x-disabled'] = true;
+  if (properties?.name) {
+    properties.name['x-disabled'] = true;
+  }
 
   if (schema.hasDefaultValue === true) {
-    properties['defaultValue'] = cloneDeep(schema.default.uiSchema);
+    properties['defaultValue'] = cloneDeep(schema.default.uiSchema)||{};
     properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
     properties['defaultValue']['x-decorator'] = 'FormItem';
     properties['defaultValue']['x-reactions'] = {
@@ -156,7 +158,7 @@ export const EditFieldAction = (props) => {
             const defaultValues: any = cloneDeep(data?.data) || {};
             if (!defaultValues?.reverseField) {
               defaultValues.autoCreateReverseField = false;
-              defaultValues.reverseField = interfaceConf.default?.reverseField;
+              defaultValues.reverseField = interfaceConf?.default?.reverseField;
               set(defaultValues.reverseField, 'name', `f_${uid()}`);
               set(defaultValues.reverseField, 'uiSchema.title', record.__parent.title);
             }
diff --git a/packages/core/client/src/collection-manager/Configuration/SyncFieldsAction.tsx b/packages/core/client/src/collection-manager/Configuration/SyncFieldsAction.tsx
new file mode 100644
index 000000000..98786f22b
--- /dev/null
+++ b/packages/core/client/src/collection-manager/Configuration/SyncFieldsAction.tsx
@@ -0,0 +1,194 @@
+import { PlusOutlined } from '@ant-design/icons';
+import { ArrayTable } from '@formily/antd';
+import { useForm } from '@formily/react';
+import { uid } from '@formily/shared';
+import { Button } from 'antd';
+import { cloneDeep } from 'lodash';
+import React, { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useRequest } from '../../api-client';
+import { RecordProvider, useRecord } from '../../record-provider';
+import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
+import { useCancelAction } from '../action-hooks';
+import { useCollectionManager } from '../hooks';
+import { IField } from '../interfaces/types';
+import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
+import * as components from './components';
+import { useAPIClient } from '../../api-client';
+import { PreviewFields } from '../templates/components/PreviewFields';
+import { PreviewTable } from '../templates/components/PreviewTable';
+
+const getSchema = (schema: IField, record: any, compile) => {
+  if (!schema) {
+    return;
+  }
+
+  const properties = cloneDeep(schema.properties) as any;
+
+  if (schema.hasDefaultValue === true) {
+    properties['defaultValue'] = cloneDeep(schema?.default?.uiSchema);
+    properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
+    properties['defaultValue']['x-decorator'] = 'FormItem';
+  }
+  const initialValue: any = {
+    name: `f_${uid()}`,
+    ...cloneDeep(schema.default),
+    interface: schema.name,
+  };
+  if (initialValue.reverseField) {
+    initialValue.reverseField.name = `f_${uid()}`;
+  }
+  // initialValue.uiSchema.title = schema.title;
+  return {
+    type: 'object',
+    properties: {
+      [uid()]: {
+        type: 'void',
+        'x-component': 'Action.Drawer',
+        'x-component-props': {
+          getContainer: '{{ getContainer }}',
+        },
+        'x-decorator': 'Form',
+        'x-decorator-props': {
+          useValues(options) {
+            return useRequest(
+              () =>
+                Promise.resolve({
+                  data: initialValue,
+                }),
+              options,
+            );
+          },
+        },
+        title: `${compile('{{ t("Sync from database") }}')}`,
+        properties: {
+          schema: {
+            type: 'string',
+            'x-hidden': true,
+            default: record?.schema,
+          },
+          viewName: {
+            type: 'string',
+            'x-hidden': true,
+            default: record?.viewName,
+          },
+          fields: {
+            type: 'array',
+            'x-component': PreviewFields,
+            'x-component-props': {
+              ...record,
+            },
+            default: record.fields,
+          },
+          preview: {
+            type: 'object',
+            'x-component': PreviewTable,
+            'x-component-props': {
+              ...record,
+            },
+            'x-reactions': {
+              dependencies: ['fields'],
+              fulfill: {
+                schema: {
+                  'x-component-props': '{{{...record,...$form.values}}}', //任意层次属性都支持表达式
+                },
+              },
+            },
+          },
+          footer: {
+            type: 'void',
+            'x-component': 'Action.Drawer.Footer',
+            properties: {
+              action1: {
+                title: '{{ t("Cancel") }}',
+                'x-component': 'Action',
+                'x-component-props': {
+                  useAction: '{{ useCancelAction }}',
+                },
+              },
+              action2: {
+                title: '{{ t("Submit") }}',
+                'x-component': 'Action',
+                'x-component-props': {
+                  type: 'primary',
+                  useAction: '{{ useSyncFromDatabase }}',
+                },
+              },
+            },
+          },
+        },
+      },
+    },
+  };
+};
+
+const useSyncFromDatabase = () => {
+  const form = useForm();
+  const { refreshCM } = useCollectionManager();
+  const ctx = useActionContext();
+  const { refresh } = useResourceActionContext();
+  const { targetKey } = useResourceContext();
+  const { [targetKey]: filterByTk } = useRecord();
+  const api = useAPIClient();
+  return {
+    async run() {
+      await form.submit();
+      await api.resource(`collections`).setFields({
+        filterByTk,
+        values: form.values,
+      });
+      ctx.setVisible(false);
+      await form.reset();
+      refresh();
+      await refreshCM();
+    },
+  };
+};
+
+export const SyncFieldsAction = (props) => {
+  const record = useRecord();
+  return <SyncFieldsActionCom item={record} {...props} />;
+};
+
+export const SyncFieldsActionCom = (props) => {
+  const { scope, getContainer, item: record, children } = props;
+  const [visible, setVisible] = useState(false);
+  const [schema, setSchema] = useState({});
+  const compile = useCompile();
+  const { t } = useTranslation();
+  return (
+    record.template === 'view' && (
+      <RecordProvider record={record}>
+        <ActionContext.Provider value={{ visible, setVisible }}>
+          {children || (
+            <Button
+              icon={<PlusOutlined />}
+              onClick={(e) => {
+                const schema = getSchema({}, record, compile);
+                if (schema) {
+                  setSchema(schema);
+                  setVisible(true);
+                }
+              }}
+            >
+              {t('Sync from database')}
+            </Button>
+          )}
+          <SchemaComponent
+            schema={schema}
+            components={{ ...components, ArrayTable }}
+            scope={{
+              getContainer,
+              useCancelAction,
+              createOnly: true,
+              isOverride: false,
+              useSyncFromDatabase,
+              record,
+              ...scope,
+            }}
+          />
+        </ActionContext.Provider>
+      </RecordProvider>
+    )
+  );
+};
diff --git a/packages/core/client/src/collection-manager/Configuration/index.tsx b/packages/core/client/src/collection-manager/Configuration/index.tsx
index c69d4c0ea..faec9c4f1 100644
--- a/packages/core/client/src/collection-manager/Configuration/index.tsx
+++ b/packages/core/client/src/collection-manager/Configuration/index.tsx
@@ -13,7 +13,8 @@ export * from './AddCollectionAction';
 export * from './EditCollectionAction';
 export * from './ConfigurationTabs';
 export * from './AddCategoryAction';
-export * from './EditCategoryAction'
+export * from './EditCategoryAction';
+export * from './SyncFieldsAction';
 
 registerValidateFormats({
   uid: /^[A-Za-z0-9][A-Za-z0-9_-]*$/,
diff --git a/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts b/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts
index fdfbdef60..41ce21c5c 100644
--- a/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts
+++ b/packages/core/client/src/collection-manager/Configuration/schemas/collectionFields.ts
@@ -73,7 +73,7 @@ export const collectionFieldSchema: ISchema = {
       params: {
         paginate: false,
         filter: {
-          'interface.$not': null,
+          $or: [{ 'interface.$not': null }, { 'options.source.$notEmpty': true }],
         },
         sort: ['sort'],
         // appends: ['uiSchema'],
@@ -106,6 +106,14 @@ export const collectionFieldSchema: ISchema = {
             },
           },
         },
+        syncfromDatabase: {
+          type: 'void',
+          title: '{{ t("Sync from database") }}',
+          'x-component': 'SyncFieldsAction',
+          'x-component-props': {
+            type: 'primary',
+          },
+        },
         create: {
           type: 'void',
           title: '{{ t("Add new") }}',
diff --git a/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts b/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts
index 4cdb3e03e..b2bed6ca1 100644
--- a/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts
+++ b/packages/core/client/src/collection-manager/Configuration/schemas/collections.ts
@@ -258,7 +258,8 @@ export const collectionTableSchema: ISchema = {
                       },
                       'x-reactions': (field) => {
                         const i = field.path.segments[1];
-                        const table = field.form.getValuesIn(`table.${i}`);
+                        const key = field.path.segments[0];
+                        const table = field.form.getValuesIn(`${key}.${i}`);
                         if (table) {
                           field.title = `${compile(table.title)} - ${compile('{{ t("Configure fields") }}')}`;
                         }
diff --git a/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts b/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts
index 85b63a1cf..d67f25d3b 100644
--- a/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts
+++ b/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts
@@ -62,7 +62,7 @@ export const useCollectionManager = () => {
     return getParents(name);
   };
 
-  const getChildrenCollections = (name) => {
+  const getChildrenCollections = (name, isSupportView = false) => {
     const children = [];
     const getChildren = (name) => {
       const inheritCollections = collections.filter((v) => {
@@ -73,6 +73,16 @@ export const useCollectionManager = () => {
         children.push(v);
         return getChildren(collectionKey);
       });
+      if (isSupportView) {
+        const sourceCollections = collections.filter((v) => {
+          return v.sources?.length === 1 && v?.sources[0] === name;
+        });
+        sourceCollections.forEach((v) => {
+          const collectionKey = v.name;
+          children.push(v);
+          return getChildren(collectionKey);
+        });
+      }
       return uniqBy(children, 'key');
     };
     return getChildren(name);
diff --git a/packages/core/client/src/collection-manager/interfaces/attachment.ts b/packages/core/client/src/collection-manager/interfaces/attachment.ts
index b36db1494..e816022e4 100644
--- a/packages/core/client/src/collection-manager/interfaces/attachment.ts
+++ b/packages/core/client/src/collection-manager/interfaces/attachment.ts
@@ -22,6 +22,7 @@ export const attachment: IField = {
       },
     },
   },
+  availableTypes:['belongsToMany'],
   schemaInitialize(schema: ISchema, { block }) {
     if (['Table', 'Kanban'].includes(block)) {
       schema['x-component-props'] = schema['x-component-props'] || {};
diff --git a/packages/core/client/src/collection-manager/interfaces/checkbox.ts b/packages/core/client/src/collection-manager/interfaces/checkbox.ts
index 3792a1794..6f3d783a1 100644
--- a/packages/core/client/src/collection-manager/interfaces/checkbox.ts
+++ b/packages/core/client/src/collection-manager/interfaces/checkbox.ts
@@ -15,6 +15,7 @@ export const checkbox: IField = {
       'x-component': 'Checkbox',
     },
   },
+  availableTypes: ['boolean'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/checkboxGroup.ts b/packages/core/client/src/collection-manager/interfaces/checkboxGroup.ts
index a59e33ac1..539a250e7 100644
--- a/packages/core/client/src/collection-manager/interfaces/checkboxGroup.ts
+++ b/packages/core/client/src/collection-manager/interfaces/checkboxGroup.ts
@@ -17,6 +17,7 @@ export const checkboxGroup: IField = {
       'x-component': 'Checkbox.Group',
     },
   },
+  availableTypes:['array'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/chinaRegion.ts b/packages/core/client/src/collection-manager/interfaces/chinaRegion.ts
index 7d8900cd3..6f4ab2d8c 100644
--- a/packages/core/client/src/collection-manager/interfaces/chinaRegion.ts
+++ b/packages/core/client/src/collection-manager/interfaces/chinaRegion.ts
@@ -34,6 +34,7 @@ export const chinaRegion: IField = {
       },
     },
   },
+  availableTypes:['belongsToMany'],
   initialize: (values: any) => {
     if (!values.through) {
       values.through = `t_${uid()}`;
diff --git a/packages/core/client/src/collection-manager/interfaces/createdAt.ts b/packages/core/client/src/collection-manager/interfaces/createdAt.ts
index 8d622cece..12b971b8b 100644
--- a/packages/core/client/src/collection-manager/interfaces/createdAt.ts
+++ b/packages/core/client/src/collection-manager/interfaces/createdAt.ts
@@ -20,6 +20,7 @@ export const createdAt: IField = {
       'x-read-pretty': true,
     },
   },
+  availableTypes:['date'],
   properties: {
     ...defaultProps,
     ...dateTimeProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/createdBy.ts b/packages/core/client/src/collection-manager/interfaces/createdBy.ts
index 8619fccc9..07b5569ad 100644
--- a/packages/core/client/src/collection-manager/interfaces/createdBy.ts
+++ b/packages/core/client/src/collection-manager/interfaces/createdBy.ts
@@ -28,6 +28,7 @@ export const createdBy: IField = {
       'x-read-pretty': true,
     },
   },
+  availableTypes:['belongsTo'],
   properties: {
     ...defaultProps,
   },
diff --git a/packages/core/client/src/collection-manager/interfaces/datetime.ts b/packages/core/client/src/collection-manager/interfaces/datetime.ts
index c21b630b5..52ced3434 100644
--- a/packages/core/client/src/collection-manager/interfaces/datetime.ts
+++ b/packages/core/client/src/collection-manager/interfaces/datetime.ts
@@ -20,6 +20,7 @@ export const datetime: IField = {
       },
     },
   },
+  availableTypes:['date'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/email.ts b/packages/core/client/src/collection-manager/interfaces/email.ts
index 05a21d33b..fa6a1a1b0 100644
--- a/packages/core/client/src/collection-manager/interfaces/email.ts
+++ b/packages/core/client/src/collection-manager/interfaces/email.ts
@@ -18,6 +18,7 @@ export const email: IField = {
       'x-validator': 'email',
     },
   },
+  availableTypes:['string'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/icon.ts b/packages/core/client/src/collection-manager/interfaces/icon.ts
index 3056375b4..fc19dc29a 100644
--- a/packages/core/client/src/collection-manager/interfaces/icon.ts
+++ b/packages/core/client/src/collection-manager/interfaces/icon.ts
@@ -16,6 +16,7 @@ export const icon: IField = {
       'x-component': 'IconPicker',
     },
   },
+  availableTypes:['string'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/id.ts b/packages/core/client/src/collection-manager/interfaces/id.ts
index 4a08ccdb8..e9bce1618 100644
--- a/packages/core/client/src/collection-manager/interfaces/id.ts
+++ b/packages/core/client/src/collection-manager/interfaces/id.ts
@@ -21,6 +21,7 @@ export const id: IField = {
       'x-read-pretty': true,
     },
   },
+  availableTypes:['bigInt','integer'],
   properties: {
     'uiSchema.title': {
       type: 'string',
diff --git a/packages/core/client/src/collection-manager/interfaces/input.ts b/packages/core/client/src/collection-manager/interfaces/input.ts
index d1d63307e..b1f76c86a 100644
--- a/packages/core/client/src/collection-manager/interfaces/input.ts
+++ b/packages/core/client/src/collection-manager/interfaces/input.ts
@@ -18,6 +18,7 @@ export const input: IField = {
       'x-component': 'Input',
     },
   },
+  availableTypes:['string'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/integer.ts b/packages/core/client/src/collection-manager/interfaces/integer.ts
index 792bef3c9..b8e51159d 100644
--- a/packages/core/client/src/collection-manager/interfaces/integer.ts
+++ b/packages/core/client/src/collection-manager/interfaces/integer.ts
@@ -29,6 +29,7 @@ export const integer: IField = {
       'x-validator': 'integer',
     },
   },
+  availableTypes:['bigInt','integer'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/json.ts b/packages/core/client/src/collection-manager/interfaces/json.ts
index 5943d80a0..bcb9d6907 100644
--- a/packages/core/client/src/collection-manager/interfaces/json.ts
+++ b/packages/core/client/src/collection-manager/interfaces/json.ts
@@ -39,6 +39,7 @@ export const json: IField = {
       default: null
     },
   },
+  availableTypes:['json','array'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/linkTo.ts b/packages/core/client/src/collection-manager/interfaces/linkTo.ts
index de8732852..b1492c531 100644
--- a/packages/core/client/src/collection-manager/interfaces/linkTo.ts
+++ b/packages/core/client/src/collection-manager/interfaces/linkTo.ts
@@ -45,6 +45,7 @@ export const linkTo: IField = {
       },
     },
   },
+  availableTypes:['belongsToMany'],
   schemaInitialize(schema: ISchema, { readPretty, block }) {
     if (block === 'Form') {
       if (schema['x-component'] === 'AssociationSelect') {
diff --git a/packages/core/client/src/collection-manager/interfaces/m2m.tsx b/packages/core/client/src/collection-manager/interfaces/m2m.tsx
index 2bc4c4c14..983de25f0 100644
--- a/packages/core/client/src/collection-manager/interfaces/m2m.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/m2m.tsx
@@ -51,6 +51,7 @@ export const m2m: IField = {
       },
     },
   },
+  availableTypes:['belongsToMany'],
   schemaInitialize(schema: ISchema, { readPretty, block }) {
     if (block === 'Form') {
       if (schema['x-component'] === 'AssociationSelect') {
diff --git a/packages/core/client/src/collection-manager/interfaces/m2o.tsx b/packages/core/client/src/collection-manager/interfaces/m2o.tsx
index 65268c3d8..d8ebdfbc5 100644
--- a/packages/core/client/src/collection-manager/interfaces/m2o.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/m2o.tsx
@@ -50,6 +50,7 @@ export const m2o: IField = {
       },
     },
   },
+  availableTypes:['belongsTo'],
   schemaInitialize(schema: ISchema, { block, readPretty }) {
     if (block === 'Form') {
       if (schema['x-component'] === 'AssociationSelect') {
diff --git a/packages/core/client/src/collection-manager/interfaces/markdown.ts b/packages/core/client/src/collection-manager/interfaces/markdown.ts
index 5788ce698..312b3caf5 100644
--- a/packages/core/client/src/collection-manager/interfaces/markdown.ts
+++ b/packages/core/client/src/collection-manager/interfaces/markdown.ts
@@ -17,6 +17,7 @@ export const markdown: IField = {
       'x-component': 'Markdown',
     },
   },
+  availableTypes:['text'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/multipleSelect.ts b/packages/core/client/src/collection-manager/interfaces/multipleSelect.ts
index 00c8b733e..44bcc1887 100644
--- a/packages/core/client/src/collection-manager/interfaces/multipleSelect.ts
+++ b/packages/core/client/src/collection-manager/interfaces/multipleSelect.ts
@@ -21,6 +21,7 @@ export const multipleSelect: IField = {
       enum: [],
     },
   },
+  availableTypes:['array'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/number.ts b/packages/core/client/src/collection-manager/interfaces/number.ts
index ca32bcdc5..2cdc7871f 100644
--- a/packages/core/client/src/collection-manager/interfaces/number.ts
+++ b/packages/core/client/src/collection-manager/interfaces/number.ts
@@ -22,6 +22,7 @@ export const number: IField = {
       },
     },
   },
+  availableTypes:['double'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/o2m.tsx b/packages/core/client/src/collection-manager/interfaces/o2m.tsx
index 5d2a0ef9b..006c0611a 100644
--- a/packages/core/client/src/collection-manager/interfaces/o2m.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/o2m.tsx
@@ -50,6 +50,7 @@ export const o2m: IField = {
       },
     },
   },
+  availableTypes:['hasMany'],
   schemaInitialize(schema: ISchema, { field, block, readPretty }) {
     if (block === 'Form') {
       if (schema['x-component'] === 'TableField') {
diff --git a/packages/core/client/src/collection-manager/interfaces/o2o.tsx b/packages/core/client/src/collection-manager/interfaces/o2o.tsx
index e69f5c863..4cfac495a 100644
--- a/packages/core/client/src/collection-manager/interfaces/o2o.tsx
+++ b/packages/core/client/src/collection-manager/interfaces/o2o.tsx
@@ -117,6 +117,7 @@ export const o2o: IField = {
       },
     },
   },
+  availableTypes:['hasOne'],
   schemaInitialize(schema: ISchema, { field, block, readPretty, action }) {
     internalSchameInitialize(schema, { field, block, readPretty, action });
     if (['Table', 'Kanban'].includes(block)) {
diff --git a/packages/core/client/src/collection-manager/interfaces/password.ts b/packages/core/client/src/collection-manager/interfaces/password.ts
index 7ff1fc680..22c475d6e 100644
--- a/packages/core/client/src/collection-manager/interfaces/password.ts
+++ b/packages/core/client/src/collection-manager/interfaces/password.ts
@@ -18,6 +18,7 @@ export const password: IField = {
       'x-component': 'Password',
     },
   },
+  availableTypes:['password'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/percent.ts b/packages/core/client/src/collection-manager/interfaces/percent.ts
index b06a1d52e..a2a680993 100644
--- a/packages/core/client/src/collection-manager/interfaces/percent.ts
+++ b/packages/core/client/src/collection-manager/interfaces/percent.ts
@@ -13,7 +13,7 @@ registerValidateRules({
         return {
           type: 'error',
           message: `${i18n.t('The field value cannot be greater than ')}${maxValue * 100}%`,
-        }
+        };
       }
     }
 
@@ -22,7 +22,7 @@ registerValidateRules({
         return {
           type: 'error',
           message: `${i18n.t('The field value cannot be less than ')}${minValue * 100}%`,
-        }
+        };
       }
     }
 
@@ -36,12 +36,12 @@ registerValidateRules({
       return {
         type: 'error',
         message: `${i18n.t('The field value is not an integer number')}`,
-      }
+      };
     }
 
     return true;
-  }
-})
+  },
+});
 
 // registerValidateFormats({
 //   percentInteger: /^(\d+)(.\d{0,2})?$/,
@@ -68,6 +68,7 @@ export const percent: IField = {
       },
     },
   },
+  availableTypes: ['float'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
@@ -104,7 +105,9 @@ export const percent: IField = {
         'x-reactions': `{{(field) => {
           const targetValue = field.query('.minimum').value();
           field.selfErrors =
-            !!targetValue && !!field.value && targetValue > field.value ? '${i18n.t('Maximum must greater than minimum')}' : ''
+            !!targetValue && !!field.value && targetValue > field.value ? '${i18n.t(
+              'Maximum must greater than minimum',
+            )}' : ''
         }}}`,
       },
       minValue: {
@@ -119,7 +122,9 @@ export const percent: IField = {
           dependencies: ['.maximum'],
           fulfill: {
             state: {
-              selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t('Minimum must less than maximum')}' : ''}}`,
+              selfErrors: `{{!!$deps[0] && !!$self.value && $deps[0] < $self.value ? '${i18n.t(
+                'Minimum must less than maximum',
+              )}' : ''}}`,
             },
           },
         },
@@ -132,10 +137,12 @@ export const percent: IField = {
         'x-component-props': {
           allowClear: true,
         },
-        enum: [{
-          label: '{{ t("Integer") }}',
-          value: 'Integer',
-        }]
+        enum: [
+          {
+            label: '{{ t("Integer") }}',
+            value: 'Integer',
+          },
+        ],
       },
       pattern: {
         type: 'string',
@@ -145,8 +152,8 @@ export const percent: IField = {
         'x-component-props': {
           prefix: '/',
           suffix: '/',
-        }
+        },
       },
     };
-  }
+  },
 };
diff --git a/packages/core/client/src/collection-manager/interfaces/phone.ts b/packages/core/client/src/collection-manager/interfaces/phone.ts
index 24055ca8c..491c49085 100644
--- a/packages/core/client/src/collection-manager/interfaces/phone.ts
+++ b/packages/core/client/src/collection-manager/interfaces/phone.ts
@@ -21,6 +21,7 @@ export const phone: IField = {
       // 'x-validator': 'phone',
     },
   },
+  availableTypes: ['string'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/radioGroup.ts b/packages/core/client/src/collection-manager/interfaces/radioGroup.ts
index a7205e3b3..5a097c732 100644
--- a/packages/core/client/src/collection-manager/interfaces/radioGroup.ts
+++ b/packages/core/client/src/collection-manager/interfaces/radioGroup.ts
@@ -17,6 +17,7 @@ export const radioGroup: IField = {
       'x-component': 'Radio.Group',
     },
   },
+  availableTypes: ['string'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/richText.ts b/packages/core/client/src/collection-manager/interfaces/richText.ts
index c10ba28a4..2f32ff1c8 100644
--- a/packages/core/client/src/collection-manager/interfaces/richText.ts
+++ b/packages/core/client/src/collection-manager/interfaces/richText.ts
@@ -18,6 +18,7 @@ export const richText: IField = {
       'x-component': 'RichText',
     },
   },
+  availableTypes: ['text'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/select.ts b/packages/core/client/src/collection-manager/interfaces/select.ts
index 26031e80e..7141c4c7d 100644
--- a/packages/core/client/src/collection-manager/interfaces/select.ts
+++ b/packages/core/client/src/collection-manager/interfaces/select.ts
@@ -18,6 +18,7 @@ export const select: IField = {
       enum: [],
     },
   },
+  availableTypes: ['string'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/subTable.ts b/packages/core/client/src/collection-manager/interfaces/subTable.ts
index 502bb1450..8689dec01 100644
--- a/packages/core/client/src/collection-manager/interfaces/subTable.ts
+++ b/packages/core/client/src/collection-manager/interfaces/subTable.ts
@@ -20,6 +20,7 @@ export const subTable: IField = {
       'x-component-props': {},
     },
   },
+  availableTypes: ['hasMany'],
   schemaInitialize(schema: ISchema, { field, readPretty }) {
     const association = `${field.collectionName}.${field.name}`;
     schema['type'] = 'void';
diff --git a/packages/core/client/src/collection-manager/interfaces/textarea.ts b/packages/core/client/src/collection-manager/interfaces/textarea.ts
index 3abf3888b..cf50e810c 100644
--- a/packages/core/client/src/collection-manager/interfaces/textarea.ts
+++ b/packages/core/client/src/collection-manager/interfaces/textarea.ts
@@ -18,6 +18,7 @@ export const textarea: IField = {
       'x-component': 'Input.TextArea',
     },
   },
+  availableTypes: ['text'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/time.ts b/packages/core/client/src/collection-manager/interfaces/time.ts
index 78a1f2bed..e1d6b08ea 100644
--- a/packages/core/client/src/collection-manager/interfaces/time.ts
+++ b/packages/core/client/src/collection-manager/interfaces/time.ts
@@ -16,6 +16,7 @@ export const time: IField = {
       'x-component': 'TimePicker',
     },
   },
+  availableTypes: ['time'],
   hasDefaultValue: true,
   properties: {
     ...defaultProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/updatedAt.ts b/packages/core/client/src/collection-manager/interfaces/updatedAt.ts
index 4498c5ee3..56bae4897 100644
--- a/packages/core/client/src/collection-manager/interfaces/updatedAt.ts
+++ b/packages/core/client/src/collection-manager/interfaces/updatedAt.ts
@@ -20,6 +20,7 @@ export const updatedAt: IField = {
       'x-read-pretty': true,
     },
   },
+  availableTypes: ['date'],
   properties: {
     ...defaultProps,
     ...dateTimeProps,
diff --git a/packages/core/client/src/collection-manager/interfaces/updatedBy.ts b/packages/core/client/src/collection-manager/interfaces/updatedBy.ts
index fdb0b934c..5b58133ae 100644
--- a/packages/core/client/src/collection-manager/interfaces/updatedBy.ts
+++ b/packages/core/client/src/collection-manager/interfaces/updatedBy.ts
@@ -27,6 +27,7 @@ export const updatedBy: IField = {
       'x-read-pretty': true,
     },
   },
+  availableTypes: ['belongsTo'],
   properties: {
     ...defaultProps,
   },
diff --git a/packages/core/client/src/collection-manager/templates/components/PreviewFields.tsx b/packages/core/client/src/collection-manager/templates/components/PreviewFields.tsx
new file mode 100644
index 000000000..0f27b521d
--- /dev/null
+++ b/packages/core/client/src/collection-manager/templates/components/PreviewFields.tsx
@@ -0,0 +1,216 @@
+import { Cascader } from '@formily/antd';
+import { useField, useForm } from '@formily/react';
+import { Input, Select, Spin, Table, Tag } from 'antd';
+import React, { useContext, useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { ResourceActionContext, useCompile } from '../../../';
+import { useAPIClient } from '../../../api-client';
+import { getOptions } from '../../Configuration/interfaces';
+import { useCollectionManager } from '../../hooks/useCollectionManager';
+
+const getInterfaceOptions = (data, type) => {
+  const interfaceOptions = [];
+  data.forEach((item) => {
+    const options = item.children.filter((h) => h?.availableTypes?.includes(type));
+    interfaceOptions.push({
+      label: item.label,
+      key: item.key,
+      children: options,
+    });
+  });
+  return interfaceOptions.filter((v) => v.children.length > 0);
+};
+const PreviewCom = (props) => {
+  const { name, sources, viewName, schema } = props;
+  const { data: fields } = useContext(ResourceActionContext);
+  const api = useAPIClient();
+  const { t } = useTranslation();
+  const [loading, setLoading] = useState(false);
+  const [dataSource, setDataSource] = useState([]);
+  const [sourceFields, setSourceFields] = useState([]);
+  const field: any = useField();
+  const form = useForm();
+  const { getCollection } = useCollectionManager();
+  const compile = useCompile();
+  const initOptions = getOptions().filter((v) => !['relation', 'systemInfo'].includes(v.key));
+  useEffect(() => {
+    const data = [];
+    sources.forEach((item) => {
+      const collection = getCollection(item);
+      const children = collection.fields?.map((v) => {
+        return { value: v.name, label: v.uiSchema?.title };
+      });
+      data.push({
+        value: item,
+        label: collection.title,
+        children,
+      });
+    });
+    setSourceFields(data);
+  }, [sources, name]);
+
+  useEffect(() => {
+    if (name) {
+      setLoading(true);
+      api
+        .resource(`dbViews`)
+        .get({ filterByTk: viewName, schema })
+        .then(({ data }) => {
+          if (data) {
+            setLoading(false);
+            setDataSource([]);
+            const fieldsData = Object.values(data?.data?.fields)?.map((v: any) => {
+              if (v.source) {
+                return v;
+              } else {
+                return fields?.data.find((h) => h.name === v.name) || v;
+              }
+            });
+            field.value = fieldsData;
+            setDataSource(fieldsData);
+            form.setValuesIn('sources', data.data?.sources);
+          }
+        });
+    }
+  }, [name]);
+
+  const handleFieldChange = (record, index) => {
+    dataSource.splice(index, 1, record);
+    setDataSource(dataSource);
+    field.value = dataSource.map((v) => {
+      return {
+        ...v,
+        source: typeof v.source === 'string' ? v.source : v.source?.join('.'),
+      };
+    });
+  };
+  const columns = [
+    {
+      title: t('Field name'),
+      dataIndex: 'name',
+      key: 'name',
+      width: 130,
+    },
+    {
+      title: t('Field source'),
+      dataIndex: 'source',
+      key: 'source',
+      width: 200,
+      render: (text, record, index) => {
+        return (
+          <Cascader
+            defaultValue={typeof text === 'string' ? text?.split('.') : text}
+            allowClear
+            style={{ width: '100%' }}
+            options={compile(sourceFields)}
+            onChange={(value, selectedOptions) => {
+              handleFieldChange({ ...record, source: value }, index);
+            }}
+            placeholder={t('Select field source')}
+          />
+        );
+      },
+    },
+    {
+      title: t('Field type'),
+      dataIndex: 'type',
+      width: 140,
+      key: 'type',
+      render: (text, _, index) => {
+        const item = dataSource[index];
+        return item?.source || !item?.possibleTypes ? (
+          <Tag>{text}</Tag>
+        ) : (
+          <Select
+            defaultValue={text}
+            style={{ width: '100%' }}
+            options={
+              item?.possibleTypes.map((v) => {
+                return { label: v, value: v };
+              }) || []
+            }
+            onChange={(value) => handleFieldChange({ ...item, type: value }, index)}
+          />
+        );
+      },
+    },
+    {
+      title: t('Field interface'),
+      dataIndex: 'interface',
+      key: 'interface',
+      width: 150,
+      render: (text, _, index) => {
+        const item = dataSource[index];
+        const data = getInterfaceOptions(initOptions, item.type);
+        return item.source ? (
+          text
+        ) : (
+          <Select
+            defaultValue={text}
+            style={{ width: '100%' }}
+            onChange={(value) => handleFieldChange({ ...item, interface: value }, index)}
+          >
+            {data.map((group) => (
+              <Select.OptGroup key={group.key} label={compile(group.label)}>
+                {group.children.map((item) => (
+                  <Select.Option key={item.value} value={item.value}>
+                    {compile(item.label)}
+                  </Select.Option>
+                ))}
+              </Select.OptGroup>
+            ))}
+          </Select>
+        );
+      },
+    },
+    {
+      title: t('Field display name'),
+      dataIndex: 'title',
+      key: 'title',
+      width: 180,
+      render: (text, record, index) => {
+        const item = dataSource[index];
+        return item.source ? (
+          record?.uiSchema?.title
+        ) : (
+          <Input
+            defaultValue={record?.uiSchema?.title}
+            onChange={(e) => handleFieldChange({ ...item, uiSchema: { title: e.target.value } }, index)}
+          />
+        );
+      },
+    },
+  ];
+  return (
+    <Spin spinning={loading}>
+      {dataSource.length > 0 && (
+        <>
+          <div className="ant-formily-item-label">
+            <div className="ant-formily-item-label-content">
+              <span>
+                <label>{t('Fields')}</label>
+              </span>
+            </div>
+            <span className="ant-formily-item-colon">:</span>
+          </div>
+          <Table
+            bordered
+            size={'middle'}
+            columns={columns}
+            dataSource={dataSource}
+            scroll={{ y: 300 }}
+            pagination={false}
+            rowClassName="editable-row"
+            key={name}
+          />
+        </>
+      )}
+    </Spin>
+  );
+};
+
+function areEqual(prevProps, nextProps) {
+  return nextProps.name === prevProps.name && nextProps.sources === prevProps.sources;
+}
+
+export const PreviewFields = React.memo(PreviewCom, areEqual);
diff --git a/packages/core/client/src/collection-manager/templates/components/PreviewTable.tsx b/packages/core/client/src/collection-manager/templates/components/PreviewTable.tsx
new file mode 100644
index 000000000..e9de3b70e
--- /dev/null
+++ b/packages/core/client/src/collection-manager/templates/components/PreviewTable.tsx
@@ -0,0 +1,105 @@
+import { RecursionField, useForm } from '@formily/react';
+import { Spin, Table } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { EllipsisWithTooltip, useCompile } from '../../../';
+import { useAPIClient } from '../../../api-client';
+import { useCollectionManager } from '../../hooks/useCollectionManager';
+
+export const PreviewTable = (props) => {
+  const { name, viewName, schema, fields } = props;
+  const [previewColumns, setPreviewColumns] = useState([]);
+  const [previewData, setPreviewData] = useState([]);
+  const compile = useCompile();
+  const [loading, setLoading] = useState(false);
+  const { getCollection, getCollectionField, getInterface } = useCollectionManager();
+  const api = useAPIClient();
+  const { t } = useTranslation();
+  const form = useForm();
+  useEffect(() => {
+    if (name) {
+      getPreviewData();
+    }
+  }, [name]);
+
+  useEffect(() => {
+    const pColumns = formatPreviewColumns(fields);
+    setPreviewColumns(pColumns);
+  }, [form.values.fields]);
+
+  const getPreviewData = () => {
+    setLoading(true);
+    api
+      .resource(`dbViews`)
+      .query({ filterByTk: viewName, schema })
+      .then(({ data }) => {
+        if (data) {
+          setLoading(false);
+          setPreviewData(data?.data || []);
+        }
+      });
+  };
+
+  const formatPreviewColumns = (data) => {
+    return data
+      .filter((k) => k.source || k.interface)
+      ?.map((item) => {
+        const fieldSource = typeof item?.source === 'string' ? item?.source?.split('.') : item?.source;
+        const sourceField = getCollection(fieldSource?.[0])?.fields.find((v) => v.name === fieldSource?.[1])?.uiSchema
+          ?.title;
+        const target = sourceField || item?.uiSchema?.title || item.name;
+        const schema: any = item.source
+          ? getCollectionField(typeof item.source === 'string' ? item.source : item.source.join('.'))?.uiSchema
+          : getInterface(item.interface)?.default?.uiSchema;
+        return {
+          title: compile(target),
+          dataIndex: item.name,
+          key: item.name,
+          width: 200,
+          render: (v, record, index) => {
+            const content = record[item.name];
+            const objSchema: any = {
+              type: 'object',
+              properties: {
+                [item.name]: { ...schema, default: content, 'x-read-pretty': true, title: null },
+              },
+            };
+            return (
+              <EllipsisWithTooltip ellipsis={true}>
+                <RecursionField schema={objSchema} name={index} onlyRenderProperties />
+              </EllipsisWithTooltip>
+            );
+          },
+        };
+      });
+  };
+  return (
+    <Spin spinning={loading}>
+      <div
+        style={{
+          marginBottom: 22,
+        }}
+      >
+        {previewColumns?.length > 0 && [
+          <div className="ant-formily-item-label" style={{ marginTop: 24 }}>
+            <div className="ant-formily-item-label-content">
+              <span>
+                <label>{t('Preview')}</label>
+              </span>
+            </div>
+            <span className="ant-formily-item-colon">:</span>
+          </div>,
+          <Table
+            size={'middle'}
+            pagination={false}
+            bordered
+            columns={previewColumns}
+            dataSource={previewData}
+            scroll={{ x: 1000, y: 300 }}
+            key={name}
+          />,
+        ]}
+      </div>
+    </Spin>
+  );
+};
diff --git a/packages/core/client/src/collection-manager/templates/index.tsx b/packages/core/client/src/collection-manager/templates/index.tsx
index 2bf123f94..236eab7b6 100644
--- a/packages/core/client/src/collection-manager/templates/index.tsx
+++ b/packages/core/client/src/collection-manager/templates/index.tsx
@@ -1,4 +1,4 @@
 export * from './calendar';
 export * from './general';
 export * from './tree';
-
+export * from './view';
diff --git a/packages/core/client/src/collection-manager/templates/types.ts b/packages/core/client/src/collection-manager/templates/types.ts
index 8528a463b..3d7753cc4 100644
--- a/packages/core/client/src/collection-manager/templates/types.ts
+++ b/packages/core/client/src/collection-manager/templates/types.ts
@@ -14,6 +14,8 @@ export interface ICollectionTemplate {
   configurableProperties?: Record<string, ISchema>;
   /** 当前模板可用的字段类型 */
   availableFieldInterfaces?: AvailableFieldInterfacesInclude | AvailableFieldInterfacesExclude;
+  /** 是否分割线 */
+  divider?: boolean;
 }
 
 interface AvailableFieldInterfacesInclude {
@@ -24,7 +26,6 @@ interface AvailableFieldInterfacesExclude {
   exclude?: any[];
 }
 
-
 interface CollectionOptions {
   /**
    * 自动生成 id
diff --git a/packages/core/client/src/collection-manager/templates/view.tsx b/packages/core/client/src/collection-manager/templates/view.tsx
new file mode 100644
index 000000000..5469e9863
--- /dev/null
+++ b/packages/core/client/src/collection-manager/templates/view.tsx
@@ -0,0 +1,106 @@
+import { getConfigurableProperties } from './properties';
+import { ICollectionTemplate } from './types';
+import { PreviewFields } from './components/PreviewFields';
+import { PreviewTable } from './components/PreviewTable';
+
+
+export const view: ICollectionTemplate = {
+  name: 'view',
+  title: '{{t("Connect to database view")}}',
+  order: 4,
+  color: 'yellow',
+  default: {
+    fields: [],
+  },
+  divider: true,
+  configurableProperties: {
+    title: {
+      type: 'string',
+      title: '{{ t("Collection display name") }}',
+      required: true,
+      'x-decorator': 'FormItem',
+      'x-component': 'Input',
+    },
+    name: {
+      title: '{{t("Connect to database view")}}',
+      type: 'single',
+      required: true,
+      'x-decorator': 'FormItem',
+      'x-component': 'Select',
+      'x-reactions': ['{{useAsyncDataSource(loadDBViews)}}'],
+      'x-disabled': '{{ !createOnly }}',
+    },
+    schema: {
+      type: 'string',
+      'x-hidden': true,
+      'x-reactions': {
+        dependencies: ['name'],
+        when: "{{isPG}}",
+        fulfill: {
+          state: {
+            value: "{{$deps[0].split('_')?.[0]}}",
+          },
+        },
+        otherwise: {
+          state: {
+            value: null,
+          },
+        },
+      },
+    },
+    viewName: {
+      type: 'string',
+      'x-hidden': true,
+      'x-reactions': {
+        dependencies: ['name'],
+        when: "{{isPG}}",
+        fulfill: {
+          state: {
+            value: '{{$deps[0].match(/^([^_]+)_(.*)$/)?.[2]}}',
+          },
+        },
+        otherwise: {
+          state: {
+            value: '{{$deps[0]}}',
+          },
+        },
+      },
+    },
+    sources: {
+      type: 'array',
+      title: '{{ t("Source collections") }}',
+      'x-decorator': 'FormItem',
+      'x-component': 'Select',
+      'x-component-props': {
+        multiple: true,
+      },
+      'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'],
+      'x-disabled': true,
+    },
+    fields: {
+      type: 'array',
+      'x-component': PreviewFields,
+      'x-reactions': {
+        dependencies: ['name'],
+        fulfill: {
+          schema: {
+            'x-component-props': '{{$form.values}}', //任意层次属性都支持表达式
+          },
+        },
+      },
+    },
+    preview: {
+      type: 'object',
+      'x-component': PreviewTable,
+      'x-reactions': {
+        dependencies: ['name','fields'],
+        fulfill: {
+          schema: {
+            'x-component-props': '{{$form.values}}', //任意层次属性都支持表达式
+          },
+        },
+      },
+    },
+    ...getConfigurableProperties('category'),
+  },
+};
diff --git a/packages/core/client/src/locale/en_US.ts b/packages/core/client/src/locale/en_US.ts
index 0d5310355..ea0cdbd5f 100644
--- a/packages/core/client/src/locale/en_US.ts
+++ b/packages/core/client/src/locale/en_US.ts
@@ -180,6 +180,10 @@ export default {
   "Collection template": "Collection template",
   "Calendar collection": "Calendar collection",
   "General collection": "General collection",
+  "Connect to database view":"Connect to database view",
+  "Source collections":"Source collections",
+  "Field source":"Field source",
+  "Preview":"Preview",
   "Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.": "Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.",
   "Storage type": "Storage type",
   "Edit": "Edit",
diff --git a/packages/core/client/src/locale/ja_JP.ts b/packages/core/client/src/locale/ja_JP.ts
index fd2bd17b2..ac4f34894 100644
--- a/packages/core/client/src/locale/ja_JP.ts
+++ b/packages/core/client/src/locale/ja_JP.ts
@@ -171,6 +171,10 @@ export default {
   "Collection template":"データテーブルテンプレート",
   "Calendar collection":"カレンダデータテーブル",
   "General collection":"一般データテーブル",
+  "Connect to database view":"ビューに接続",
+  "Source collections":"ソースデータセット",
+  "Field source":"ソースフィールド",
+  "Preview":"プレビュー",
   "Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.": "ランダムに生成され、変更可能です。 アルファベット、数字、アンダースコアをサポートし、アルファベットから始まる必要があります。",
   "Storage type": "ストレージタイプ",
   "Edit": "編集",
diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts
index 6eddcbbb1..968b33eca 100644
--- a/packages/core/client/src/locale/zh_CN.ts
+++ b/packages/core/client/src/locale/zh_CN.ts
@@ -188,6 +188,10 @@ export default {
   "Collection template": "数据表模板",
   "Calendar collection": "日历数据表",
   "General collection": "普通数据表",
+  "Connect to database view":"连接数据库视图",
+  "Source collections":"来源数据表",
+  "Field source":"来源字段",
+  "Preview":"预览",
   "Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.": "随机生成,可修改。支持英文、数字和下划线,必须以英文字母开头。",
   "Storage type": "存储类型",
   "Types will be used in database": "数据库使用的类型",
diff --git a/packages/core/client/src/schema-initializer/buttons/CalendarActionInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/CalendarActionInitializers.tsx
index 73f2cc587..9508b1cce 100644
--- a/packages/core/client/src/schema-initializer/buttons/CalendarActionInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/CalendarActionInitializers.tsx
@@ -1,3 +1,5 @@
+import { useCollection } from '../../';
+
 // 日历的操作配置
 export const CalendarActionInitializers = {
   title: '{{t("Configure actions")}}',
@@ -72,6 +74,10 @@ export const CalendarActionInitializers = {
               skipScopeCheck: true,
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
       ],
     },
diff --git a/packages/core/client/src/schema-initializer/buttons/CalendarFormActionInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/CalendarFormActionInitializers.tsx
index 6677f3d2e..f2caff05e 100644
--- a/packages/core/client/src/schema-initializer/buttons/CalendarFormActionInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/CalendarFormActionInitializers.tsx
@@ -1,3 +1,5 @@
+import { useCollection } from '../..';
+
 // 表单的操作配置
 export const CalendarFormActionInitializers = {
   title: '{{t("Configure actions")}}',
@@ -21,6 +23,10 @@ export const CalendarFormActionInitializers = {
               type: 'primary',
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -30,6 +36,10 @@ export const CalendarFormActionInitializers = {
             'x-component': 'Action',
             'x-decorator': 'ACLActionProvider',
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -39,6 +49,10 @@ export const CalendarFormActionInitializers = {
             'x-component': 'Action',
             'x-decorator': 'ACLActionProvider',
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -130,6 +144,10 @@ export const CalendarFormActionInitializers = {
               useProps: '{{ useCustomizeUpdateActionProps }}',
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -153,6 +171,10 @@ export const CalendarFormActionInitializers = {
               useProps: '{{ useCustomizeRequestActionProps }}',
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
       ],
     },
diff --git a/packages/core/client/src/schema-initializer/buttons/KanbanActionInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/KanbanActionInitializers.tsx
index ff22997c0..ad5e8c4a7 100644
--- a/packages/core/client/src/schema-initializer/buttons/KanbanActionInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/KanbanActionInitializers.tsx
@@ -1,3 +1,5 @@
+import { useCollection } from '../../';
+
 export const KanbanActionInitializers = {
   title: "{{t('Configure actions')}}",
   icon: 'SettingOutlined',
@@ -28,6 +30,10 @@ export const KanbanActionInitializers = {
               skipScopeCheck: true,
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
       ],
     },
diff --git a/packages/core/client/src/schema-initializer/buttons/ReadPrettyFormActionInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/ReadPrettyFormActionInitializers.tsx
index 18b686467..2cca7b01e 100644
--- a/packages/core/client/src/schema-initializer/buttons/ReadPrettyFormActionInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/ReadPrettyFormActionInitializers.tsx
@@ -1,3 +1,5 @@
+import { useCollection } from '../..';
+
 // 表单的操作配置
 export const ReadPrettyFormActionInitializers = {
   title: '{{t("Configure actions")}}',
@@ -21,6 +23,10 @@ export const ReadPrettyFormActionInitializers = {
               type: 'primary',
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -30,6 +36,10 @@ export const ReadPrettyFormActionInitializers = {
             'x-component': 'Action',
             'x-decorator': 'ACLActionProvider',
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -122,6 +132,10 @@ export const ReadPrettyFormActionInitializers = {
               useProps: '{{ useCustomizeUpdateActionProps }}',
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -145,6 +159,10 @@ export const ReadPrettyFormActionInitializers = {
               useProps: '{{ useCustomizeRequestActionProps }}',
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
       ],
     },
diff --git a/packages/core/client/src/schema-initializer/buttons/RecordBlockInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/RecordBlockInitializers.tsx
index 5e3608382..e0dd52a3a 100644
--- a/packages/core/client/src/schema-initializer/buttons/RecordBlockInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/RecordBlockInitializers.tsx
@@ -166,8 +166,11 @@ export const RecordBlockInitializers = (props: any) => {
   const { insertPosition, component, actionInitializers } = props;
   const collection = useCollection();
   const { getChildrenCollections } = useCollectionManager();
-  const childrenCollections = getChildrenCollections(collection.name);
-  const hasChildCollection = childrenCollections?.length > 0;
+  const formChildrenCollections = getChildrenCollections(collection.name);
+  const hasFormChildCollection = formChildrenCollections?.length > 0;
+  const detailChildrenCollections = getChildrenCollections(collection.name, true);
+  const hasDetailChildCollection = detailChildrenCollections?.length > 0;
+  const modifyFlag = (collection as any).template !== 'view';
   return (
     <SchemaInitializer.Button
       wrap={gridRowColWrap}
@@ -179,36 +182,43 @@ export const RecordBlockInitializers = (props: any) => {
         {
           type: 'itemGroup',
           title: '{{t("Current record blocks")}}',
-          children: hasChildCollection
-            ? [
-                {
+          children: [
+            hasDetailChildCollection
+              ? {
                   key: 'details',
                   type: 'subMenu',
                   title: '{{t("Details")}}',
-                  children: useDetailCollections({ ...props, childrenCollections, collection }),
-                },
-                {
-                  key: 'form',
-                  type: 'subMenu',
-                  title: '{{t("Form")}}',
-                  children: useFormCollections({ ...props, childrenCollections, collection }),
-                },
-              ]
-            : [
-                {
+                  children: useDetailCollections({
+                    ...props,
+                    childrenCollections: detailChildrenCollections,
+                    collection,
+                  }),
+                }
+              : {
                   key: 'details',
                   type: 'item',
                   title: '{{t("Details")}}',
                   component: 'RecordReadPrettyFormBlockInitializer',
                   actionInitializers,
                 },
-                {
+            hasFormChildCollection
+              ? {
+                  key: 'form',
+                  type: 'subMenu',
+                  title: '{{t("Form")}}',
+                  children: useFormCollections({
+                    ...props,
+                    childrenCollections: formChildrenCollections,
+                    collection,
+                  }),
+                }
+              : modifyFlag && {
                   key: 'form',
                   type: 'item',
                   title: '{{t("Form")}}',
                   component: 'RecordFormBlockInitializer',
                 },
-              ],
+          ],
         },
         {
           type: 'itemGroup',
diff --git a/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx
index 669d576a0..ba97bf8b3 100644
--- a/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/TableActionColumnInitializers.tsx
@@ -51,7 +51,8 @@ export const TableActionColumnInitializers = (props: any) => {
   const { refresh } = useDesignable();
   const { t } = useTranslation();
   const collection = useCollection();
-  const { treeTable } = fieldSchema?.parent?.parent['x-decorator-props']||{};
+  const { treeTable } = fieldSchema?.parent?.parent['x-decorator-props'] || {};
+  const modifyFlag = (collection as any).template !== 'view';
   return (
     <SchemaInitializer.Button
       insertPosition={'beforeEnd'}
@@ -98,8 +99,12 @@ export const TableActionColumnInitializers = (props: any) => {
                 'x-action': 'update',
                 'x-decorator': 'ACLActionProvider',
               },
+              visible: () => {
+                const collection = useCollection();
+                return (collection as any).template !== 'view';
+              },
             },
-            {
+            modifyFlag && {
               type: 'item',
               title: t('Delete'),
               component: 'DestroyActionInitializer',
@@ -202,6 +207,10 @@ export const TableActionColumnInitializers = (props: any) => {
                   useProps: '{{ useCustomizeUpdateActionProps }}',
                 },
               },
+              visible: () => {
+                const collection = useCollection();
+                return (collection as any).template !== 'view';
+              },
             },
             {
               type: 'item',
@@ -224,6 +233,10 @@ export const TableActionColumnInitializers = (props: any) => {
                   useProps: '{{ useCustomizeRequestActionProps }}',
                 },
               },
+              visible: () => {
+                const collection = useCollection();
+                return (collection as any).template !== 'view';
+              },
             },
           ],
         },
diff --git a/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx b/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx
index 40c6c493d..91e17308f 100644
--- a/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx
+++ b/packages/core/client/src/schema-initializer/buttons/TableActionInitializers.tsx
@@ -32,6 +32,10 @@ export const TableActionInitializers = {
               skipScopeCheck: true,
             },
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -41,6 +45,10 @@ export const TableActionInitializers = {
             'x-align': 'right',
             'x-decorator': 'ACLActionProvider',
           },
+          visible: () => {
+            const collection = useCollection();
+            return (collection as any).template !== 'view';
+          },
         },
         {
           type: 'item',
@@ -60,7 +68,7 @@ export const TableActionInitializers = {
           visible: () => {
             const schema = useFieldSchema();
             const collection = useCollection();
-            const { treeTable } = schema?.parent?.['x-decorator-props']||{};
+            const { treeTable } = schema?.parent?.['x-decorator-props'] || {};
             return collection.tree && treeTable !== false;
           },
         },
@@ -68,6 +76,10 @@ export const TableActionInitializers = {
     },
     {
       type: 'divider',
+      visible: () => {
+        const collection = useCollection();
+        return (collection as any).template !== 'view';
+      },
     },
     {
       type: 'item',
@@ -82,9 +94,17 @@ export const TableActionInitializers = {
         )?.[1];
         return resultSchema;
       },
+      visible: () => {
+        const collection = useCollection();
+        return (collection as any).template !== 'view';
+      },
     },
     {
       type: 'divider',
+      visible: () => {
+        const collection = useCollection();
+        return (collection as any).template !== 'view';
+      },
     },
     {
       type: 'subMenu',
@@ -135,6 +155,10 @@ export const TableActionInitializers = {
           },
         },
       ],
+      visible: () => {
+        const collection = useCollection();
+        return (collection as any).template !== 'view';
+      },
     },
   ],
 };
diff --git a/packages/core/client/src/schema-initializer/items/DetailsBlockInitializer.tsx b/packages/core/client/src/schema-initializer/items/DetailsBlockInitializer.tsx
index dd2bd7392..8907ef886 100644
--- a/packages/core/client/src/schema-initializer/items/DetailsBlockInitializer.tsx
+++ b/packages/core/client/src/schema-initializer/items/DetailsBlockInitializer.tsx
@@ -1,9 +1,9 @@
-import React from "react";
+import React from 'react';
 import { TableOutlined } from '@ant-design/icons';
 
-import { useCollectionManager } from "../../collection-manager";
-import { createDetailsBlockSchema } from "../utils";
-import { DataBlockInitializer } from "./DataBlockInitializer";
+import { useCollectionManager } from '../../collection-manager';
+import { createDetailsBlockSchema } from '../utils';
+import { DataBlockInitializer } from './DataBlockInitializer';
 
 export const DetailsBlockInitializer = (props) => {
   const { insert } = props;
@@ -15,7 +15,11 @@ export const DetailsBlockInitializer = (props) => {
       componentType={'Details'}
       onCreateBlockSchema={async ({ item }) => {
         const collection = getCollection(item.name);
-        const schema = createDetailsBlockSchema({ collection: item.name, rowKey: collection.filterTargetKey || 'id' });
+        const schema = createDetailsBlockSchema({
+          collection: item.name,
+          rowKey: collection.filterTargetKey || 'id',
+          actionInitializers: collection.template !== 'view' && 'DetailsActionInitializers',
+        });
         insert(schema);
       }}
     />
diff --git a/packages/core/client/src/schema-initializer/items/TableBlockInitializer.tsx b/packages/core/client/src/schema-initializer/items/TableBlockInitializer.tsx
index 71004f942..bb74cfb15 100644
--- a/packages/core/client/src/schema-initializer/items/TableBlockInitializer.tsx
+++ b/packages/core/client/src/schema-initializer/items/TableBlockInitializer.tsx
@@ -1,9 +1,8 @@
-import React from "react";
+import React from 'react';
 import { TableOutlined } from '@ant-design/icons';
-
-import { useCollectionManager } from "../../collection-manager";
-import { DataBlockInitializer } from "./DataBlockInitializer";
-import { createTableBlockSchema } from "../utils";
+import { useCollectionManager } from '../../collection-manager';
+import { DataBlockInitializer } from './DataBlockInitializer';
+import { createTableBlockSchema } from '../utils';
 
 export const TableBlockInitializer = (props) => {
   const { insert } = props;
@@ -15,7 +14,10 @@ export const TableBlockInitializer = (props) => {
       componentType={'Table'}
       onCreateBlockSchema={async ({ item }) => {
         const collection = getCollection(item.name);
-        const schema = createTableBlockSchema({ collection: item.name, rowKey: collection.filterTargetKey || 'id' });
+        const schema = createTableBlockSchema({
+          collection: item.name,
+          rowKey: collection.filterTargetKey || 'id',
+        });
         insert(schema);
       }}
     />
diff --git a/packages/core/client/src/schema-initializer/utils.ts b/packages/core/client/src/schema-initializer/utils.ts
index 5f37f5def..ada43660d 100644
--- a/packages/core/client/src/schema-initializer/utils.ts
+++ b/packages/core/client/src/schema-initializer/utils.ts
@@ -705,6 +705,8 @@ export const useCollectionDataSourceItems = (componentName) => {
             return false;
           } else if (item.autoGenId === false && !item.fields.find((v) => v.primaryKey)) {
             return false;
+          } else if (['Kanban', 'FormItem'].includes(componentName) && item.template === 'view') {
+            return false;
           } else {
             return b && !(item?.isThrough && item?.autoCreate);
           }
diff --git a/packages/core/database/src/__tests__/repository.test.ts b/packages/core/database/src/__tests__/repository.test.ts
index 6af56a3ff..060a1d434 100644
--- a/packages/core/database/src/__tests__/repository.test.ts
+++ b/packages/core/database/src/__tests__/repository.test.ts
@@ -311,6 +311,20 @@ describe('repository.update', () => {
       name: 'post1',
       userId: user.id,
     });
+
+    await User.repository.update({
+      filterByTk: user.id,
+      values: {
+        posts: [{ name: 'post2' }, { name: 'post3' }],
+      },
+    });
+
+    const updated2 = await User.repository.findOne({
+      filterByTk: user.id,
+      appends: ['posts'],
+    });
+
+    expect(updated2.posts.length).toBe(2);
   });
 
   it('update2', async () => {
diff --git a/packages/core/database/src/__tests__/sql-parser.test.ts b/packages/core/database/src/__tests__/sql-parser.test.ts
new file mode 100644
index 000000000..d0bbb2745
--- /dev/null
+++ b/packages/core/database/src/__tests__/sql-parser.test.ts
@@ -0,0 +1,13 @@
+import sqlParser from '../sql-parser';
+
+describe('sql parser', () => {
+  it('should parse sql', function () {
+    const sql = `select users.id as id from users`;
+    const { ast } = sqlParser.parse(sql);
+    const columns = ast.columns;
+    const firstColumn = columns[0];
+
+    expect(firstColumn['expr']['table']).toEqual('users');
+    expect(firstColumn['expr']['column']).toEqual('id');
+  });
+});
diff --git a/packages/core/database/src/__tests__/view/list-view.test.ts b/packages/core/database/src/__tests__/view/list-view.test.ts
new file mode 100644
index 000000000..3b218c0de
--- /dev/null
+++ b/packages/core/database/src/__tests__/view/list-view.test.ts
@@ -0,0 +1,34 @@
+import { Database, mockDatabase } from '@nocobase/database';
+
+describe('list view', () => {
+  let db: Database;
+
+  beforeEach(async () => {
+    db = mockDatabase({
+      tablePrefix: '',
+    });
+    await db.clean({ drop: true });
+  });
+
+  afterEach(async () => {
+    await db.close();
+  });
+
+  it('should list view', async () => {
+    const dropViewSQL1 = `DROP VIEW IF EXISTS test1`;
+    await db.sequelize.query(dropViewSQL1);
+
+    const dropViewSQL2 = `DROP VIEW IF EXISTS test2`;
+    await db.sequelize.query(dropViewSQL2);
+
+    const sql1 = `CREATE VIEW test1 AS SELECT 1`;
+    const sql2 = `CREATE VIEW test2 AS SELECT 2`;
+
+    await db.sequelize.query(sql1);
+    await db.sequelize.query(sql2);
+
+    const results = await db.queryInterface.listViews();
+    expect(results.find((item) => item.name === 'test1')).toBeTruthy();
+    expect(results.find((item) => item.name === 'test2')).toBeTruthy();
+  });
+});
diff --git a/packages/core/database/src/__tests__/view/view-collection.test.ts b/packages/core/database/src/__tests__/view/view-collection.test.ts
new file mode 100644
index 000000000..14f3c694c
--- /dev/null
+++ b/packages/core/database/src/__tests__/view/view-collection.test.ts
@@ -0,0 +1,199 @@
+import { Database, mockDatabase } from '@nocobase/database';
+import { uid } from '@nocobase/utils';
+import { ViewCollection } from '../../view-collection';
+
+describe('create view', () => {
+  let db: Database;
+
+  beforeEach(async () => {
+    db = mockDatabase({
+      tablePrefix: '',
+    });
+    await db.clean({ drop: true });
+  });
+
+  afterEach(async () => {
+    await db.close();
+  });
+
+  it('should create view collection in difference schema', async () => {
+    if (!db.inDialect('postgres')) return;
+    const schemaName = `t_${uid(6)}`;
+    const testSchemaSql = `CREATE SCHEMA IF NOT EXISTS ${schemaName};`;
+    await db.sequelize.query(testSchemaSql);
+
+    const viewName = 'test_view';
+
+    const viewSQL = `CREATE OR REPLACE VIEW ${schemaName}.test_view AS SELECT 1+1 as result`;
+    await db.sequelize.query(viewSQL);
+
+    const viewCollection = db.collection({
+      name: viewName,
+      schema: schemaName,
+      view: true,
+      fields: [
+        {
+          type: 'string',
+          name: 'result',
+        },
+      ],
+    });
+
+    const results = await viewCollection.repository.find();
+
+    expect(results.length).toBe(1);
+  });
+
+  it('should create view collection', async () => {
+    const UserCollection = db.collection({
+      name: 'users',
+      fields: [
+        {
+          type: 'string',
+          name: 'name',
+        },
+        {
+          type: 'hasOne',
+          name: 'profile',
+          foreignKey: 'user_id',
+        },
+      ],
+    });
+
+    const ProfileCollection = db.collection({
+      name: 'profiles',
+      fields: [
+        {
+          type: 'integer',
+          name: 'age',
+        },
+        {
+          type: 'belongsTo',
+          name: 'user',
+          foreignKey: 'user_id',
+        },
+      ],
+    });
+
+    await db.sync();
+
+    await UserCollection.repository.create({
+      values: {
+        name: 'foo',
+        profile: {
+          age: 18,
+        },
+      },
+    });
+    const schema = UserCollection.collectionSchema();
+    const viewName = 'users_with_profile';
+
+    const appendSchema = db.inDialect('postgres') ? `"${schema}".` : '';
+
+    const dropViewSQL = `DROP VIEW IF EXISTS ${appendSchema}${viewName}`;
+    await db.sequelize.query(dropViewSQL);
+    const viewSql = `CREATE  VIEW ${appendSchema}${viewName} AS SELECT users.name, profiles.age FROM ${appendSchema}${UserCollection.model.tableName} as users LEFT JOIN ${appendSchema}${ProfileCollection.model.tableName} as profiles ON users.id = profiles.user_id;`;
+
+    await db.sequelize.query(viewSql);
+
+    db.collection({
+      name: viewName,
+      view: true,
+      fields: [
+        {
+          type: 'string',
+          name: 'name',
+        },
+        {
+          type: 'integer',
+          name: 'age',
+        },
+      ],
+    });
+    const UserWithProfileView = db.getCollection(viewName);
+    expect(UserWithProfileView).toBeInstanceOf(ViewCollection);
+
+    const fooData = await UserWithProfileView.repository.findOne({
+      filter: {
+        name: 'foo',
+      },
+    });
+
+    console.log(fooData);
+    expect(fooData.get('name')).toBe('foo');
+    expect(fooData.get('age')).toBe(18);
+  });
+
+  it('should not sync view collection', async () => {
+    const dropViewSQL = `DROP VIEW IF EXISTS test_view`;
+    await db.sequelize.query(dropViewSQL);
+
+    const viewSql = `CREATE VIEW test_view AS SELECT 1+1 as result`;
+
+    await db.sequelize.query(viewSql);
+    const viewCollection = db.collection({
+      name: 'view_collection',
+      viewName: 'test_view',
+      fields: [
+        {
+          type: 'string',
+          name: 'result',
+        },
+      ],
+    });
+
+    const jestFn = jest.fn();
+
+    db.on('beforeSync', jestFn);
+
+    await viewCollection.sync();
+    expect(jestFn).not.toBeCalled();
+  });
+
+  it('should create view collection with source field options', async () => {
+    const UserCollection = db.collection({
+      name: 'users',
+      fields: [
+        {
+          name: 'name',
+          type: 'string',
+          patterns: [
+            {
+              type: 'integer',
+              options: { key: 1 },
+            },
+          ],
+        },
+      ],
+    });
+
+    await db.sync();
+
+    const viewName = 'users_view';
+
+    const dropViewSQL = `DROP VIEW IF EXISTS ${viewName}`;
+    await db.sequelize.query(dropViewSQL);
+
+    const viewSQL = `
+       CREATE VIEW ${viewName} as SELECT users.* FROM ${UserCollection.quotedTableName()} as users
+    `;
+
+    await db.sequelize.query(viewSQL);
+
+    // create view collection
+    const ViewCollection = db.collection({
+      name: viewName,
+      view: true,
+      fields: [
+        {
+          name: 'name',
+          type: 'string',
+          source: 'users.name',
+        },
+      ],
+    });
+
+    const viewNameField = ViewCollection.getField('name');
+    expect(viewNameField.options.patterns).toEqual(UserCollection.getField('name').options.patterns);
+  });
+});
diff --git a/packages/core/database/src/__tests__/view/view-inference.test.ts b/packages/core/database/src/__tests__/view/view-inference.test.ts
new file mode 100644
index 000000000..f5e9f5052
--- /dev/null
+++ b/packages/core/database/src/__tests__/view/view-inference.test.ts
@@ -0,0 +1,103 @@
+import { Database, mockDatabase } from '@nocobase/database';
+import { ViewFieldInference } from '../../view/view-inference';
+
+describe('view inference', function () {
+  let db: Database;
+
+  beforeEach(async () => {
+    db = mockDatabase({
+      tablePrefix: '',
+    });
+    await db.clean({ drop: true });
+  });
+
+  afterEach(async () => {
+    await db.close();
+  });
+
+  it('should infer collection fields', async () => {
+    const UserCollection = db.collection({
+      name: 'users',
+      fields: [
+        {
+          name: 'name',
+          type: 'string',
+          interface: 'test',
+        },
+        {
+          name: 'age',
+          type: 'integer',
+          interface: 'test',
+        },
+        {
+          name: 'profile',
+          type: 'json',
+          interface: 'test',
+        },
+        {
+          name: 'posts',
+          type: 'hasMany',
+          interface: 'test',
+        },
+      ],
+    });
+
+    const PostCollection = db.collection({
+      name: 'posts',
+      fields: [
+        {
+          name: 'title',
+          type: 'string',
+          interface: 'test',
+        },
+        {
+          name: 'user',
+          type: 'belongsTo',
+          interface: 'test',
+        },
+      ],
+    });
+
+    await db.sync();
+
+    const viewName = 'user_posts';
+
+    const dropViewSQL = `DROP VIEW IF EXISTS ${viewName}`;
+    await db.sequelize.query(dropViewSQL);
+
+    const viewSQL = `
+       CREATE VIEW ${viewName} as SELECT 1 as const_field, users.* FROM ${UserCollection.quotedTableName()} as users
+    `;
+
+    await db.sequelize.query(viewSQL);
+
+    const inferredFields = await ViewFieldInference.inferFields({
+      db,
+      viewName,
+      viewSchema: 'public',
+    });
+
+    const createdAt = UserCollection.model.rawAttributes['createdAt'].field;
+    expect(inferredFields[createdAt]['type']).toBe('date');
+
+    if (db.options.dialect == 'sqlite') {
+      expect(inferredFields['name']).toMatchObject({
+        name: 'name',
+        type: 'string',
+      });
+    } else {
+      expect(inferredFields['name']).toMatchObject({
+        name: 'name',
+        type: 'string',
+        source: 'users.name',
+      });
+
+      expect(inferredFields['const_field']).toMatchObject({
+        name: 'const_field',
+        type: 'integer',
+      });
+    }
+
+    await db.sequelize.query(dropViewSQL);
+  });
+});
diff --git a/packages/core/database/src/__tests__/view/view-repository.test.ts b/packages/core/database/src/__tests__/view/view-repository.test.ts
new file mode 100644
index 000000000..66dd29c03
--- /dev/null
+++ b/packages/core/database/src/__tests__/view/view-repository.test.ts
@@ -0,0 +1,67 @@
+import { Database, mockDatabase } from '@nocobase/database';
+import { uid } from '@nocobase/utils';
+
+describe('view repository', () => {
+  let db: Database;
+
+  beforeEach(async () => {
+    db = mockDatabase({
+      tablePrefix: '',
+    });
+    await db.clean({ drop: true });
+  });
+
+  afterEach(async () => {
+    await db.close();
+  });
+
+  it('should support find view without primary key', async () => {
+    const UserCollection = await db.collection({
+      name: 'users',
+      fields: [
+        {
+          type: 'string',
+          name: 'name',
+        },
+      ],
+    });
+
+    await db.sync();
+
+    await UserCollection.repository.create({
+      values: [{ name: 'a' }, { name: 'b' }, { name: 'c' }, { name: 'd' }],
+    });
+
+    const viewName = `t_${uid(6)}`;
+    const dropSQL = `DROP VIEW IF EXISTS ${viewName};`;
+    await db.sequelize.query(dropSQL);
+
+    const viewSQL = `CREATE VIEW ${viewName} AS select id as aaa, name from ${UserCollection.quotedTableName()}`;
+
+    await db.sequelize.query(viewSQL);
+
+    const viewCollection = db.collection({
+      name: viewName,
+      view: true,
+      schema: db.inDialect('postgres') ? 'public' : undefined,
+      fields: [
+        {
+          type: 'string',
+          name: 'name',
+        },
+        {
+          type: 'integer',
+          name: 'aaa',
+        },
+      ],
+    });
+
+    const results = await viewCollection.repository.findAndCount({
+      offset: 1,
+      limit: 1,
+    });
+
+    expect(results[0].length).toBe(1);
+    expect(results[1]).toBe(4);
+  });
+});
diff --git a/packages/core/database/src/collection.ts b/packages/core/database/src/collection.ts
index aca9aa543..f65973479 100644
--- a/packages/core/database/src/collection.ts
+++ b/packages/core/database/src/collection.ts
@@ -34,6 +34,8 @@ export interface CollectionOptions extends Omit<ModelOptions, 'name' | 'hooks'>
 
   tableName?: string;
   inherits?: string[] | string;
+  viewName?: string;
+
   filterTargetKey?: string;
   fields?: FieldOptions[];
   model?: string | ModelStatic<Model>;
@@ -69,7 +71,12 @@ export class Collection<
   repository: Repository<TModelAttributes, TCreationAttributes>;
 
   get filterTargetKey() {
-    return lodash.get(this.options, 'filterTargetKey', this.model.primaryKeyAttribute);
+    let targetKey = lodash.get(this.options, 'filterTargetKey', this.model.primaryKeyAttribute);
+    if (!targetKey && this.model.rawAttributes['id']) {
+      return 'id';
+    }
+
+    return targetKey;
   }
 
   get name() {
@@ -111,7 +118,11 @@ export class Collection<
     this.modelInit();
 
     this.db.modelCollection.set(this.model, this);
-    this.db.tableNameCollectionMap.set(this.model.tableName, this);
+
+    // set tableName to collection map
+    // the form of key is `${schema}.${tableName}` if schema exists
+    // otherwise is `${tableName}`
+    this.db.tableNameCollectionMap.set(this.getTableNameWithSchemaAsString(), this);
 
     if (!options.inherits) {
       this.setFields(options.fields);
@@ -141,7 +152,7 @@ export class Collection<
     return this.db.options.underscored ? snakeCase(tName) : tName;
   }
 
-  private sequelizeModelOptions() {
+  protected sequelizeModelOptions() {
     const { name } = this.options;
     return {
       ..._.omit(this.options, ['name', 'fields', 'model', 'targetKey']),
@@ -261,6 +272,17 @@ export class Collection<
     this.checkFieldType(name, options);
 
     const { database } = this.context;
+
+    if (options.source) {
+      const [sourceCollectionName, sourceFieldName] = options.source.split('.');
+      const sourceCollection = this.db.collections.get(sourceCollectionName);
+      if (!sourceCollection) {
+        throw new Error(`source collection "${sourceCollectionName}" not found`);
+      }
+      const sourceField = sourceCollection.fields.get(sourceFieldName);
+      options = { ...sourceField.options, ...options };
+    }
+
     this.emit('field.beforeAdd', name, options, { collection: this });
 
     const field = database.buildField(
@@ -334,9 +356,10 @@ export class Collection<
 
   async removeFromDb(options?: QueryInterfaceDropTableOptions) {
     if (
-      await this.existsInDb({
+      !this.isView() &&
+      (await this.existsInDb({
         transaction: options?.transaction,
-      })
+      }))
     ) {
       const queryInterface = this.db.sequelize.getQueryInterface();
       await queryInterface.dropTable(this.getTableNameWithSchema(), options);
@@ -575,13 +598,23 @@ export class Collection<
   public getTableNameWithSchema() {
     const tableName = this.model.tableName;
 
-    if (this.collectionSchema()) {
+    if (this.collectionSchema() && this.db.inDialect('postgres')) {
       return this.db.utils.addSchema(tableName, this.collectionSchema());
     }
 
     return tableName;
   }
 
+  public getTableNameWithSchemaAsString() {
+    const tableName = this.model.tableName;
+
+    if (this.collectionSchema() && this.db.inDialect('postgres')) {
+      return `${this.collectionSchema()}.${tableName}`;
+    }
+
+    return tableName;
+  }
+
   public quotedTableName() {
     return this.db.utils.quoteTable(this.getTableNameWithSchema());
   }
@@ -601,4 +634,8 @@ export class Collection<
 
     return undefined;
   }
+
+  public isView() {
+    return false;
+  }
 }
diff --git a/packages/core/database/src/database-utils/index.ts b/packages/core/database/src/database-utils/index.ts
index 8e2d656c8..46c3906b8 100644
--- a/packages/core/database/src/database-utils/index.ts
+++ b/packages/core/database/src/database-utils/index.ts
@@ -5,6 +5,7 @@ export default class DatabaseUtils {
   constructor(public db: Database) {}
 
   addSchema(tableName, schema?) {
+    if (!this.db.inDialect('postgres')) return tableName;
     if (this.db.options.schema && !schema) {
       schema = this.db.options.schema;
     }
diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts
index 33c10d76d..5e8a66af1 100644
--- a/packages/core/database/src/database.ts
+++ b/packages/core/database/src/database.ts
@@ -15,7 +15,7 @@ import {
   Sequelize,
   SyncOptions,
   Transactionable,
-  Utils
+  Utils,
 } from 'sequelize';
 import { SequelizeStorage, Umzug } from 'umzug';
 import { Collection, CollectionOptions, RepositoryType } from './collection';
@@ -58,7 +58,7 @@ import {
   SyncListener,
   UpdateListener,
   UpdateWithAssociationsListener,
-  ValidateListener
+  ValidateListener,
 } from './types';
 import { patchSequelizeQueryInterface, snakeCase } from './utils';
 
@@ -69,6 +69,7 @@ import buildQueryInterface from './query-interface/query-interface-builder';
 import QueryInterface from './query-interface/query-interface';
 import { Logger } from '@nocobase/logger';
 import { CollectionGroupManager } from './collection-group-manager';
+import { ViewCollection } from './view-collection';
 
 export interface MergeOptions extends merge.Options {}
 
@@ -221,7 +222,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
     }
     this.options = opts;
 
-    this.sequelize = new Sequelize(opts);
+    this.sequelize = new Sequelize(this.sequelizeOptions(this.options));
 
     this.queryInterface = buildQueryInterface(this);
 
@@ -297,6 +298,17 @@ export class Database extends EventEmitter implements AsyncEmitter {
     this.logger = logger;
   }
 
+  sequelizeOptions(options) {
+    if (options.dialect === 'postgres') {
+      options.hooks = {
+        afterConnect: async (connection) => {
+          await connection.query('SET search_path TO public;');
+        },
+      };
+    }
+    return options;
+  }
+
   initListener() {
     this.on('beforeDefine', (model, options) => {
       if (this.options.underscored) {
@@ -416,14 +428,21 @@ export class Database extends EventEmitter implements AsyncEmitter {
       return options.inherits && lodash.castArray(options.inherits).length > 0;
     })();
 
-    const collection = hasValidInheritsOptions
-      ? new InheritedCollection(options, {
-          database: this,
-        })
-      : new Collection(options, {
-          database: this,
-        });
+    const hasViewOptions = options.viewName || options.view;
 
+    const collectionKlass = (() => {
+      if (hasValidInheritsOptions) {
+        return InheritedCollection;
+      }
+
+      if (hasViewOptions) {
+        return ViewCollection;
+      }
+
+      return Collection;
+    })();
+
+    const collection = new collectionKlass(options, { database: this });
     this.collections.set(collection.name, collection);
 
     this.emit('afterDefineCollection', collection);
@@ -647,7 +666,7 @@ export class Database extends EventEmitter implements AsyncEmitter {
       return;
     }
 
-    await this.sequelize.getQueryInterface().dropAllTables(others);
+    await this.queryInterface.dropAll(options);
   }
 
   async collectionExistsInDb(name: string, options?: Transactionable) {
diff --git a/packages/core/database/src/fields/field.ts b/packages/core/database/src/fields/field.ts
index e78e391e1..8011a44bf 100644
--- a/packages/core/database/src/fields/field.ts
+++ b/packages/core/database/src/fields/field.ts
@@ -157,6 +157,11 @@ export abstract class Field {
     //   return;
     // }
 
+    if (this.collection.isView()) {
+      this.remove();
+      return;
+    }
+
     const columnReferencesCount = _.filter(
       this.collection.model.rawAttributes,
       (attr) => attr.field == this.columnName(),
@@ -232,6 +237,7 @@ export abstract class Field {
     if (this.dataType) {
       Object.assign(opts, { type: this.dataType });
     }
+
     return opts;
   }
 
diff --git a/packages/core/database/src/fields/json-field.ts b/packages/core/database/src/fields/json-field.ts
index 19ea21cdb..a1b89be2f 100644
--- a/packages/core/database/src/fields/json-field.ts
+++ b/packages/core/database/src/fields/json-field.ts
@@ -20,6 +20,7 @@ export class JsonbField extends Field {
     return DataTypes.JSON;
   }
 }
+
 export interface JsonbFieldOptions extends BaseColumnFieldOptions {
   type: 'jsonb';
 }
diff --git a/packages/core/database/src/index.ts b/packages/core/database/src/index.ts
index d379a4676..3162fad03 100644
--- a/packages/core/database/src/index.ts
+++ b/packages/core/database/src/index.ts
@@ -21,3 +21,5 @@ export * from './update-associations';
 export { snakeCase } from './utils';
 export * from './value-parsers';
 export * from './collection-group-manager';
+export * from './view-collection';
+export * from './view/view-inference';
diff --git a/packages/core/database/src/mock-database.ts b/packages/core/database/src/mock-database.ts
index 137f7a927..7abc8b4b5 100644
--- a/packages/core/database/src/mock-database.ts
+++ b/packages/core/database/src/mock-database.ts
@@ -14,7 +14,7 @@ export class MockDatabase extends Database {
 }
 
 export function getConfigByEnv() {
-  return {
+  const options = {
     username: process.env.DB_USER,
     password: process.env.DB_PASSWORD,
     database: process.env.DB_DATABASE,
@@ -33,10 +33,14 @@ export function getConfigByEnv() {
     timezone: process.env.DB_TIMEZONE,
     underscored: process.env.DB_UNDERSCORED === 'true',
     schema: process.env.DB_SCHEMA !== 'public' ? process.env.DB_SCHEMA : undefined,
-    dialectOptions: {
-      application_name: process.env.DB_DIALECT == 'postgres' ? 'nocobase.main' : undefined,
-    },
+    dialectOptions: {},
   };
+
+  if (process.env.DB_DIALECT == 'postgres') {
+    options.dialectOptions['application_name'] = 'nocobase.main';
+  }
+
+  return options;
 }
 
 function customLogger(queryString, queryObject) {
diff --git a/packages/core/database/src/model.ts b/packages/core/database/src/model.ts
index e5224f8b9..c549e09a1 100644
--- a/packages/core/database/src/model.ts
+++ b/packages/core/database/src/model.ts
@@ -151,6 +151,10 @@ export class Model<TModelAttributes extends {} = any, TCreationAttributes extend
   }
 
   static async sync(options) {
+    if (this.collection.isView()) {
+      return;
+    }
+
     const model = this as any;
 
     const _schema = model._schema;
diff --git a/packages/core/database/src/options-parser.ts b/packages/core/database/src/options-parser.ts
index 26c45061e..343b34b46 100644
--- a/packages/core/database/src/options-parser.ts
+++ b/packages/core/database/src/options-parser.ts
@@ -109,11 +109,21 @@ export class OptionsParser {
     return filterParams;
   }
 
-  protected inheritFromSubQuery(): any {
-    return [
+  protected inheritFromSubQuery(include): any {
+    include.push([
       Sequelize.literal(`(select relname from pg_class where pg_class.oid = "${this.collection.name}".tableoid)`),
       '__tableName',
-    ];
+    ]);
+
+    include.push([
+      Sequelize.literal(`
+        (SELECT n.nspname
+        FROM pg_class c
+               JOIN pg_namespace n ON n.oid = c.relnamespace
+        WHERE c.oid = "${this.collection.name}".tableoid)
+      `),
+      '__schemaName',
+    ]);
   }
 
   protected parseFields(filterParams: any) {
@@ -132,7 +142,7 @@ export class OptionsParser {
     }; // out put all fields by default
 
     if (this.collection.isParent()) {
-      attributes.include.push(this.inheritFromSubQuery());
+      this.inheritFromSubQuery(attributes.include);
     }
 
     if (this.options?.fields) {
@@ -146,7 +156,7 @@ export class OptionsParser {
           if (!Array.isArray(attributes)) {
             attributes = [];
             if (this.collection.isParent()) {
-              attributes.push(this.inheritFromSubQuery());
+              this.inheritFromSubQuery(attributes);
             }
           }
 
diff --git a/packages/core/database/src/query-interface/mysql-query-interface.ts b/packages/core/database/src/query-interface/mysql-query-interface.ts
index 0f724ff8e..887995728 100644
--- a/packages/core/database/src/query-interface/mysql-query-interface.ts
+++ b/packages/core/database/src/query-interface/mysql-query-interface.ts
@@ -1,6 +1,7 @@
 import QueryInterface from './query-interface';
 import { Collection } from '../collection';
 import { Transactionable } from 'sequelize';
+import sqlParser from '../sql-parser';
 
 export default class MysqlQueryInterface extends QueryInterface {
   constructor(db) {
@@ -12,9 +13,57 @@ export default class MysqlQueryInterface extends QueryInterface {
 
     const tableName = collection.model.tableName;
     const databaseName = this.db.options.database;
-    const sql = `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${databaseName}' AND TABLE_NAME = '${tableName}'`;
+    const sql = `SELECT TABLE_NAME
+                 FROM INFORMATION_SCHEMA.TABLES
+                 WHERE TABLE_SCHEMA = '${databaseName}'
+                   AND TABLE_NAME = '${tableName}'`;
 
     const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });
     return results.length > 0;
   }
+
+  async listViews() {
+    const sql = `SELECT TABLE_NAME as name, VIEW_DEFINITION as definition
+                 FROM information_schema.views
+                 WHERE TABLE_SCHEMA = DATABASE()
+                 ORDER BY TABLE_NAME;`;
+
+    return await this.db.sequelize.query(sql, { type: 'SELECT' });
+  }
+
+  async viewColumnUsage(options: { viewName: string; schema?: string }): Promise<
+    Array<{
+      column_name: string;
+      table_name: string;
+      table_schema?: string;
+    }>
+  > {
+    try {
+      const viewDefinition = await this.db.sequelize.query(`SHOW CREATE VIEW ${options.viewName}`, { type: 'SELECT' });
+      const createView = viewDefinition[0]['Create View'];
+      const regex = /(?<=AS\s)([\s\S]*)/i;
+      const match = createView.match(regex);
+      const sql = match[0];
+
+      const { ast } = sqlParser.parse(sql);
+
+      const columns = ast.columns;
+
+      const results = [];
+      for (const column of columns) {
+        if (column.expr.type === 'column_ref') {
+          results.push({
+            column_name: column.expr.column,
+            table_name: column.expr.table,
+          });
+        }
+      }
+
+      return results;
+    } catch (e) {
+      this.db.logger.warn(e);
+
+      return [];
+    }
+  }
 }
diff --git a/packages/core/database/src/query-interface/postgres-query-interface.ts b/packages/core/database/src/query-interface/postgres-query-interface.ts
index c01fe9509..eb5e054e8 100644
--- a/packages/core/database/src/query-interface/postgres-query-interface.ts
+++ b/packages/core/database/src/query-interface/postgres-query-interface.ts
@@ -12,11 +12,35 @@ export default class PostgresQueryInterface extends QueryInterface {
     const tableName = collection.model.tableName;
     const schema = collection.collectionSchema() || 'public';
 
-    const sql = `SELECT EXISTS(SELECT 1 FROM information_schema.tables
-                 WHERE  table_schema = '${schema}'
-                 AND    table_name   = '${tableName}')`;
+    const sql = `SELECT EXISTS(SELECT 1
+                               FROM information_schema.tables
+                               WHERE table_schema = '${schema}'
+                                 AND table_name = '${tableName}')`;
 
     const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });
     return results[0]['exists'];
   }
+
+  async listViews() {
+    const sql = `
+      SELECT viewname as name, definition, schemaname as schema
+      FROM pg_views
+      WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
+      ORDER BY viewname;
+    `;
+
+    return await this.db.sequelize.query(sql, { type: 'SELECT' });
+  }
+
+  async viewColumnUsage(options) {
+    const { viewName, schema = 'public' } = options;
+    const sql = `
+      SELECT *
+      FROM information_schema.view_column_usage
+      WHERE view_schema = '${schema}'
+        AND view_name = '${viewName}';
+    `;
+
+    return (await this.db.sequelize.query(sql, { type: 'SELECT' })) as any;
+  }
 }
diff --git a/packages/core/database/src/query-interface/query-interface.ts b/packages/core/database/src/query-interface/query-interface.ts
index 311da005a..8792a24cc 100644
--- a/packages/core/database/src/query-interface/query-interface.ts
+++ b/packages/core/database/src/query-interface/query-interface.ts
@@ -4,9 +4,40 @@ import { QueryInterface as SequelizeQueryInterface, Transactionable } from 'sequ
 
 export default abstract class QueryInterface {
   sequelizeQueryInterface: SequelizeQueryInterface;
+
   protected constructor(public db: Database) {
     this.sequelizeQueryInterface = db.sequelize.getQueryInterface();
   }
 
   abstract collectionTableExists(collection: Collection, options?: Transactionable): Promise<boolean>;
+
+  abstract listViews();
+
+  abstract viewColumnUsage(options: { viewName: string; schema?: string }): Promise<
+    Array<{
+      column_name: string;
+      table_name: string;
+      table_schema?: string;
+    }>
+  >;
+
+  async dropAll(options) {
+    if (options.drop !== true) return;
+
+    const views = await this.listViews();
+
+    for (const view of views) {
+      let removeSql;
+
+      if (view.schema) {
+        removeSql = `DROP VIEW IF EXISTS "${view.schema}"."${view.name}"`;
+      } else {
+        removeSql = `DROP VIEW IF EXISTS ${view.name}`;
+      }
+
+      await this.db.sequelize.query(removeSql, { transaction: options.transaction });
+    }
+
+    await this.db.sequelize.getQueryInterface().dropAllTables(options);
+  }
 }
diff --git a/packages/core/database/src/query-interface/sqlite-query-interface.ts b/packages/core/database/src/query-interface/sqlite-query-interface.ts
index 9ac5e8a77..137b75789 100644
--- a/packages/core/database/src/query-interface/sqlite-query-interface.ts
+++ b/packages/core/database/src/query-interface/sqlite-query-interface.ts
@@ -1,5 +1,6 @@
 import QueryInterface from './query-interface';
 import { Collection } from '../collection';
+import sqlParser from '../sql-parser';
 
 export default class SqliteQueryInterface extends QueryInterface {
   constructor(db) {
@@ -11,8 +12,65 @@ export default class SqliteQueryInterface extends QueryInterface {
 
     const tableName = collection.model.tableName;
 
-    const sql = `SELECT name FROM sqlite_master WHERE type='table' AND name='${tableName}';`;
+    const sql = `SELECT name
+                 FROM sqlite_master
+                 WHERE type = 'table'
+                   AND name = '${tableName}';`;
     const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });
     return results.length > 0;
   }
+
+  async listViews() {
+    const sql = `
+      SELECT name , sql as definition
+      FROM sqlite_master
+      WHERE type = 'view'
+      ORDER BY name;
+    `;
+
+    return await this.db.sequelize.query(sql, {
+      type: 'SELECT',
+    });
+  }
+
+  async viewColumnUsage(options: { viewName: string; schema?: string }): Promise<
+    Array<{
+      column_name: string;
+      table_name: string;
+      table_schema?: string;
+    }>
+  > {
+    try {
+      const viewDefinition = await this.db.sequelize.query(
+        `SELECT sql FROM sqlite_master WHERE name = '${options.viewName}' AND type = 'view'`,
+        {
+          type: 'SELECT',
+        },
+      );
+
+      const createView = viewDefinition[0]['sql'];
+      const regex = /(?<=AS\s)([\s\S]*)/i;
+      const match = createView.match(regex);
+      const sql = match[0];
+
+      const { ast } = sqlParser.parse(sql);
+
+      const columns = ast.columns;
+
+      const results = [];
+      for (const column of columns) {
+        if (column.expr.type === 'column_ref') {
+          results.push({
+            column_name: column.expr.column,
+            table_name: column.expr.table,
+          });
+        }
+      }
+
+      return results;
+    } catch (e) {
+      this.db.logger.warn(e);
+      return [];
+    }
+  }
 }
diff --git a/packages/core/database/src/repository.ts b/packages/core/database/src/repository.ts
index d58d0f37d..4a9821aa5 100644
--- a/packages/core/database/src/repository.ts
+++ b/packages/core/database/src/repository.ts
@@ -11,7 +11,7 @@ import {
   Op,
   Transactionable,
   UpdateOptions as SequelizeUpdateOptions,
-  WhereOperators
+  WhereOperators,
 } from 'sequelize';
 import { Collection } from './collection';
 import { Database } from './database';
@@ -340,7 +340,9 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
     if (this.collection.isParent()) {
       for (const row of rows) {
         const rowCollectionName = this.database.tableNameCollectionMap.get(
-          options.raw ? row['__tableName'] : row.get('__tableName'),
+          options.raw
+            ? `${row['__schemaName']}.${row['__tableName']}`
+            : `${row.get('__schemaName')}.${row.get('__tableName')}`,
         ).name;
 
         options.raw
diff --git a/packages/core/database/src/sql-parser/index.js b/packages/core/database/src/sql-parser/index.js
new file mode 100644
index 000000000..eab4bd585
--- /dev/null
+++ b/packages/core/database/src/sql-parser/index.js
@@ -0,0 +1,10698 @@
+// Generated by Peggy 3.0.2.
+//
+// https://peggyjs.org/
+
+"use strict";
+
+function peg$subclass(child, parent) {
+  function C() { this.constructor = child; }
+  C.prototype = parent.prototype;
+  child.prototype = new C();
+}
+
+function peg$SyntaxError(message, expected, found, location) {
+  var self = Error.call(this, message);
+  // istanbul ignore next Check is a necessary evil to support older environments
+  if (Object.setPrototypeOf) {
+    Object.setPrototypeOf(self, peg$SyntaxError.prototype);
+  }
+  self.expected = expected;
+  self.found = found;
+  self.location = location;
+  self.name = "SyntaxError";
+  return self;
+}
+
+peg$subclass(peg$SyntaxError, Error);
+
+function peg$padEnd(str, targetLength, padString) {
+  padString = padString || " ";
+  if (str.length > targetLength) { return str; }
+  targetLength -= str.length;
+  padString += padString.repeat(targetLength);
+  return str + padString.slice(0, targetLength);
+}
+
+peg$SyntaxError.prototype.format = function(sources) {
+  var str = "Error: " + this.message;
+  if (this.location) {
+    var src = null;
+    var k;
+    for (k = 0; k < sources.length; k++) {
+      if (sources[k].source === this.location.source) {
+        src = sources[k].text.split(/\r\n|\n|\r/g);
+        break;
+      }
+    }
+    var s = this.location.start;
+    var offset_s = (this.location.source && (typeof this.location.source.offset === "function"))
+      ? this.location.source.offset(s)
+      : s;
+    var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column;
+    if (src) {
+      var e = this.location.end;
+      var filler = peg$padEnd("", offset_s.line.toString().length, ' ');
+      var line = src[s.line - 1];
+      var last = s.line === e.line ? e.column : line.length + 1;
+      var hatLen = (last - s.column) || 1;
+      str += "\n --> " + loc + "\n"
+          + filler + " |\n"
+          + offset_s.line + " | " + line + "\n"
+          + filler + " | " + peg$padEnd("", s.column - 1, ' ')
+          + peg$padEnd("", hatLen, "^");
+    } else {
+      str += "\n at " + loc;
+    }
+  }
+  return str;
+};
+
+peg$SyntaxError.buildMessage = function(expected, found) {
+  var DESCRIBE_EXPECTATION_FNS = {
+    literal: function(expectation) {
+      return "\"" + literalEscape(expectation.text) + "\"";
+    },
+
+    class: function(expectation) {
+      var escapedParts = expectation.parts.map(function(part) {
+        return Array.isArray(part)
+          ? classEscape(part[0]) + "-" + classEscape(part[1])
+          : classEscape(part);
+      });
+
+      return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";
+    },
+
+    any: function() {
+      return "any character";
+    },
+
+    end: function() {
+      return "end of input";
+    },
+
+    other: function(expectation) {
+      return expectation.description;
+    }
+  };
+
+  function hex(ch) {
+    return ch.charCodeAt(0).toString(16).toUpperCase();
+  }
+
+  function literalEscape(s) {
+    return s
+      .replace(/\\/g, "\\\\")
+      .replace(/"/g,  "\\\"")
+      .replace(/\0/g, "\\0")
+      .replace(/\t/g, "\\t")
+      .replace(/\n/g, "\\n")
+      .replace(/\r/g, "\\r")
+      .replace(/[\x00-\x0F]/g,          function(ch) { return "\\x0" + hex(ch); })
+      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x"  + hex(ch); });
+  }
+
+  function classEscape(s) {
+    return s
+      .replace(/\\/g, "\\\\")
+      .replace(/\]/g, "\\]")
+      .replace(/\^/g, "\\^")
+      .replace(/-/g,  "\\-")
+      .replace(/\0/g, "\\0")
+      .replace(/\t/g, "\\t")
+      .replace(/\n/g, "\\n")
+      .replace(/\r/g, "\\r")
+      .replace(/[\x00-\x0F]/g,          function(ch) { return "\\x0" + hex(ch); })
+      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x"  + hex(ch); });
+  }
+
+  function describeExpectation(expectation) {
+    return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
+  }
+
+  function describeExpected(expected) {
+    var descriptions = expected.map(describeExpectation);
+    var i, j;
+
+    descriptions.sort();
+
+    if (descriptions.length > 0) {
+      for (i = 1, j = 1; i < descriptions.length; i++) {
+        if (descriptions[i - 1] !== descriptions[i]) {
+          descriptions[j] = descriptions[i];
+          j++;
+        }
+      }
+      descriptions.length = j;
+    }
+
+    switch (descriptions.length) {
+      case 1:
+        return descriptions[0];
+
+      case 2:
+        return descriptions[0] + " or " + descriptions[1];
+
+      default:
+        return descriptions.slice(0, -1).join(", ")
+          + ", or "
+          + descriptions[descriptions.length - 1];
+    }
+  }
+
+  function describeFound(found) {
+    return found ? "\"" + literalEscape(found) + "\"" : "end of input";
+  }
+
+  return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
+};
+
+function peg$parse(input, options) {
+  options = options !== undefined ? options : {};
+
+  var peg$FAILED = {};
+  var peg$source = options.grammarSource;
+
+  var peg$startRuleFunctions = { start: peg$parsestart };
+  var peg$startRuleFunction = peg$parsestart;
+
+  var peg$c0 = "(";
+  var peg$c1 = ")";
+  var peg$c2 = "=";
+  var peg$c3 = "!";
+  var peg$c4 = ">=";
+  var peg$c5 = ">";
+  var peg$c6 = "<=";
+  var peg$c7 = "<>";
+  var peg$c8 = "<";
+  var peg$c9 = "!=";
+  var peg$c10 = "+";
+  var peg$c11 = "-";
+  var peg$c12 = "*";
+  var peg$c13 = "/";
+  var peg$c14 = "%";
+  var peg$c15 = "\"";
+  var peg$c16 = "'";
+  var peg$c17 = "`";
+  var peg$c18 = ":";
+  var peg$c19 = "\\'";
+  var peg$c20 = "\\\"";
+  var peg$c21 = "\\\\";
+  var peg$c22 = "\\/";
+  var peg$c23 = "\\b";
+  var peg$c24 = "\\f";
+  var peg$c25 = "\\n";
+  var peg$c26 = "\\r";
+  var peg$c27 = "\\t";
+  var peg$c28 = "\\u";
+  var peg$c29 = ".";
+  var peg$c30 = "null";
+  var peg$c31 = "true";
+  var peg$c32 = "false";
+  var peg$c33 = "show";
+  var peg$c34 = "drop";
+  var peg$c35 = "select";
+  var peg$c36 = "update";
+  var peg$c37 = "create";
+  var peg$c38 = "delete";
+  var peg$c39 = "insert";
+  var peg$c40 = "RECURSIVE";
+  var peg$c41 = "replace";
+  var peg$c42 = "explain";
+  var peg$c43 = "into";
+  var peg$c44 = "from";
+  var peg$c45 = "set";
+  var peg$c46 = "as";
+  var peg$c47 = "table";
+  var peg$c48 = "on";
+  var peg$c49 = "left";
+  var peg$c50 = "right";
+  var peg$c51 = "full";
+  var peg$c52 = "inner";
+  var peg$c53 = "join";
+  var peg$c54 = "outer";
+  var peg$c55 = "union";
+  var peg$c56 = "values";
+  var peg$c57 = "using";
+  var peg$c58 = "where";
+  var peg$c59 = "with";
+  var peg$c60 = "group";
+  var peg$c61 = "by";
+  var peg$c62 = "order";
+  var peg$c63 = "having";
+  var peg$c64 = "limit";
+  var peg$c65 = "asc";
+  var peg$c66 = "desc";
+  var peg$c67 = "all";
+  var peg$c68 = "distinct";
+  var peg$c69 = "between";
+  var peg$c70 = "in";
+  var peg$c71 = "is";
+  var peg$c72 = "like";
+  var peg$c73 = "exists";
+  var peg$c74 = "not";
+  var peg$c75 = "and";
+  var peg$c76 = "or";
+  var peg$c77 = "count";
+  var peg$c78 = "max";
+  var peg$c79 = "min";
+  var peg$c80 = "sum";
+  var peg$c81 = "avg";
+  var peg$c82 = "case";
+  var peg$c83 = "when";
+  var peg$c84 = "then";
+  var peg$c85 = "else";
+  var peg$c86 = "end";
+  var peg$c87 = "cast";
+  var peg$c88 = "char";
+  var peg$c89 = "varchar";
+  var peg$c90 = "numeric";
+  var peg$c91 = "decimal";
+  var peg$c92 = "signed";
+  var peg$c93 = "unsigned";
+  var peg$c94 = "int";
+  var peg$c95 = "integer";
+  var peg$c96 = "json";
+  var peg$c97 = "smallint";
+  var peg$c98 = "date";
+  var peg$c99 = "time";
+  var peg$c100 = "timestamp";
+  var peg$c101 = "user";
+  var peg$c102 = "current_date";
+  var peg$c103 = "adddate";
+  var peg$c104 = "interval";
+  var peg$c105 = "year";
+  var peg$c106 = "month";
+  var peg$c107 = "day";
+  var peg$c108 = "hour";
+  var peg$c109 = "minute";
+  var peg$c110 = "second";
+  var peg$c111 = "current_time";
+  var peg$c112 = "current_timestamp";
+  var peg$c113 = "current_user";
+  var peg$c114 = "session_user";
+  var peg$c115 = "system_user";
+  var peg$c116 = "$";
+  var peg$c117 = "return";
+  var peg$c118 = ":=";
+  var peg$c119 = "dual";
+  var peg$c120 = "sql_calc_found_rows";
+  var peg$c121 = "sql_cache";
+  var peg$c122 = "sql_no_cache";
+  var peg$c123 = "sql_small_result";
+  var peg$c124 = "sql_big_result";
+  var peg$c125 = "sql_buffer_result";
+  var peg$c126 = ",";
+  var peg$c127 = "[";
+  var peg$c128 = "]";
+  var peg$c129 = ";";
+  var peg$c130 = "/*";
+  var peg$c131 = "*/";
+  var peg$c132 = "--";
+
+  var peg$r0 = /^[^"]/;
+  var peg$r1 = /^[^']/;
+  var peg$r2 = /^[^`]/;
+  var peg$r3 = /^[A-Za-z_]/;
+  var peg$r4 = /^[A-Za-z0-9_]/;
+  var peg$r5 = /^[A-Za-z0-9_:]/;
+  var peg$r6 = /^[^"\\\0-\x1F\x7F]/;
+  var peg$r7 = /^[^'\\\0-\x1F\x7F]/;
+  var peg$r8 = /^[\n\r]/;
+  var peg$r9 = /^[0-9]/;
+  var peg$r10 = /^[1-9]/;
+  var peg$r11 = /^[0-9a-fA-F]/;
+  var peg$r12 = /^[eE]/;
+  var peg$r13 = /^[+\-]/;
+  var peg$r14 = /^[ \t\n\r]/;
+
+  var peg$e0 = peg$literalExpectation("(", false);
+  var peg$e1 = peg$literalExpectation(")", false);
+  var peg$e2 = peg$literalExpectation("=", false);
+  var peg$e3 = peg$literalExpectation("!", false);
+  var peg$e4 = peg$literalExpectation(">=", false);
+  var peg$e5 = peg$literalExpectation(">", false);
+  var peg$e6 = peg$literalExpectation("<=", false);
+  var peg$e7 = peg$literalExpectation("<>", false);
+  var peg$e8 = peg$literalExpectation("<", false);
+  var peg$e9 = peg$literalExpectation("!=", false);
+  var peg$e10 = peg$literalExpectation("+", false);
+  var peg$e11 = peg$literalExpectation("-", false);
+  var peg$e12 = peg$literalExpectation("*", false);
+  var peg$e13 = peg$literalExpectation("/", false);
+  var peg$e14 = peg$literalExpectation("%", false);
+  var peg$e15 = peg$literalExpectation("\"", false);
+  var peg$e16 = peg$classExpectation(["\""], true, false);
+  var peg$e17 = peg$literalExpectation("'", false);
+  var peg$e18 = peg$classExpectation(["'"], true, false);
+  var peg$e19 = peg$literalExpectation("`", false);
+  var peg$e20 = peg$classExpectation(["`"], true, false);
+  var peg$e21 = peg$classExpectation([["A", "Z"], ["a", "z"], "_"], false, false);
+  var peg$e22 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_"], false, false);
+  var peg$e23 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", ":"], false, false);
+  var peg$e24 = peg$literalExpectation(":", false);
+  var peg$e25 = peg$classExpectation(["\"", "\\", ["\0", "\x1F"], "\x7F"], true, false);
+  var peg$e26 = peg$classExpectation(["'", "\\", ["\0", "\x1F"], "\x7F"], true, false);
+  var peg$e27 = peg$literalExpectation("\\'", false);
+  var peg$e28 = peg$literalExpectation("\\\"", false);
+  var peg$e29 = peg$literalExpectation("\\\\", false);
+  var peg$e30 = peg$literalExpectation("\\/", false);
+  var peg$e31 = peg$literalExpectation("\\b", false);
+  var peg$e32 = peg$literalExpectation("\\f", false);
+  var peg$e33 = peg$literalExpectation("\\n", false);
+  var peg$e34 = peg$literalExpectation("\\r", false);
+  var peg$e35 = peg$literalExpectation("\\t", false);
+  var peg$e36 = peg$literalExpectation("\\u", false);
+  var peg$e37 = peg$classExpectation(["\n", "\r"], false, false);
+  var peg$e38 = peg$literalExpectation(".", false);
+  var peg$e39 = peg$classExpectation([["0", "9"]], false, false);
+  var peg$e40 = peg$classExpectation([["1", "9"]], false, false);
+  var peg$e41 = peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false);
+  var peg$e42 = peg$classExpectation(["e", "E"], false, false);
+  var peg$e43 = peg$classExpectation(["+", "-"], false, false);
+  var peg$e44 = peg$literalExpectation("NULL", true);
+  var peg$e45 = peg$literalExpectation("TRUE", true);
+  var peg$e46 = peg$literalExpectation("FALSE", true);
+  var peg$e47 = peg$literalExpectation("SHOW", true);
+  var peg$e48 = peg$literalExpectation("DROP", true);
+  var peg$e49 = peg$literalExpectation("SELECT", true);
+  var peg$e50 = peg$literalExpectation("UPDATE", true);
+  var peg$e51 = peg$literalExpectation("CREATE", true);
+  var peg$e52 = peg$literalExpectation("DELETE", true);
+  var peg$e53 = peg$literalExpectation("INSERT", true);
+  var peg$e54 = peg$literalExpectation("RECURSIVE", false);
+  var peg$e55 = peg$literalExpectation("REPLACE", true);
+  var peg$e56 = peg$literalExpectation("EXPLAIN", true);
+  var peg$e57 = peg$literalExpectation("INTO", true);
+  var peg$e58 = peg$literalExpectation("FROM", true);
+  var peg$e59 = peg$literalExpectation("SET", true);
+  var peg$e60 = peg$literalExpectation("AS", true);
+  var peg$e61 = peg$literalExpectation("TABLE", true);
+  var peg$e62 = peg$literalExpectation("ON", true);
+  var peg$e63 = peg$literalExpectation("LEFT", true);
+  var peg$e64 = peg$literalExpectation("RIGHT", true);
+  var peg$e65 = peg$literalExpectation("FULL", true);
+  var peg$e66 = peg$literalExpectation("INNER", true);
+  var peg$e67 = peg$literalExpectation("JOIN", true);
+  var peg$e68 = peg$literalExpectation("OUTER", true);
+  var peg$e69 = peg$literalExpectation("UNION", true);
+  var peg$e70 = peg$literalExpectation("VALUES", true);
+  var peg$e71 = peg$literalExpectation("USING", true);
+  var peg$e72 = peg$literalExpectation("WHERE", true);
+  var peg$e73 = peg$literalExpectation("WITH", true);
+  var peg$e74 = peg$literalExpectation("GROUP", true);
+  var peg$e75 = peg$literalExpectation("BY", true);
+  var peg$e76 = peg$literalExpectation("ORDER", true);
+  var peg$e77 = peg$literalExpectation("HAVING", true);
+  var peg$e78 = peg$literalExpectation("LIMIT", true);
+  var peg$e79 = peg$literalExpectation("ASC", true);
+  var peg$e80 = peg$literalExpectation("DESC", true);
+  var peg$e81 = peg$literalExpectation("ALL", true);
+  var peg$e82 = peg$literalExpectation("DISTINCT", true);
+  var peg$e83 = peg$literalExpectation("BETWEEN", true);
+  var peg$e84 = peg$literalExpectation("IN", true);
+  var peg$e85 = peg$literalExpectation("IS", true);
+  var peg$e86 = peg$literalExpectation("LIKE", true);
+  var peg$e87 = peg$literalExpectation("EXISTS", true);
+  var peg$e88 = peg$literalExpectation("NOT", true);
+  var peg$e89 = peg$literalExpectation("AND", true);
+  var peg$e90 = peg$literalExpectation("OR", true);
+  var peg$e91 = peg$literalExpectation("COUNT", true);
+  var peg$e92 = peg$literalExpectation("MAX", true);
+  var peg$e93 = peg$literalExpectation("MIN", true);
+  var peg$e94 = peg$literalExpectation("SUM", true);
+  var peg$e95 = peg$literalExpectation("AVG", true);
+  var peg$e96 = peg$literalExpectation("CASE", true);
+  var peg$e97 = peg$literalExpectation("WHEN", true);
+  var peg$e98 = peg$literalExpectation("THEN", true);
+  var peg$e99 = peg$literalExpectation("ELSE", true);
+  var peg$e100 = peg$literalExpectation("END", true);
+  var peg$e101 = peg$literalExpectation("CAST", true);
+  var peg$e102 = peg$literalExpectation("CHAR", true);
+  var peg$e103 = peg$literalExpectation("VARCHAR", true);
+  var peg$e104 = peg$literalExpectation("NUMERIC", true);
+  var peg$e105 = peg$literalExpectation("DECIMAL", true);
+  var peg$e106 = peg$literalExpectation("SIGNED", true);
+  var peg$e107 = peg$literalExpectation("UNSIGNED", true);
+  var peg$e108 = peg$literalExpectation("INT", true);
+  var peg$e109 = peg$literalExpectation("INTEGER", true);
+  var peg$e110 = peg$literalExpectation("JSON", true);
+  var peg$e111 = peg$literalExpectation("SMALLINT", true);
+  var peg$e112 = peg$literalExpectation("DATE", true);
+  var peg$e113 = peg$literalExpectation("TIME", true);
+  var peg$e114 = peg$literalExpectation("TIMESTAMP", true);
+  var peg$e115 = peg$literalExpectation("USER", true);
+  var peg$e116 = peg$literalExpectation("CURRENT_DATE", true);
+  var peg$e117 = peg$literalExpectation("ADDDATE", true);
+  var peg$e118 = peg$literalExpectation("INTERVAL", true);
+  var peg$e119 = peg$literalExpectation("YEAR", true);
+  var peg$e120 = peg$literalExpectation("MONTH", true);
+  var peg$e121 = peg$literalExpectation("DAY", true);
+  var peg$e122 = peg$literalExpectation("HOUR", true);
+  var peg$e123 = peg$literalExpectation("MINUTE", true);
+  var peg$e124 = peg$literalExpectation("SECOND", true);
+  var peg$e125 = peg$literalExpectation("CURRENT_TIME", true);
+  var peg$e126 = peg$literalExpectation("CURRENT_TIMESTAMP", true);
+  var peg$e127 = peg$literalExpectation("CURRENT_USER", true);
+  var peg$e128 = peg$literalExpectation("SESSION_USER", true);
+  var peg$e129 = peg$literalExpectation("SYSTEM_USER", true);
+  var peg$e130 = peg$literalExpectation("$", false);
+  var peg$e131 = peg$literalExpectation("return", true);
+  var peg$e132 = peg$literalExpectation(":=", false);
+  var peg$e133 = peg$literalExpectation("DUAL", true);
+  var peg$e134 = peg$literalExpectation("SQL_CALC_FOUND_ROWS", true);
+  var peg$e135 = peg$literalExpectation("SQL_CACHE", true);
+  var peg$e136 = peg$literalExpectation("SQL_NO_CACHE", true);
+  var peg$e137 = peg$literalExpectation("SQL_SMALL_RESULT", true);
+  var peg$e138 = peg$literalExpectation("SQL_BIG_RESULT", true);
+  var peg$e139 = peg$literalExpectation("SQL_BUFFER_RESULT", true);
+  var peg$e140 = peg$literalExpectation(",", false);
+  var peg$e141 = peg$literalExpectation("[", false);
+  var peg$e142 = peg$literalExpectation("]", false);
+  var peg$e143 = peg$literalExpectation(";", false);
+  var peg$e144 = peg$literalExpectation("/*", false);
+  var peg$e145 = peg$literalExpectation("*/", false);
+  var peg$e146 = peg$literalExpectation("--", false);
+  var peg$e147 = peg$anyExpectation();
+  var peg$e148 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false);
+
+  var peg$f0 = function(head, tail) {
+      const cur = [head && head.ast || head];
+      for (let i = 0; i < tail.length; i++) {
+        if(!tail[i][3] || tail[i][3].length === 0) continue;
+        cur.push(tail[i][3] && tail[i][3].ast || tail[i][3]);
+      }
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+      	ast: cur
+      }
+    };
+  var peg$f1 = function(head, tail) {
+      let cur = head;
+      for (let i = 0; i < tail.length; i++) {
+        cur._next = tail[i][3];
+        cur = cur._next
+      }
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+      	ast: head
+      }
+    };
+  var peg$f2 = function(s) {
+      return s[2];
+    };
+  var peg$f3 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f4 = function(cte) {
+      cte.recursive = true;
+      return [cte]
+    };
+  var peg$f5 = function(name, columns, stmt) {
+      return { name, stmt, columns };
+    };
+  var peg$f6 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f7 = function(cte, opts, d, c, f, w, g, h, o, l) {
+      if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`));
+      return {
+          with: cte,
+          type: 'select',
+          options: opts,
+          distinct: d,
+          columns: c,
+          from: f,
+          where: w,
+          groupby: g,
+          having: h,
+          orderby: o,
+          limit: l
+      };
+  };
+  var peg$f8 = function(head, tail) {
+    const opts = [head];
+    for (let i = 0, l = tail.length; i < l; ++i) {
+      opts.push(tail[i][1]);
+    }
+    return opts;
+  };
+  var peg$f9 = function(option) { return option; };
+  var peg$f10 = function() {
+      columnList.add('select::null::(.*)');
+      return '*';
+    };
+  var peg$f11 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f12 = function(tbl) {
+      columnList.add(`select::${tbl}::(.*)`);
+      return {
+        expr: {
+          type: 'column_ref',
+          table: tbl,
+          column: '*'
+        },
+        as: null
+      };
+    };
+  var peg$f13 = function(e, alias) {
+      return { expr: e, as: alias };
+    };
+  var peg$f14 = function(i) { return i; };
+  var peg$f15 = function(i) { return i; };
+  var peg$f16 = function(l) { return l; };
+  var peg$f17 = function(head, tail) {
+      tail.unshift(head);
+      return tail;
+    };
+  var peg$f18 = function(t) { return t; };
+  var peg$f19 = function(t) { return t; };
+  var peg$f20 = function(op, t, head, tail) {
+      t.join = op;
+      t.using = createList(head, tail);
+      return t;
+    };
+  var peg$f21 = function(op, t, expr) {
+      t.join = op;
+      t.on   = expr;
+      return t;
+    };
+  var peg$f22 = function(op, stmt, alias, expr) {
+    stmt.parentheses = true;
+    return {
+      expr: stmt,
+      as: alias,
+      join: op,
+      on: expr
+    };
+  };
+  var peg$f23 = function() {
+      return {
+        type: 'dual'
+      };
+  };
+  var peg$f24 = function(t, alias) {
+      if (t.type === 'var') {
+        t.as = alias;
+        return t;
+      } else {
+        return {
+          db: t.db,
+          table: t.table,
+          as: alias
+        };
+      }
+    };
+  var peg$f25 = function(stmt, alias) {
+      stmt.parentheses = true;
+      return {
+        expr: stmt,
+        as: alias
+      };
+    };
+  var peg$f26 = function() { return 'LEFT JOIN'; };
+  var peg$f27 = function() { return 'RIGHT JOIN'; };
+  var peg$f28 = function() { return 'FULL JOIN'; };
+  var peg$f29 = function() { return 'INNER JOIN'; };
+  var peg$f30 = function(dt, tail) {
+      const obj = { db: null, table: dt };
+      if (tail !== null) {
+        obj.db = dt;
+        obj.table = tail[3];
+      }
+      return obj;
+    };
+  var peg$f31 = function(v) {
+      v.db = null;
+      v.table = v.name;
+      return v;
+    };
+  var peg$f32 = function(e) { return e; };
+  var peg$f33 = function(e) { return e; };
+  var peg$f34 = function(l) { return l; };
+  var peg$f35 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f36 = function(e) { return e; };
+  var peg$f37 = function(l) { return l; };
+  var peg$f38 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f39 = function(e, d) {
+    const obj = { expr: e, type: 'ASC' };
+    if (d === 'DESC') obj.type = 'DESC';
+    return obj;
+  };
+  var peg$f40 = function(i1, tail) {
+      const res = [i1];
+      if (tail === null) res.unshift({ type: 'number', value: 0 });
+      else res.push(tail[2]);
+      return res;
+    };
+  var peg$f41 = function(t, l, w) {
+      if(t.table) tableList.add(`update::${t.db}::${t.table}`);
+      if(l) l.forEach(col => columnList.add(`update::${t.table}::${col.column}`));
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: 'update',
+          db: t.db,
+          table: t.table,
+          set: l,
+          where: w
+        }
+      };
+    };
+  var peg$f42 = function(t, f, w) {
+      if(f) f.forEach(info => {
+        info.table && tableList.add(`delete::${info.db}::${info.table}`);
+        columnList.add(`delete::${info.table}::(.*)`);
+      });
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: 'delete',
+          tables: t,
+          from: f,
+          where: w
+        }
+      };
+    };
+  var peg$f43 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f44 = function(tbl, c, v) {
+      return { column: c, value: v, table: tbl && tbl[0] };
+    };
+  var peg$f45 = function(ri, t, c, v) {
+      if (t.table) tableList.add(`insert::${t.db}::${t.table}`);
+      if (c) c.forEach(c => columnList.add(`insert::${t.table}::${c}`));
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: ri,
+          db: t.db,
+          table: t.table,
+          columns: c,
+          values: v
+        }
+      };
+    };
+  var peg$f46 = function(ri, t, v) {
+      if (t.table) tableList.add(`insert::${t.db}::${t.table}`);
+      columnList.add(`insert::${t.table}::(.*)`);
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: ri,
+          db: t.db,
+          table: t.table,
+          columns: null,
+          values: v
+        }
+      };
+    };
+  var peg$f47 = function() { return 'insert'; };
+  var peg$f48 = function() { return 'replace'; };
+  var peg$f49 = function(l) { return l; };
+  var peg$f50 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f51 = function(l) {
+      return l;
+    };
+  var peg$f52 = function(head, tail) {
+      const el = { type: 'expr_list' };
+      el.value = createList(head, tail);
+      return el;
+    };
+  var peg$f53 = function(n, u) {
+      return {
+        type: 'interval',
+        value: [n, u]
+      }
+    };
+  var peg$f54 = function(expr, condition_list, otherwise) {
+      if (otherwise) condition_list.push(otherwise);
+      return {
+        type: 'case',
+        expr: expr || null,
+        args: condition_list
+      };
+    };
+  var peg$f55 = function(condition, result) {
+    return {
+      type: 'when',
+      cond: condition,
+      result: result
+    };
+  };
+  var peg$f56 = function(result) {
+    return { type: 'else', result: result };
+  };
+  var peg$f57 = function(head, tail) {
+      return createBinaryExprChain(head, tail);
+    };
+  var peg$f58 = function(head, tail) {
+      return createBinaryExprChain(head, tail);
+    };
+  var peg$f59 = function(expr) {
+      return createUnaryExpr('NOT', expr);
+    };
+  var peg$f60 = function(left, rh) {
+      if (rh === null) return left;
+      else if (rh.type === 'arithmetic') return createBinaryExprChain(left, rh.tail);
+      else return createBinaryExpr(rh.op, left, rh.right);
+    };
+  var peg$f61 = function(op, stmt) {
+    stmt.parentheses = true;
+    return createUnaryExpr(op, stmt);
+  };
+  var peg$f62 = function(nk) { return nk[0] + ' ' + nk[2]; };
+  var peg$f63 = function(l) {
+      return { type: 'arithmetic', tail: l };
+    };
+  var peg$f64 = function(right) {
+      return { op: 'IS', right: right };
+    };
+  var peg$f65 = function(right) {
+      return { op: 'IS NOT', right: right };
+  };
+  var peg$f66 = function(op, begin, end) {
+      return {
+        op: op,
+        right: {
+          type: 'expr_list',
+          value: [begin, end]
+        }
+      };
+    };
+  var peg$f67 = function(nk) { return nk[0] + ' ' + nk[2]; };
+  var peg$f68 = function(nk) { return nk[0] + ' ' + nk[2]; };
+  var peg$f69 = function(nk) { return nk[0] + ' ' + nk[2]; };
+  var peg$f70 = function(op, right) {
+      return { op: op, right: right };
+    };
+  var peg$f71 = function(op, l) {
+      return { op: op, right: l };
+    };
+  var peg$f72 = function(op, e) {
+      return { op: op, right: e };
+    };
+  var peg$f73 = function(head, tail) {
+      return createBinaryExprChain(head, tail);
+    };
+  var peg$f74 = function(head, tail) {
+      return createBinaryExprChain(head, tail)
+    };
+  var peg$f75 = function(e) {
+      e.parentheses = true;
+      return e;
+    };
+  var peg$f76 = function(list) {
+        list.parentheses = true;
+        return list;
+    };
+  var peg$f77 = function(tbl, col) {
+      columnList.add(`select::${tbl}::${col}`);
+      return {
+        type: 'column_ref',
+        table: tbl,
+        column: col
+      };
+    };
+  var peg$f78 = function(col) {
+      columnList.add(`select::null::${col}`);
+      return {
+        type: 'column_ref',
+        table: null,
+        column: col
+      };
+    };
+  var peg$f79 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f80 = function(name) { return reservedMap[name.toUpperCase()] === true; };
+  var peg$f81 = function(name) {
+      return name;
+    };
+  var peg$f82 = function(name) {
+      return name;
+    };
+  var peg$f83 = function(name) {
+      if (reservedMap[name.toUpperCase()] === true) throw new Error("Error: "+ JSON.stringify(name)+" is a reserved word, can not as alias clause");
+      return false
+    };
+  var peg$f84 = function(name) {
+      return name;
+    };
+  var peg$f85 = function(name) {
+      return name;
+    };
+  var peg$f86 = function(chars) { return chars.join(''); };
+  var peg$f87 = function(chars) { return chars.join(''); };
+  var peg$f88 = function(chars) { return chars.join(''); };
+  var peg$f89 = function(name) { return reservedMap[name.toUpperCase()] === true; };
+  var peg$f90 = function(name) { return name; };
+  var peg$f91 = function(start, parts) { return start + parts.join(''); };
+  var peg$f92 = function(start, parts) { return start + parts.join(''); };
+  var peg$f93 = function(l) {
+      return { type: 'param', value: l[1] };
+    };
+  var peg$f94 = function(name, e) {
+      return {
+        type: 'aggr_func',
+        name: name,
+        args: {
+          expr: e
+        }
+      };
+    };
+  var peg$f95 = function(name, arg) {
+      return {
+        type: 'aggr_func',
+        name: name,
+        args: arg
+      };
+    };
+  var peg$f96 = function(e) { return { expr: e }; };
+  var peg$f97 = function(d, c) { return { distinct: d, expr: c }; };
+  var peg$f98 = function() { return { type: 'star', value: '*' }; };
+  var peg$f99 = function(name, l) {
+      return {
+        type: 'function',
+        name: name,
+        args: l ? l: { type: 'expr_list', value: [] }
+      };
+    };
+  var peg$f100 = function(name) {
+      return {
+        type: 'function',
+        name: name,
+        args: { type: 'expr_list', value: [] }
+      };
+    };
+  var peg$f101 = function(e, t) {
+    return {
+      type: 'cast',
+      expr: e,
+      target: t
+    };
+  };
+  var peg$f102 = function(e, precision) {
+    return {
+      type: 'cast',
+      expr: e,
+      target: {
+        dataType: 'DECIMAL(' + precision + ')'
+      }
+    };
+  };
+  var peg$f103 = function(e, precision, scale) {
+      return {
+        type: 'cast',
+        expr: e,
+        target: {
+          dataType: 'DECIMAL(' + precision + ', ' + scale + ')'
+        }
+      };
+    };
+  var peg$f104 = function(e, s, t) { /* MySQL cast to un-/signed integer */
+    return {
+      type: 'cast',
+      expr: e,
+      target: {
+        dataType: s + (t ? ' ' + t: '')
+      }
+    };
+  };
+  var peg$f105 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f106 = function() {
+      return { type: 'null', value: null };
+    };
+  var peg$f107 = function() {
+      return { type: 'bool', value: true };
+    };
+  var peg$f108 = function() {
+      return { type: 'bool', value: false };
+    };
+  var peg$f109 = function(ca) {
+      return {
+        type: 'string',
+        value: ca[1].join('')
+      };
+    };
+  var peg$f110 = function(ca) {
+      return {
+        type: 'string',
+        value: ca[1].join('')
+      };
+    };
+  var peg$f111 = function(type, ca) {
+      return {
+        type: type.toLowerCase(),
+        value: ca[1].join('')
+      };
+    };
+  var peg$f112 = function() { return "'";  };
+  var peg$f113 = function() { return '"';  };
+  var peg$f114 = function() { return "\\"; };
+  var peg$f115 = function() { return "/";  };
+  var peg$f116 = function() { return "\b"; };
+  var peg$f117 = function() { return "\f"; };
+  var peg$f118 = function() { return "\n"; };
+  var peg$f119 = function() { return "\r"; };
+  var peg$f120 = function() { return "\t"; };
+  var peg$f121 = function(h1, h2, h3, h4) {
+      return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
+    };
+  var peg$f122 = function(n) {
+      return { type: 'number', value: n };
+    };
+  var peg$f123 = function(int_, frac, exp) { return parseFloat(int_ + frac + exp); };
+  var peg$f124 = function(int_, frac) { return parseFloat(int_ + frac); };
+  var peg$f125 = function(int_, exp) { return parseFloat(int_ + exp); };
+  var peg$f126 = function(int_) { return parseFloat(int_); };
+  var peg$f127 = function(digit19, digits) { return digit19 + digits; };
+  var peg$f128 = function(op, digit19, digits) { return "-" + digit19 + digits; };
+  var peg$f129 = function(op, digit) { return "-" + digit; };
+  var peg$f130 = function(digits) { return "." + digits; };
+  var peg$f131 = function(e, digits) { return e + digits; };
+  var peg$f132 = function(digits) { return digits.join(""); };
+  var peg$f133 = function(e, sign) { return e + (sign !== null ? sign: ''); };
+  var peg$f134 = function() { return 'ASC'; };
+  var peg$f135 = function() { return 'DESC'; };
+  var peg$f136 = function() { return 'ALL'; };
+  var peg$f137 = function() { return 'DISTINCT';};
+  var peg$f138 = function() { return 'BETWEEN'; };
+  var peg$f139 = function() { return 'IN'; };
+  var peg$f140 = function() { return 'IS'; };
+  var peg$f141 = function() { return 'LIKE'; };
+  var peg$f142 = function() { return 'EXISTS'; };
+  var peg$f143 = function() { return 'NOT'; };
+  var peg$f144 = function() { return 'AND'; };
+  var peg$f145 = function() { return 'OR'; };
+  var peg$f146 = function() { return 'COUNT'; };
+  var peg$f147 = function() { return 'MAX'; };
+  var peg$f148 = function() { return 'MIN'; };
+  var peg$f149 = function() { return 'SUM'; };
+  var peg$f150 = function() { return 'AVG'; };
+  var peg$f151 = function() { return 'CHAR'; };
+  var peg$f152 = function() { return 'VARCHAR';};
+  var peg$f153 = function() { return 'NUMERIC'; };
+  var peg$f154 = function() { return 'DECIMAL'; };
+  var peg$f155 = function() { return 'SIGNED'; };
+  var peg$f156 = function() { return 'UNSIGNED'; };
+  var peg$f157 = function() { return 'INT'; };
+  var peg$f158 = function() { return 'INTEGER'; };
+  var peg$f159 = function() { return 'JSON'; };
+  var peg$f160 = function() { return 'SMALLINT'; };
+  var peg$f161 = function() { return 'DATE'; };
+  var peg$f162 = function() { return 'TIME'; };
+  var peg$f163 = function() { return 'TIMESTAMP'; };
+  var peg$f164 = function() { return 'USER'; };
+  var peg$f165 = function() { return 'CURRENT_DATE'; };
+  var peg$f166 = function() { return 'ADDDATE'; };
+  var peg$f167 = function() { return 'INTERVAL'; };
+  var peg$f168 = function() { return 'YEAR'; };
+  var peg$f169 = function() { return 'MONTH'; };
+  var peg$f170 = function() { return 'DAY'; };
+  var peg$f171 = function() { return 'HOUR'; };
+  var peg$f172 = function() { return 'MINUTE'; };
+  var peg$f173 = function() { return 'SECOND'; };
+  var peg$f174 = function() { return 'CURRENT_TIME'; };
+  var peg$f175 = function() { return 'CURRENT_TIMESTAMP'; };
+  var peg$f176 = function() { return 'CURRENT_USER'; };
+  var peg$f177 = function() { return 'SESSION_USER'; };
+  var peg$f178 = function() { return 'SYSTEM_USER'; };
+  var peg$f179 = function() { varList = []; return true; };
+  var peg$f180 = function(s) {
+      return { stmt: s, vars: varList };
+    };
+  var peg$f181 = function(va, e) {
+    return {
+      type: 'assign',
+      left: va,
+      right: e
+    };
+  };
+  var peg$f182 = function(e) {
+      return { type: 'return', expr: e };
+    };
+  var peg$f183 = function(head, tail) {
+      return createBinaryExprChain(head, tail);
+    };
+  var peg$f184 = function(head, tail) {
+      return createBinaryExprChain(head, tail);
+    };
+  var peg$f185 = function(lt, op, rt, expr) {
+      return {
+        type: 'join',
+        ltable: lt,
+        rtable: rt,
+        op: op,
+        on: expr
+      };
+    };
+  var peg$f186 = function(e) {
+      e.parentheses = true;
+      return e;
+    };
+  var peg$f187 = function(name, l) {
+      //compatible with original func_call
+      return {
+        type: 'function',
+        name: name,
+        args: {
+          type: 'expr_list',
+          value: l
+        }
+      };
+    };
+  var peg$f188 = function(head, tail) {
+      return createList(head, tail);
+    };
+  var peg$f189 = function(l) {
+    return { type: 'array', value: l };
+  };
+  var peg$f190 = function(name, m) {
+    //push for analysis
+    varList.push(name);
+    return {
+      type: 'var',
+      name: name,
+      members: m
+    };
+  };
+  var peg$f191 = function(l) {
+    const s = [];
+    for (let i = 0; i < l.length; i++) {
+      s.push(l[i][1]);
+    }
+    return s;
+  };
+  var peg$f192 = function(t, l) {
+    return { dataType: t, length: parseInt(l.join(''), 10) };
+  };
+  var peg$f193 = function(t) { return { dataType: t }; };
+  var peg$f194 = function(t) { return { dataType: t }; };
+  var peg$f195 = function(t) { return { dataType: t }; };
+  var peg$f196 = function(t) { return { dataType: t }; };
+  var peg$f197 = function(t) { return { dataType: t }; };
+  var peg$currPos = 0;
+  var peg$savedPos = 0;
+  var peg$posDetailsCache = [{ line: 1, column: 1 }];
+  var peg$maxFailPos = 0;
+  var peg$maxFailExpected = [];
+  var peg$silentFails = 0;
+
+  var peg$result;
+
+  if ("startRule" in options) {
+    if (!(options.startRule in peg$startRuleFunctions)) {
+      throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
+    }
+
+    peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
+  }
+
+  function text() {
+    return input.substring(peg$savedPos, peg$currPos);
+  }
+
+  function offset() {
+    return peg$savedPos;
+  }
+
+  function range() {
+    return {
+      source: peg$source,
+      start: peg$savedPos,
+      end: peg$currPos
+    };
+  }
+
+  function location() {
+    return peg$computeLocation(peg$savedPos, peg$currPos);
+  }
+
+  function expected(description, location) {
+    location = location !== undefined
+      ? location
+      : peg$computeLocation(peg$savedPos, peg$currPos);
+
+    throw peg$buildStructuredError(
+      [peg$otherExpectation(description)],
+      input.substring(peg$savedPos, peg$currPos),
+      location
+    );
+  }
+
+  function error(message, location) {
+    location = location !== undefined
+      ? location
+      : peg$computeLocation(peg$savedPos, peg$currPos);
+
+    throw peg$buildSimpleError(message, location);
+  }
+
+  function peg$literalExpectation(text, ignoreCase) {
+    return { type: "literal", text: text, ignoreCase: ignoreCase };
+  }
+
+  function peg$classExpectation(parts, inverted, ignoreCase) {
+    return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
+  }
+
+  function peg$anyExpectation() {
+    return { type: "any" };
+  }
+
+  function peg$endExpectation() {
+    return { type: "end" };
+  }
+
+  function peg$otherExpectation(description) {
+    return { type: "other", description: description };
+  }
+
+  function peg$computePosDetails(pos) {
+    var details = peg$posDetailsCache[pos];
+    var p;
+
+    if (details) {
+      return details;
+    } else {
+      p = pos - 1;
+      while (!peg$posDetailsCache[p]) {
+        p--;
+      }
+
+      details = peg$posDetailsCache[p];
+      details = {
+        line: details.line,
+        column: details.column
+      };
+
+      while (p < pos) {
+        if (input.charCodeAt(p) === 10) {
+          details.line++;
+          details.column = 1;
+        } else {
+          details.column++;
+        }
+
+        p++;
+      }
+
+      peg$posDetailsCache[pos] = details;
+
+      return details;
+    }
+  }
+
+  function peg$computeLocation(startPos, endPos, offset) {
+    var startPosDetails = peg$computePosDetails(startPos);
+    var endPosDetails = peg$computePosDetails(endPos);
+
+    var res = {
+      source: peg$source,
+      start: {
+        offset: startPos,
+        line: startPosDetails.line,
+        column: startPosDetails.column
+      },
+      end: {
+        offset: endPos,
+        line: endPosDetails.line,
+        column: endPosDetails.column
+      }
+    };
+    if (offset && peg$source && (typeof peg$source.offset === "function")) {
+      res.start = peg$source.offset(res.start);
+      res.end = peg$source.offset(res.end);
+    }
+    return res;
+  }
+
+  function peg$fail(expected) {
+    if (peg$currPos < peg$maxFailPos) { return; }
+
+    if (peg$currPos > peg$maxFailPos) {
+      peg$maxFailPos = peg$currPos;
+      peg$maxFailExpected = [];
+    }
+
+    peg$maxFailExpected.push(expected);
+  }
+
+  function peg$buildSimpleError(message, location) {
+    return new peg$SyntaxError(message, null, null, location);
+  }
+
+  function peg$buildStructuredError(expected, found, location) {
+    return new peg$SyntaxError(
+      peg$SyntaxError.buildMessage(expected, found),
+      expected,
+      found,
+      location
+    );
+  }
+
+  function peg$parsestart() {
+    var s0;
+
+    s0 = peg$parsemultiple_stmt();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsecrud_stmt();
+    }
+
+    return s0;
+  }
+
+  function peg$parsecrud_stmt() {
+    var s0;
+
+    s0 = peg$parseunion_stmt();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseupdate_stmt();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsereplace_insert_stmt();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseinsert_no_columns_stmt();
+          if (s0 === peg$FAILED) {
+            s0 = peg$parsedelete_stmt();
+            if (s0 === peg$FAILED) {
+              s0 = peg$parseproc_stmts();
+            }
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsemultiple_stmt() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsecrud_stmt();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseSEMICOLON();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsecrud_stmt();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      if (s3 !== peg$FAILED) {
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parse__();
+          s5 = peg$parseSEMICOLON();
+          if (s5 !== peg$FAILED) {
+            s6 = peg$parse__();
+            s7 = peg$parsecrud_stmt();
+            if (s7 !== peg$FAILED) {
+              s4 = [s4, s5, s6, s7];
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        }
+      } else {
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f0(s1, s2);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseunion_stmt() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseselect_stmt();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseKW_UNION();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseselect_stmt();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseKW_UNION();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseselect_stmt();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f1(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseselect_stmt() {
+    var s0, s1, s2, s3, s4, s5, s6;
+
+    s0 = peg$parseselect_stmt_nake();
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      if (input.charCodeAt(peg$currPos) === 40) {
+        s2 = peg$c0;
+        peg$currPos++;
+      } else {
+        s2 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e0); }
+      }
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parse__();
+        s4 = peg$parseselect_stmt();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parse__();
+          if (input.charCodeAt(peg$currPos) === 41) {
+            s6 = peg$c1;
+            peg$currPos++;
+          } else {
+            s6 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e1); }
+          }
+          if (s6 !== peg$FAILED) {
+            s2 = [s2, s3, s4, s5, s6];
+            s1 = s2;
+          } else {
+            peg$currPos = s1;
+            s1 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s1;
+          s1 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f2(s1);
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parsewith_clause() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_WITH();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsecte_definition();
+      if (s3 !== peg$FAILED) {
+        s4 = [];
+        s5 = peg$currPos;
+        s6 = peg$parse__();
+        s7 = peg$parseCOMMA();
+        if (s7 !== peg$FAILED) {
+          s8 = peg$parse__();
+          s9 = peg$parsecte_definition();
+          if (s9 !== peg$FAILED) {
+            s6 = [s6, s7, s8, s9];
+            s5 = s6;
+          } else {
+            peg$currPos = s5;
+            s5 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s5;
+          s5 = peg$FAILED;
+        }
+        while (s5 !== peg$FAILED) {
+          s4.push(s5);
+          s5 = peg$currPos;
+          s6 = peg$parse__();
+          s7 = peg$parseCOMMA();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            s9 = peg$parsecte_definition();
+            if (s9 !== peg$FAILED) {
+              s6 = [s6, s7, s8, s9];
+              s5 = s6;
+            } else {
+              peg$currPos = s5;
+              s5 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s5;
+            s5 = peg$FAILED;
+          }
+        }
+        peg$savedPos = s0;
+        s0 = peg$f3(s3, s4);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parse__();
+      s2 = peg$parseKW_WITH();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parse__();
+        s4 = peg$parseKW_RECURSIVE();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parse__();
+          s6 = peg$parsecte_definition();
+          if (s6 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f4(s6);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecte_definition() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident_name();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsecte_column_definition();
+      if (s3 === peg$FAILED) {
+        s3 = null;
+      }
+      s4 = peg$parse__();
+      s5 = peg$parseKW_AS();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseLPAREN();
+        if (s7 !== peg$FAILED) {
+          s8 = peg$parse__();
+          s9 = peg$parseunion_stmt();
+          if (s9 !== peg$FAILED) {
+            s10 = peg$parse__();
+            s11 = peg$parseRPAREN();
+            if (s11 !== peg$FAILED) {
+              peg$savedPos = s0;
+              s0 = peg$f5(s1, s3, s9);
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecte_column_definition() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
+
+    s0 = peg$currPos;
+    s1 = peg$parseLPAREN();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsecolumn();
+      if (s3 !== peg$FAILED) {
+        s4 = [];
+        s5 = peg$currPos;
+        s6 = peg$parse__();
+        s7 = peg$parseCOMMA();
+        if (s7 !== peg$FAILED) {
+          s8 = peg$parse__();
+          s9 = peg$parsecolumn();
+          if (s9 !== peg$FAILED) {
+            s6 = [s6, s7, s8, s9];
+            s5 = s6;
+          } else {
+            peg$currPos = s5;
+            s5 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s5;
+          s5 = peg$FAILED;
+        }
+        while (s5 !== peg$FAILED) {
+          s4.push(s5);
+          s5 = peg$currPos;
+          s6 = peg$parse__();
+          s7 = peg$parseCOMMA();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            s9 = peg$parsecolumn();
+            if (s9 !== peg$FAILED) {
+              s6 = [s6, s7, s8, s9];
+              s5 = s6;
+            } else {
+              peg$currPos = s5;
+              s5 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s5;
+            s5 = peg$FAILED;
+          }
+        }
+        s5 = peg$parse__();
+        s6 = peg$parseRPAREN();
+        if (s6 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f6(s3, s4);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseselect_stmt_nake() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21;
+
+    s0 = peg$currPos;
+    s1 = peg$parsewith_clause();
+    if (s1 === peg$FAILED) {
+      s1 = null;
+    }
+    s2 = peg$parse__();
+    s3 = peg$parseKW_SELECT();
+    if (s3 !== peg$FAILED) {
+      s4 = peg$parse__();
+      s5 = peg$parseoption_clause();
+      if (s5 === peg$FAILED) {
+        s5 = null;
+      }
+      s6 = peg$parse__();
+      s7 = peg$parseKW_DISTINCT();
+      if (s7 === peg$FAILED) {
+        s7 = null;
+      }
+      s8 = peg$parse__();
+      s9 = peg$parsecolumn_clause();
+      if (s9 !== peg$FAILED) {
+        s10 = peg$parse__();
+        s11 = peg$parsefrom_clause();
+        if (s11 === peg$FAILED) {
+          s11 = null;
+        }
+        s12 = peg$parse__();
+        s13 = peg$parsewhere_clause();
+        if (s13 === peg$FAILED) {
+          s13 = null;
+        }
+        s14 = peg$parse__();
+        s15 = peg$parsegroup_by_clause();
+        if (s15 === peg$FAILED) {
+          s15 = null;
+        }
+        s16 = peg$parse__();
+        s17 = peg$parsehaving_clause();
+        if (s17 === peg$FAILED) {
+          s17 = null;
+        }
+        s18 = peg$parse__();
+        s19 = peg$parseorder_by_clause();
+        if (s19 === peg$FAILED) {
+          s19 = null;
+        }
+        s20 = peg$parse__();
+        s21 = peg$parselimit_clause();
+        if (s21 === peg$FAILED) {
+          s21 = null;
+        }
+        peg$savedPos = s0;
+        s0 = peg$f7(s1, s5, s7, s9, s11, s13, s15, s17, s19, s21);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseoption_clause() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parsequery_option();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parsequery_option();
+      if (s5 !== peg$FAILED) {
+        s4 = [s4, s5];
+        s3 = s4;
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parsequery_option();
+        if (s5 !== peg$FAILED) {
+          s4 = [s4, s5];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f8(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsequery_option() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parseOPT_SQL_CALC_FOUND_ROWS();
+    if (s1 === peg$FAILED) {
+      s1 = peg$parseOPT_SQL_CACHE();
+      if (s1 === peg$FAILED) {
+        s1 = peg$parseOPT_SQL_NO_CACHE();
+      }
+      if (s1 === peg$FAILED) {
+        s1 = peg$parseOPT_SQL_BIG_RESULT();
+        if (s1 === peg$FAILED) {
+          s1 = peg$parseOPT_SQL_SMALL_RESULT();
+          if (s1 === peg$FAILED) {
+            s1 = peg$parseOPT_SQL_BUFFER_RESULT();
+          }
+        }
+      }
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f9(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsecolumn_clause() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_ALL();
+    if (s1 === peg$FAILED) {
+      s1 = peg$currPos;
+      s2 = peg$parseSTAR();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$currPos;
+        peg$silentFails++;
+        s4 = peg$parseident_start();
+        peg$silentFails--;
+        if (s4 === peg$FAILED) {
+          s3 = undefined;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+        if (s3 !== peg$FAILED) {
+          s2 = [s2, s3];
+          s1 = s2;
+        } else {
+          peg$currPos = s1;
+          s1 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+      if (s1 === peg$FAILED) {
+        s1 = peg$parseSTAR();
+      }
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f10();
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsecolumn_list_item();
+      if (s1 !== peg$FAILED) {
+        s2 = [];
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parsecolumn_list_item();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          s3 = peg$currPos;
+          s4 = peg$parse__();
+          s5 = peg$parseCOMMA();
+          if (s5 !== peg$FAILED) {
+            s6 = peg$parse__();
+            s7 = peg$parsecolumn_list_item();
+            if (s7 !== peg$FAILED) {
+              s4 = [s4, s5, s6, s7];
+              s3 = s4;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        }
+        peg$savedPos = s0;
+        s0 = peg$f11(s1, s2);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecolumn_list_item() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseDOT();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseSTAR();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f12(s1);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseexpr();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse__();
+        s3 = peg$parsealias_clause();
+        if (s3 === peg$FAILED) {
+          s3 = null;
+        }
+        peg$savedPos = s0;
+        s0 = peg$f13(s1, s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsealias_clause() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_AS();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsealias_ident();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f14(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseKW_AS();
+      if (s1 === peg$FAILED) {
+        s1 = null;
+      }
+      s2 = peg$parse__();
+      s3 = peg$parseident();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f15(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsefrom_clause() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_FROM();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsetable_ref_list();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f16(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsetable_ref_list() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parsetable_base();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$parsetable_ref();
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$parsetable_ref();
+      }
+      peg$savedPos = s0;
+      s0 = peg$f17(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsetable_ref() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$parse__();
+    s2 = peg$parseCOMMA();
+    if (s2 !== peg$FAILED) {
+      s3 = peg$parse__();
+      s4 = peg$parsetable_base();
+      if (s4 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f18(s4);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parse__();
+      s2 = peg$parsetable_join();
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f19(s2);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsetable_join() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15;
+
+    s0 = peg$currPos;
+    s1 = peg$parsejoin_op();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsetable_base();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseKW_USING();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseLPAREN();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            s9 = peg$parseident_name();
+            if (s9 !== peg$FAILED) {
+              s10 = [];
+              s11 = peg$currPos;
+              s12 = peg$parse__();
+              s13 = peg$parseCOMMA();
+              if (s13 !== peg$FAILED) {
+                s14 = peg$parse__();
+                s15 = peg$parseident_name();
+                if (s15 !== peg$FAILED) {
+                  s12 = [s12, s13, s14, s15];
+                  s11 = s12;
+                } else {
+                  peg$currPos = s11;
+                  s11 = peg$FAILED;
+                }
+              } else {
+                peg$currPos = s11;
+                s11 = peg$FAILED;
+              }
+              while (s11 !== peg$FAILED) {
+                s10.push(s11);
+                s11 = peg$currPos;
+                s12 = peg$parse__();
+                s13 = peg$parseCOMMA();
+                if (s13 !== peg$FAILED) {
+                  s14 = peg$parse__();
+                  s15 = peg$parseident_name();
+                  if (s15 !== peg$FAILED) {
+                    s12 = [s12, s13, s14, s15];
+                    s11 = s12;
+                  } else {
+                    peg$currPos = s11;
+                    s11 = peg$FAILED;
+                  }
+                } else {
+                  peg$currPos = s11;
+                  s11 = peg$FAILED;
+                }
+              }
+              s11 = peg$parse__();
+              s12 = peg$parseRPAREN();
+              if (s12 !== peg$FAILED) {
+                peg$savedPos = s0;
+                s0 = peg$f20(s1, s3, s9, s10);
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsejoin_op();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse__();
+        s3 = peg$parsetable_base();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parse__();
+          s5 = peg$parseon_clause();
+          if (s5 === peg$FAILED) {
+            s5 = null;
+          }
+          peg$savedPos = s0;
+          s0 = peg$f21(s1, s3, s5);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parsejoin_op();
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parse__();
+          s3 = peg$parseLPAREN();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parse__();
+            s5 = peg$parseunion_stmt();
+            if (s5 !== peg$FAILED) {
+              s6 = peg$parse__();
+              s7 = peg$parseRPAREN();
+              if (s7 !== peg$FAILED) {
+                s8 = peg$parse__();
+                s9 = peg$parsealias_clause();
+                if (s9 === peg$FAILED) {
+                  s9 = null;
+                }
+                s10 = peg$parse__();
+                s11 = peg$parseon_clause();
+                if (s11 === peg$FAILED) {
+                  s11 = null;
+                }
+                peg$savedPos = s0;
+                s0 = peg$f22(s1, s5, s9, s11);
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsetable_base() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_DUAL();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f23();
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsetable_name();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse__();
+        s3 = peg$parsealias_clause();
+        if (s3 === peg$FAILED) {
+          s3 = null;
+        }
+        peg$savedPos = s0;
+        s0 = peg$f24(s1, s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parseLPAREN();
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parse__();
+          s3 = peg$parseunion_stmt();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parse__();
+            s5 = peg$parseRPAREN();
+            if (s5 !== peg$FAILED) {
+              s6 = peg$parse__();
+              s7 = peg$parsealias_clause();
+              if (s7 === peg$FAILED) {
+                s7 = null;
+              }
+              peg$savedPos = s0;
+              s0 = peg$f25(s3, s7);
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsejoin_op() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_LEFT();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseKW_OUTER();
+      if (s3 === peg$FAILED) {
+        s3 = null;
+      }
+      s4 = peg$parse__();
+      s5 = peg$parseKW_JOIN();
+      if (s5 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f26();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseKW_RIGHT();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse__();
+        s3 = peg$parseKW_OUTER();
+        if (s3 === peg$FAILED) {
+          s3 = null;
+        }
+        s4 = peg$parse__();
+        s5 = peg$parseKW_JOIN();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f27();
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parseKW_FULL();
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parse__();
+          s3 = peg$parseKW_OUTER();
+          if (s3 === peg$FAILED) {
+            s3 = null;
+          }
+          s4 = peg$parse__();
+          s5 = peg$parseKW_JOIN();
+          if (s5 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f28();
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+        if (s0 === peg$FAILED) {
+          s0 = peg$currPos;
+          s1 = peg$currPos;
+          s2 = peg$parseKW_INNER();
+          if (s2 !== peg$FAILED) {
+            s3 = peg$parse__();
+            s2 = [s2, s3];
+            s1 = s2;
+          } else {
+            peg$currPos = s1;
+            s1 = peg$FAILED;
+          }
+          if (s1 === peg$FAILED) {
+            s1 = null;
+          }
+          s2 = peg$parseKW_JOIN();
+          if (s2 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f29();
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsetable_name() {
+    var s0, s1, s2, s3, s4, s5, s6;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      s3 = peg$parse__();
+      s4 = peg$parseDOT();
+      if (s4 !== peg$FAILED) {
+        s5 = peg$parse__();
+        s6 = peg$parseident();
+        if (s6 !== peg$FAILED) {
+          s3 = [s3, s4, s5, s6];
+          s2 = s3;
+        } else {
+          peg$currPos = s2;
+          s2 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 === peg$FAILED) {
+        s2 = null;
+      }
+      peg$savedPos = s0;
+      s0 = peg$f30(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsevar_decl();
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f31(s1);
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parseon_clause() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_ON();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseexpr();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f32(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsewhere_clause() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_WHERE();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseexpr();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f33(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsegroup_by_clause() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_GROUP();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseKW_BY();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parsecolumn_ref_list();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f34(s5);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecolumn_ref_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsecolumn_ref();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsecolumn_ref();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parsecolumn_ref();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f35(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsehaving_clause() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_HAVING();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseexpr();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f36(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseorder_by_clause() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_ORDER();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseKW_BY();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseorder_by_list();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f37(s5);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseorder_by_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseorder_by_element();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseorder_by_element();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseorder_by_element();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f38(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseorder_by_element() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseexpr();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseKW_DESC();
+      if (s3 === peg$FAILED) {
+        s3 = peg$parseKW_ASC();
+      }
+      if (s3 === peg$FAILED) {
+        s3 = null;
+      }
+      peg$savedPos = s0;
+      s0 = peg$f39(s1, s3);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsenumber_or_param() {
+    var s0;
+
+    s0 = peg$parseliteral_numeric();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseparam();
+    }
+
+    return s0;
+  }
+
+  function peg$parselimit_clause() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_LIMIT();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsenumber_or_param();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$currPos;
+        s6 = peg$parseCOMMA();
+        if (s6 !== peg$FAILED) {
+          s7 = peg$parse__();
+          s8 = peg$parsenumber_or_param();
+          if (s8 !== peg$FAILED) {
+            s6 = [s6, s7, s8];
+            s5 = s6;
+          } else {
+            peg$currPos = s5;
+            s5 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s5;
+          s5 = peg$FAILED;
+        }
+        if (s5 === peg$FAILED) {
+          s5 = null;
+        }
+        peg$savedPos = s0;
+        s0 = peg$f40(s3, s5);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseupdate_stmt() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_UPDATE();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsetable_name();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseKW_SET();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseset_list();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            s9 = peg$parsewhere_clause();
+            if (s9 === peg$FAILED) {
+              s9 = null;
+            }
+            peg$savedPos = s0;
+            s0 = peg$f41(s3, s7, s9);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsedelete_stmt() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_DELETE();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsetable_ref_list();
+      if (s3 === peg$FAILED) {
+        s3 = null;
+      }
+      s4 = peg$parse__();
+      s5 = peg$parsefrom_clause();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsewhere_clause();
+        if (s7 === peg$FAILED) {
+          s7 = null;
+        }
+        peg$savedPos = s0;
+        s0 = peg$f42(s3, s5, s7);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseset_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseset_item();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseset_item();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseset_item();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f43(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseset_item() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$currPos;
+    s2 = peg$parseident();
+    if (s2 !== peg$FAILED) {
+      s3 = peg$parse__();
+      s4 = peg$parseDOT();
+      if (s4 !== peg$FAILED) {
+        s2 = [s2, s3, s4];
+        s1 = s2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s1;
+      s1 = peg$FAILED;
+    }
+    if (s1 === peg$FAILED) {
+      s1 = null;
+    }
+    s2 = peg$parse__();
+    s3 = peg$parsecolumn_name();
+    if (s3 !== peg$FAILED) {
+      s4 = peg$parse__();
+      if (input.charCodeAt(peg$currPos) === 61) {
+        s5 = peg$c2;
+        peg$currPos++;
+      } else {
+        s5 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e2); }
+      }
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseadditive_expr();
+        if (s7 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f44(s1, s3, s7);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsereplace_insert_stmt() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13;
+
+    s0 = peg$currPos;
+    s1 = peg$parsereplace_insert();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseKW_INTO();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parsetable_name();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseLPAREN();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            s9 = peg$parsecolumn_list();
+            if (s9 !== peg$FAILED) {
+              s10 = peg$parse__();
+              s11 = peg$parseRPAREN();
+              if (s11 !== peg$FAILED) {
+                s12 = peg$parse__();
+                s13 = peg$parsevalue_clause();
+                if (s13 !== peg$FAILED) {
+                  peg$savedPos = s0;
+                  s0 = peg$f45(s1, s5, s9, s13);
+                } else {
+                  peg$currPos = s0;
+                  s0 = peg$FAILED;
+                }
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseinsert_no_columns_stmt() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsereplace_insert();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseKW_INTO();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parsetable_name();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parsevalue_clause();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f46(s1, s5, s7);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsereplace_insert() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_INSERT();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f47();
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseKW_REPLACE();
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f48();
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parsevalue_clause() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_VALUES();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsevalue_list();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f49(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsevalue_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsevalue_item();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsevalue_item();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parsevalue_item();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f50(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsevalue_item() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseLPAREN();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseexpr_list();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseRPAREN();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f51(s3);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseexpr_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseexpr();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseexpr();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseexpr();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f52(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseinterval_expr() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_INTERVAL();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsenumber();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseinterval_unit();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f53(s3, s5);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecase_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_CASE();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseexpr();
+      if (s3 === peg$FAILED) {
+        s3 = null;
+      }
+      s4 = peg$parse__();
+      s5 = [];
+      s6 = peg$parsecase_when_then();
+      if (s6 !== peg$FAILED) {
+        while (s6 !== peg$FAILED) {
+          s5.push(s6);
+          s6 = peg$parsecase_when_then();
+        }
+      } else {
+        s5 = peg$FAILED;
+      }
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsecase_else();
+        if (s7 === peg$FAILED) {
+          s7 = null;
+        }
+        s8 = peg$parse__();
+        s9 = peg$parseKW_END();
+        if (s9 !== peg$FAILED) {
+          s10 = peg$parse__();
+          s11 = peg$parseKW_CASE();
+          if (s11 === peg$FAILED) {
+            s11 = null;
+          }
+          peg$savedPos = s0;
+          s0 = peg$f54(s3, s5, s7);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecase_when_then() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_WHEN();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseexpr();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseKW_THEN();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseexpr();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            peg$savedPos = s0;
+            s0 = peg$f55(s3, s7);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecase_else() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_ELSE();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseexpr();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f56(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseexpr() {
+    var s0;
+
+    s0 = peg$parseor_expr();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseselect_stmt();
+    }
+
+    return s0;
+  }
+
+  function peg$parseor_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseand_expr();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseKW_OR();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseand_expr();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseKW_OR();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseand_expr();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f57(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseand_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsenot_expr();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseKW_AND();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsenot_expr();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseKW_AND();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parsenot_expr();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f58(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsenot_expr() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$parsecomparison_expr();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseexists_expr();
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parseKW_NOT();
+        if (s1 === peg$FAILED) {
+          s1 = peg$currPos;
+          if (input.charCodeAt(peg$currPos) === 33) {
+            s2 = peg$c3;
+            peg$currPos++;
+          } else {
+            s2 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e3); }
+          }
+          if (s2 !== peg$FAILED) {
+            s3 = peg$currPos;
+            peg$silentFails++;
+            if (input.charCodeAt(peg$currPos) === 61) {
+              s4 = peg$c2;
+              peg$currPos++;
+            } else {
+              s4 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$e2); }
+            }
+            peg$silentFails--;
+            if (s4 === peg$FAILED) {
+              s3 = undefined;
+            } else {
+              peg$currPos = s3;
+              s3 = peg$FAILED;
+            }
+            if (s3 !== peg$FAILED) {
+              s2 = [s2, s3];
+              s1 = s2;
+            } else {
+              peg$currPos = s1;
+              s1 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s1;
+            s1 = peg$FAILED;
+          }
+        }
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parse__();
+          s3 = peg$parsenot_expr();
+          if (s3 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f59(s3);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecomparison_expr() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseadditive_expr();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsecomparison_op_right();
+      if (s3 === peg$FAILED) {
+        s3 = null;
+      }
+      peg$savedPos = s0;
+      s0 = peg$f60(s1, s3);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseexists_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseexists_op();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseunion_stmt();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseRPAREN();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f61(s1, s5);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseexists_op() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$currPos;
+    s2 = peg$parseKW_NOT();
+    if (s2 !== peg$FAILED) {
+      s3 = peg$parse__();
+      s4 = peg$parseKW_EXISTS();
+      if (s4 !== peg$FAILED) {
+        s2 = [s2, s3, s4];
+        s1 = s2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s1;
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f62(s1);
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_EXISTS();
+    }
+
+    return s0;
+  }
+
+  function peg$parsecomparison_op_right() {
+    var s0;
+
+    s0 = peg$parsearithmetic_op_right();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsein_op_right();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsebetween_op_right();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseis_op_right();
+          if (s0 === peg$FAILED) {
+            s0 = peg$parselike_op_right();
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsearithmetic_op_right() {
+    var s0, s1, s2, s3, s4, s5, s6;
+
+    s0 = peg$currPos;
+    s1 = [];
+    s2 = peg$currPos;
+    s3 = peg$parse__();
+    s4 = peg$parsearithmetic_comparison_operator();
+    if (s4 !== peg$FAILED) {
+      s5 = peg$parse__();
+      s6 = peg$parseadditive_expr();
+      if (s6 !== peg$FAILED) {
+        s3 = [s3, s4, s5, s6];
+        s2 = s3;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s2;
+      s2 = peg$FAILED;
+    }
+    if (s2 !== peg$FAILED) {
+      while (s2 !== peg$FAILED) {
+        s1.push(s2);
+        s2 = peg$currPos;
+        s3 = peg$parse__();
+        s4 = peg$parsearithmetic_comparison_operator();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parse__();
+          s6 = peg$parseadditive_expr();
+          if (s6 !== peg$FAILED) {
+            s3 = [s3, s4, s5, s6];
+            s2 = s3;
+          } else {
+            peg$currPos = s2;
+            s2 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s2;
+          s2 = peg$FAILED;
+        }
+      }
+    } else {
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f63(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsearithmetic_comparison_operator() {
+    var s0;
+
+    if (input.substr(peg$currPos, 2) === peg$c4) {
+      s0 = peg$c4;
+      peg$currPos += 2;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e4); }
+    }
+    if (s0 === peg$FAILED) {
+      if (input.charCodeAt(peg$currPos) === 62) {
+        s0 = peg$c5;
+        peg$currPos++;
+      } else {
+        s0 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e5); }
+      }
+      if (s0 === peg$FAILED) {
+        if (input.substr(peg$currPos, 2) === peg$c6) {
+          s0 = peg$c6;
+          peg$currPos += 2;
+        } else {
+          s0 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e6); }
+        }
+        if (s0 === peg$FAILED) {
+          if (input.substr(peg$currPos, 2) === peg$c7) {
+            s0 = peg$c7;
+            peg$currPos += 2;
+          } else {
+            s0 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e7); }
+          }
+          if (s0 === peg$FAILED) {
+            if (input.charCodeAt(peg$currPos) === 60) {
+              s0 = peg$c8;
+              peg$currPos++;
+            } else {
+              s0 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$e8); }
+            }
+            if (s0 === peg$FAILED) {
+              if (input.charCodeAt(peg$currPos) === 61) {
+                s0 = peg$c2;
+                peg$currPos++;
+              } else {
+                s0 = peg$FAILED;
+                if (peg$silentFails === 0) { peg$fail(peg$e2); }
+              }
+              if (s0 === peg$FAILED) {
+                if (input.substr(peg$currPos, 2) === peg$c9) {
+                  s0 = peg$c9;
+                  peg$currPos += 2;
+                } else {
+                  s0 = peg$FAILED;
+                  if (peg$silentFails === 0) { peg$fail(peg$e9); }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseis_op_right() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_IS();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseadditive_expr();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f64(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      s2 = peg$parseKW_IS();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parse__();
+        s4 = peg$parseKW_NOT();
+        if (s4 !== peg$FAILED) {
+          s2 = [s2, s3, s4];
+          s1 = s2;
+        } else {
+          peg$currPos = s1;
+          s1 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse__();
+        s3 = peg$parseadditive_expr();
+        if (s3 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f65(s3);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsebetween_op_right() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsebetween_or_not_between_op();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseadditive_expr();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseKW_AND();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseadditive_expr();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f66(s1, s3, s7);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsebetween_or_not_between_op() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$currPos;
+    s2 = peg$parseKW_NOT();
+    if (s2 !== peg$FAILED) {
+      s3 = peg$parse__();
+      s4 = peg$parseKW_BETWEEN();
+      if (s4 !== peg$FAILED) {
+        s2 = [s2, s3, s4];
+        s1 = s2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s1;
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f67(s1);
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_BETWEEN();
+    }
+
+    return s0;
+  }
+
+  function peg$parselike_op() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$currPos;
+    s2 = peg$parseKW_NOT();
+    if (s2 !== peg$FAILED) {
+      s3 = peg$parse__();
+      s4 = peg$parseKW_LIKE();
+      if (s4 !== peg$FAILED) {
+        s2 = [s2, s3, s4];
+        s1 = s2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s1;
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f68(s1);
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_LIKE();
+    }
+
+    return s0;
+  }
+
+  function peg$parsein_op() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$currPos;
+    s2 = peg$parseKW_NOT();
+    if (s2 !== peg$FAILED) {
+      s3 = peg$parse__();
+      s4 = peg$parseKW_IN();
+      if (s4 !== peg$FAILED) {
+        s2 = [s2, s3, s4];
+        s1 = s2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s1;
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f69(s1);
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_IN();
+    }
+
+    return s0;
+  }
+
+  function peg$parselike_op_right() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parselike_op();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsecomparison_expr();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f70(s1, s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsein_op_right() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsein_op();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseexpr_list();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseRPAREN();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f71(s1, s5);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsein_op();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse__();
+        s3 = peg$parsevar_decl();
+        if (s3 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f72(s1, s3);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseadditive_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsemultiplicative_expr();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseadditive_operator();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsemultiplicative_expr();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseadditive_operator();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parsemultiplicative_expr();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f73(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseadditive_operator() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 43) {
+      s0 = peg$c10;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e10); }
+    }
+    if (s0 === peg$FAILED) {
+      if (input.charCodeAt(peg$currPos) === 45) {
+        s0 = peg$c11;
+        peg$currPos++;
+      } else {
+        s0 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e11); }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsemultiplicative_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseprimary();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parsemultiplicative_operator();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseprimary();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parsemultiplicative_operator();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseprimary();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f74(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsemultiplicative_operator() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 42) {
+      s0 = peg$c12;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e12); }
+    }
+    if (s0 === peg$FAILED) {
+      if (input.charCodeAt(peg$currPos) === 47) {
+        s0 = peg$c13;
+        peg$currPos++;
+      } else {
+        s0 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e13); }
+      }
+      if (s0 === peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 37) {
+          s0 = peg$c14;
+          peg$currPos++;
+        } else {
+          s0 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e14); }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseprimary() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$parseliteral();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsecast_expr();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parseaggr_func();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parsefunc_call();
+          if (s0 === peg$FAILED) {
+            s0 = peg$parsecase_expr();
+            if (s0 === peg$FAILED) {
+              s0 = peg$parseinterval_expr();
+              if (s0 === peg$FAILED) {
+                s0 = peg$parsecolumn_ref();
+                if (s0 === peg$FAILED) {
+                  s0 = peg$parseparam();
+                  if (s0 === peg$FAILED) {
+                    s0 = peg$currPos;
+                    s1 = peg$parseLPAREN();
+                    if (s1 !== peg$FAILED) {
+                      s2 = peg$parse__();
+                      s3 = peg$parseexpr();
+                      if (s3 !== peg$FAILED) {
+                        s4 = peg$parse__();
+                        s5 = peg$parseRPAREN();
+                        if (s5 !== peg$FAILED) {
+                          peg$savedPos = s0;
+                          s0 = peg$f75(s3);
+                        } else {
+                          peg$currPos = s0;
+                          s0 = peg$FAILED;
+                        }
+                      } else {
+                        peg$currPos = s0;
+                        s0 = peg$FAILED;
+                      }
+                    } else {
+                      peg$currPos = s0;
+                      s0 = peg$FAILED;
+                    }
+                    if (s0 === peg$FAILED) {
+                      s0 = peg$currPos;
+                      s1 = peg$parseLPAREN();
+                      if (s1 !== peg$FAILED) {
+                        s2 = peg$parse__();
+                        s3 = peg$parseexpr_list();
+                        if (s3 !== peg$FAILED) {
+                          s4 = peg$parse__();
+                          s5 = peg$parseRPAREN();
+                          if (s5 !== peg$FAILED) {
+                            peg$savedPos = s0;
+                            s0 = peg$f76(s3);
+                          } else {
+                            peg$currPos = s0;
+                            s0 = peg$FAILED;
+                          }
+                        } else {
+                          peg$currPos = s0;
+                          s0 = peg$FAILED;
+                        }
+                      } else {
+                        peg$currPos = s0;
+                        s0 = peg$FAILED;
+                      }
+                      if (s0 === peg$FAILED) {
+                        s0 = peg$parsevar_decl();
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecolumn_ref() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseDOT();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parsecolumn();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f77(s1, s5);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsecolumn();
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f78(s1);
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecolumn_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsecolumn();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parsecolumn();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parsecolumn();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f79(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseident() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident_name();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = peg$currPos;
+      s2 = peg$f80(s1);
+      if (s2) {
+        s2 = peg$FAILED;
+      } else {
+        s2 = undefined;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f81(s1);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsequoted_ident();
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f82(s1);
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parsealias_ident() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident_name();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = peg$currPos;
+      s2 = peg$f83(s1);
+      if (s2) {
+        s2 = peg$FAILED;
+      } else {
+        s2 = undefined;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f84(s1);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsequoted_ident();
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f85(s1);
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parsequoted_ident() {
+    var s0;
+
+    s0 = peg$parsedouble_quoted_ident();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsesingle_quoted_ident();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsebackticks_quoted_ident();
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsedouble_quoted_ident() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 34) {
+      s1 = peg$c15;
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e15); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      if (peg$r0.test(input.charAt(peg$currPos))) {
+        s3 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s3 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e16); }
+      }
+      if (s3 !== peg$FAILED) {
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          if (peg$r0.test(input.charAt(peg$currPos))) {
+            s3 = input.charAt(peg$currPos);
+            peg$currPos++;
+          } else {
+            s3 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e16); }
+          }
+        }
+      } else {
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 34) {
+          s3 = peg$c15;
+          peg$currPos++;
+        } else {
+          s3 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e15); }
+        }
+        if (s3 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f86(s2);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsesingle_quoted_ident() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 39) {
+      s1 = peg$c16;
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e17); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      if (peg$r1.test(input.charAt(peg$currPos))) {
+        s3 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s3 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e18); }
+      }
+      if (s3 !== peg$FAILED) {
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          if (peg$r1.test(input.charAt(peg$currPos))) {
+            s3 = input.charAt(peg$currPos);
+            peg$currPos++;
+          } else {
+            s3 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e18); }
+          }
+        }
+      } else {
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 39) {
+          s3 = peg$c16;
+          peg$currPos++;
+        } else {
+          s3 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e17); }
+        }
+        if (s3 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f87(s2);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsebackticks_quoted_ident() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 96) {
+      s1 = peg$c17;
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e19); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      if (peg$r2.test(input.charAt(peg$currPos))) {
+        s3 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s3 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e20); }
+      }
+      if (s3 !== peg$FAILED) {
+        while (s3 !== peg$FAILED) {
+          s2.push(s3);
+          if (peg$r2.test(input.charAt(peg$currPos))) {
+            s3 = input.charAt(peg$currPos);
+            peg$currPos++;
+          } else {
+            s3 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e20); }
+          }
+        }
+      } else {
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        if (input.charCodeAt(peg$currPos) === 96) {
+          s3 = peg$c17;
+          peg$currPos++;
+        } else {
+          s3 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e19); }
+        }
+        if (s3 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f88(s2);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecolumn() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    s1 = peg$parsecolumn_name();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = peg$currPos;
+      s2 = peg$f89(s1);
+      if (s2) {
+        s2 = peg$FAILED;
+      } else {
+        s2 = undefined;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f90(s1);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsequoted_ident();
+    }
+
+    return s0;
+  }
+
+  function peg$parsecolumn_name() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident_start();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$parsecolumn_part();
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$parsecolumn_part();
+      }
+      peg$savedPos = s0;
+      s0 = peg$f91(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseident_name() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident_start();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$parseident_part();
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$parseident_part();
+      }
+      peg$savedPos = s0;
+      s0 = peg$f92(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseident_start() {
+    var s0;
+
+    if (peg$r3.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e21); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseident_part() {
+    var s0;
+
+    if (peg$r4.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e22); }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecolumn_part() {
+    var s0;
+
+    if (peg$r5.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e23); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseparam() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 58) {
+      s2 = peg$c18;
+      peg$currPos++;
+    } else {
+      s2 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e24); }
+    }
+    if (s2 !== peg$FAILED) {
+      s3 = peg$parseident_name();
+      if (s3 !== peg$FAILED) {
+        s2 = [s2, s3];
+        s1 = s2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s1;
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f93(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parseaggr_func() {
+    var s0;
+
+    s0 = peg$parseaggr_fun_count();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseaggr_fun_smma();
+    }
+
+    return s0;
+  }
+
+  function peg$parseaggr_fun_smma() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_SUM_MAX_MIN_AVG();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseadditive_expr();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseRPAREN();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f94(s1, s5);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SUM_MAX_MIN_AVG() {
+    var s0;
+
+    s0 = peg$parseKW_SUM();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_MAX();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parseKW_MIN();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseKW_AVG();
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseaggr_fun_count() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_COUNT();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parsecount_arg();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseRPAREN();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f95(s1, s5);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsecount_arg() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parsestar_expr();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f96(s1);
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseKW_DISTINCT();
+      if (s1 === peg$FAILED) {
+        s1 = null;
+      }
+      s2 = peg$parse__();
+      s3 = peg$parsecolumn_ref();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f97(s1, s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsestar_expr() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 42) {
+      s1 = peg$c12;
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e12); }
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f98();
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsefunc_call() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseexpr_list();
+        if (s5 === peg$FAILED) {
+          s5 = null;
+        }
+        s6 = peg$parse__();
+        s7 = peg$parseRPAREN();
+        if (s7 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f99(s1, s5);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parsescalar_func();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$currPos;
+        s3 = peg$parse__();
+        s4 = peg$parseLPAREN();
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parseRPAREN();
+          if (s5 !== peg$FAILED) {
+            s6 = peg$parse__();
+            s3 = [s3, s4, s5, s6];
+            s2 = s3;
+          } else {
+            peg$currPos = s2;
+            s2 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s2;
+          s2 = peg$FAILED;
+        }
+        if (s2 === peg$FAILED) {
+          s2 = null;
+        }
+        peg$savedPos = s0;
+        s0 = peg$f100(s1);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsescalar_func() {
+    var s0;
+
+    s0 = peg$parseKW_CURRENT_DATE();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_CURRENT_TIME();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parseKW_CURRENT_TIMESTAMP();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseKW_CURRENT_USER();
+          if (s0 === peg$FAILED) {
+            s0 = peg$parseKW_USER();
+            if (s0 === peg$FAILED) {
+              s0 = peg$parseKW_SESSION_USER();
+              if (s0 === peg$FAILED) {
+                s0 = peg$parseKW_SYSTEM_USER();
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecast_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_CAST();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseexpr();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseKW_AS();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            s9 = peg$parsedata_type();
+            if (s9 !== peg$FAILED) {
+              s10 = peg$parse__();
+              s11 = peg$parseRPAREN();
+              if (s11 !== peg$FAILED) {
+                peg$savedPos = s0;
+                s0 = peg$f101(s5, s9);
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseKW_CAST();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parse__();
+        s3 = peg$parseLPAREN();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parse__();
+          s5 = peg$parseexpr();
+          if (s5 !== peg$FAILED) {
+            s6 = peg$parse__();
+            s7 = peg$parseKW_AS();
+            if (s7 !== peg$FAILED) {
+              s8 = peg$parse__();
+              s9 = peg$parseKW_DECIMAL();
+              if (s9 !== peg$FAILED) {
+                s10 = peg$parse__();
+                s11 = peg$parseLPAREN();
+                if (s11 !== peg$FAILED) {
+                  s12 = peg$parse__();
+                  s13 = peg$parseint();
+                  if (s13 !== peg$FAILED) {
+                    s14 = peg$parse__();
+                    s15 = peg$parseRPAREN();
+                    if (s15 !== peg$FAILED) {
+                      s16 = peg$parse__();
+                      s17 = peg$parseRPAREN();
+                      if (s17 !== peg$FAILED) {
+                        peg$savedPos = s0;
+                        s0 = peg$f102(s5, s13);
+                      } else {
+                        peg$currPos = s0;
+                        s0 = peg$FAILED;
+                      }
+                    } else {
+                      peg$currPos = s0;
+                      s0 = peg$FAILED;
+                    }
+                  } else {
+                    peg$currPos = s0;
+                    s0 = peg$FAILED;
+                  }
+                } else {
+                  peg$currPos = s0;
+                  s0 = peg$FAILED;
+                }
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parseKW_CAST();
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parse__();
+          s3 = peg$parseLPAREN();
+          if (s3 !== peg$FAILED) {
+            s4 = peg$parse__();
+            s5 = peg$parseexpr();
+            if (s5 !== peg$FAILED) {
+              s6 = peg$parse__();
+              s7 = peg$parseKW_AS();
+              if (s7 !== peg$FAILED) {
+                s8 = peg$parse__();
+                s9 = peg$parseKW_DECIMAL();
+                if (s9 !== peg$FAILED) {
+                  s10 = peg$parse__();
+                  s11 = peg$parseLPAREN();
+                  if (s11 !== peg$FAILED) {
+                    s12 = peg$parse__();
+                    s13 = peg$parseint();
+                    if (s13 !== peg$FAILED) {
+                      s14 = peg$parse__();
+                      s15 = peg$parseCOMMA();
+                      if (s15 !== peg$FAILED) {
+                        s16 = peg$parse__();
+                        s17 = peg$parseint();
+                        if (s17 !== peg$FAILED) {
+                          s18 = peg$parse__();
+                          s19 = peg$parseRPAREN();
+                          if (s19 !== peg$FAILED) {
+                            s20 = peg$parse__();
+                            s21 = peg$parseRPAREN();
+                            if (s21 !== peg$FAILED) {
+                              peg$savedPos = s0;
+                              s0 = peg$f103(s5, s13, s17);
+                            } else {
+                              peg$currPos = s0;
+                              s0 = peg$FAILED;
+                            }
+                          } else {
+                            peg$currPos = s0;
+                            s0 = peg$FAILED;
+                          }
+                        } else {
+                          peg$currPos = s0;
+                          s0 = peg$FAILED;
+                        }
+                      } else {
+                        peg$currPos = s0;
+                        s0 = peg$FAILED;
+                      }
+                    } else {
+                      peg$currPos = s0;
+                      s0 = peg$FAILED;
+                    }
+                  } else {
+                    peg$currPos = s0;
+                    s0 = peg$FAILED;
+                  }
+                } else {
+                  peg$currPos = s0;
+                  s0 = peg$FAILED;
+                }
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+        if (s0 === peg$FAILED) {
+          s0 = peg$currPos;
+          s1 = peg$parseKW_CAST();
+          if (s1 !== peg$FAILED) {
+            s2 = peg$parse__();
+            s3 = peg$parseLPAREN();
+            if (s3 !== peg$FAILED) {
+              s4 = peg$parse__();
+              s5 = peg$parseexpr();
+              if (s5 !== peg$FAILED) {
+                s6 = peg$parse__();
+                s7 = peg$parseKW_AS();
+                if (s7 !== peg$FAILED) {
+                  s8 = peg$parse__();
+                  s9 = peg$parsesignedness();
+                  if (s9 !== peg$FAILED) {
+                    s10 = peg$parse__();
+                    s11 = peg$parseKW_INTEGER();
+                    if (s11 === peg$FAILED) {
+                      s11 = null;
+                    }
+                    s12 = peg$parse__();
+                    s13 = peg$parseRPAREN();
+                    if (s13 !== peg$FAILED) {
+                      peg$savedPos = s0;
+                      s0 = peg$f104(s5, s9, s11);
+                    } else {
+                      peg$currPos = s0;
+                      s0 = peg$FAILED;
+                    }
+                  } else {
+                    peg$currPos = s0;
+                    s0 = peg$FAILED;
+                  }
+                } else {
+                  peg$currPos = s0;
+                  s0 = peg$FAILED;
+                }
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsesignedness() {
+    var s0;
+
+    s0 = peg$parseKW_SIGNED();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_UNSIGNED();
+    }
+
+    return s0;
+  }
+
+  function peg$parseliteral() {
+    var s0;
+
+    s0 = peg$parseliteral_string();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseliteral_numeric();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parseliteral_bool();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseliteral_null();
+          if (s0 === peg$FAILED) {
+            s0 = peg$parseliteral_datetime();
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseliteral_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseliteral();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseliteral();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseliteral();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f105(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseliteral_null() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_NULL();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f106();
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parseliteral_bool() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_TRUE();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f107();
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseKW_FALSE();
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f108();
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parseliteral_string() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 39) {
+      s2 = peg$c16;
+      peg$currPos++;
+    } else {
+      s2 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e17); }
+    }
+    if (s2 !== peg$FAILED) {
+      s3 = [];
+      s4 = peg$parsesingle_char();
+      while (s4 !== peg$FAILED) {
+        s3.push(s4);
+        s4 = peg$parsesingle_char();
+      }
+      if (input.charCodeAt(peg$currPos) === 39) {
+        s4 = peg$c16;
+        peg$currPos++;
+      } else {
+        s4 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e17); }
+      }
+      if (s4 !== peg$FAILED) {
+        s2 = [s2, s3, s4];
+        s1 = s2;
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s1;
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f109(s1);
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$currPos;
+      if (input.charCodeAt(peg$currPos) === 34) {
+        s2 = peg$c15;
+        peg$currPos++;
+      } else {
+        s2 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e15); }
+      }
+      if (s2 !== peg$FAILED) {
+        s3 = [];
+        s4 = peg$parsesingle_quote_char();
+        while (s4 !== peg$FAILED) {
+          s3.push(s4);
+          s4 = peg$parsesingle_quote_char();
+        }
+        if (input.charCodeAt(peg$currPos) === 34) {
+          s4 = peg$c15;
+          peg$currPos++;
+        } else {
+          s4 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e15); }
+        }
+        if (s4 !== peg$FAILED) {
+          s2 = [s2, s3, s4];
+          s1 = s2;
+        } else {
+          peg$currPos = s1;
+          s1 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s1;
+        s1 = peg$FAILED;
+      }
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f110(s1);
+      }
+      s0 = s1;
+    }
+
+    return s0;
+  }
+
+  function peg$parseliteral_datetime() {
+    var s0, s1, s2, s3, s4, s5, s6;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_TIME();
+    if (s1 === peg$FAILED) {
+      s1 = peg$parseKW_DATE();
+      if (s1 === peg$FAILED) {
+        s1 = peg$parseKW_TIMESTAMP();
+      }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$currPos;
+      if (input.charCodeAt(peg$currPos) === 39) {
+        s4 = peg$c16;
+        peg$currPos++;
+      } else {
+        s4 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e17); }
+      }
+      if (s4 !== peg$FAILED) {
+        s5 = [];
+        s6 = peg$parsesingle_char();
+        while (s6 !== peg$FAILED) {
+          s5.push(s6);
+          s6 = peg$parsesingle_char();
+        }
+        if (input.charCodeAt(peg$currPos) === 39) {
+          s6 = peg$c16;
+          peg$currPos++;
+        } else {
+          s6 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e17); }
+        }
+        if (s6 !== peg$FAILED) {
+          s4 = [s4, s5, s6];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f111(s1, s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsesingle_quote_char() {
+    var s0;
+
+    if (peg$r6.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e25); }
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseescape_char();
+    }
+
+    return s0;
+  }
+
+  function peg$parsesingle_char() {
+    var s0;
+
+    if (peg$r7.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e26); }
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseescape_char();
+    }
+
+    return s0;
+  }
+
+  function peg$parseescape_char() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2) === peg$c19) {
+      s1 = peg$c19;
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e27); }
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f112();
+    }
+    s0 = s1;
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      if (input.substr(peg$currPos, 2) === peg$c20) {
+        s1 = peg$c20;
+        peg$currPos += 2;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e28); }
+      }
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f113();
+      }
+      s0 = s1;
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        if (input.substr(peg$currPos, 2) === peg$c21) {
+          s1 = peg$c21;
+          peg$currPos += 2;
+        } else {
+          s1 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e29); }
+        }
+        if (s1 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s1 = peg$f114();
+        }
+        s0 = s1;
+        if (s0 === peg$FAILED) {
+          s0 = peg$currPos;
+          if (input.substr(peg$currPos, 2) === peg$c22) {
+            s1 = peg$c22;
+            peg$currPos += 2;
+          } else {
+            s1 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e30); }
+          }
+          if (s1 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s1 = peg$f115();
+          }
+          s0 = s1;
+          if (s0 === peg$FAILED) {
+            s0 = peg$currPos;
+            if (input.substr(peg$currPos, 2) === peg$c23) {
+              s1 = peg$c23;
+              peg$currPos += 2;
+            } else {
+              s1 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$e31); }
+            }
+            if (s1 !== peg$FAILED) {
+              peg$savedPos = s0;
+              s1 = peg$f116();
+            }
+            s0 = s1;
+            if (s0 === peg$FAILED) {
+              s0 = peg$currPos;
+              if (input.substr(peg$currPos, 2) === peg$c24) {
+                s1 = peg$c24;
+                peg$currPos += 2;
+              } else {
+                s1 = peg$FAILED;
+                if (peg$silentFails === 0) { peg$fail(peg$e32); }
+              }
+              if (s1 !== peg$FAILED) {
+                peg$savedPos = s0;
+                s1 = peg$f117();
+              }
+              s0 = s1;
+              if (s0 === peg$FAILED) {
+                s0 = peg$currPos;
+                if (input.substr(peg$currPos, 2) === peg$c25) {
+                  s1 = peg$c25;
+                  peg$currPos += 2;
+                } else {
+                  s1 = peg$FAILED;
+                  if (peg$silentFails === 0) { peg$fail(peg$e33); }
+                }
+                if (s1 !== peg$FAILED) {
+                  peg$savedPos = s0;
+                  s1 = peg$f118();
+                }
+                s0 = s1;
+                if (s0 === peg$FAILED) {
+                  s0 = peg$currPos;
+                  if (input.substr(peg$currPos, 2) === peg$c26) {
+                    s1 = peg$c26;
+                    peg$currPos += 2;
+                  } else {
+                    s1 = peg$FAILED;
+                    if (peg$silentFails === 0) { peg$fail(peg$e34); }
+                  }
+                  if (s1 !== peg$FAILED) {
+                    peg$savedPos = s0;
+                    s1 = peg$f119();
+                  }
+                  s0 = s1;
+                  if (s0 === peg$FAILED) {
+                    s0 = peg$currPos;
+                    if (input.substr(peg$currPos, 2) === peg$c27) {
+                      s1 = peg$c27;
+                      peg$currPos += 2;
+                    } else {
+                      s1 = peg$FAILED;
+                      if (peg$silentFails === 0) { peg$fail(peg$e35); }
+                    }
+                    if (s1 !== peg$FAILED) {
+                      peg$savedPos = s0;
+                      s1 = peg$f120();
+                    }
+                    s0 = s1;
+                    if (s0 === peg$FAILED) {
+                      s0 = peg$currPos;
+                      if (input.substr(peg$currPos, 2) === peg$c28) {
+                        s1 = peg$c28;
+                        peg$currPos += 2;
+                      } else {
+                        s1 = peg$FAILED;
+                        if (peg$silentFails === 0) { peg$fail(peg$e36); }
+                      }
+                      if (s1 !== peg$FAILED) {
+                        s2 = peg$parsehexDigit();
+                        if (s2 !== peg$FAILED) {
+                          s3 = peg$parsehexDigit();
+                          if (s3 !== peg$FAILED) {
+                            s4 = peg$parsehexDigit();
+                            if (s4 !== peg$FAILED) {
+                              s5 = peg$parsehexDigit();
+                              if (s5 !== peg$FAILED) {
+                                peg$savedPos = s0;
+                                s0 = peg$f121(s2, s3, s4, s5);
+                              } else {
+                                peg$currPos = s0;
+                                s0 = peg$FAILED;
+                              }
+                            } else {
+                              peg$currPos = s0;
+                              s0 = peg$FAILED;
+                            }
+                          } else {
+                            peg$currPos = s0;
+                            s0 = peg$FAILED;
+                          }
+                        } else {
+                          peg$currPos = s0;
+                          s0 = peg$FAILED;
+                        }
+                      } else {
+                        peg$currPos = s0;
+                        s0 = peg$FAILED;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseline_terminator() {
+    var s0;
+
+    if (peg$r8.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e37); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseliteral_numeric() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parsenumber();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f122(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsenumber() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = peg$parseint();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parsefrac();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parseexp();
+        if (s3 !== peg$FAILED) {
+          s4 = peg$parse__();
+          peg$savedPos = s0;
+          s0 = peg$f123(s1, s2, s3);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseint();
+      if (s1 !== peg$FAILED) {
+        s2 = peg$parsefrac();
+        if (s2 !== peg$FAILED) {
+          s3 = peg$parse__();
+          peg$savedPos = s0;
+          s0 = peg$f124(s1, s2);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parseint();
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parseexp();
+          if (s2 !== peg$FAILED) {
+            s3 = peg$parse__();
+            peg$savedPos = s0;
+            s0 = peg$f125(s1, s2);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+        if (s0 === peg$FAILED) {
+          s0 = peg$currPos;
+          s1 = peg$parseint();
+          if (s1 !== peg$FAILED) {
+            s2 = peg$parse__();
+            peg$savedPos = s0;
+            s0 = peg$f126(s1);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseint() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parsedigit19();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parsedigits();
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f127(s1, s2);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsedigit();
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        if (input.charCodeAt(peg$currPos) === 45) {
+          s1 = peg$c11;
+          peg$currPos++;
+        } else {
+          s1 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e11); }
+        }
+        if (s1 === peg$FAILED) {
+          if (input.charCodeAt(peg$currPos) === 43) {
+            s1 = peg$c10;
+            peg$currPos++;
+          } else {
+            s1 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e10); }
+          }
+        }
+        if (s1 !== peg$FAILED) {
+          s2 = peg$parsedigit19();
+          if (s2 !== peg$FAILED) {
+            s3 = peg$parsedigits();
+            if (s3 !== peg$FAILED) {
+              peg$savedPos = s0;
+              s0 = peg$f128(s1, s2, s3);
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+        if (s0 === peg$FAILED) {
+          s0 = peg$currPos;
+          if (input.charCodeAt(peg$currPos) === 45) {
+            s1 = peg$c11;
+            peg$currPos++;
+          } else {
+            s1 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e11); }
+          }
+          if (s1 === peg$FAILED) {
+            if (input.charCodeAt(peg$currPos) === 43) {
+              s1 = peg$c10;
+              peg$currPos++;
+            } else {
+              s1 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$e10); }
+            }
+          }
+          if (s1 !== peg$FAILED) {
+            s2 = peg$parsedigit();
+            if (s2 !== peg$FAILED) {
+              peg$savedPos = s0;
+              s0 = peg$f129(s1, s2);
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsefrac() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 46) {
+      s1 = peg$c29;
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e38); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parsedigits();
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f130(s2);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseexp() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    s1 = peg$parsee();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parsedigits();
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f131(s1, s2);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsedigits() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    s1 = [];
+    s2 = peg$parsedigit();
+    if (s2 !== peg$FAILED) {
+      while (s2 !== peg$FAILED) {
+        s1.push(s2);
+        s2 = peg$parsedigit();
+      }
+    } else {
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f132(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsedigit() {
+    var s0;
+
+    if (peg$r9.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e39); }
+    }
+
+    return s0;
+  }
+
+  function peg$parsedigit19() {
+    var s0;
+
+    if (peg$r10.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e40); }
+    }
+
+    return s0;
+  }
+
+  function peg$parsehexDigit() {
+    var s0;
+
+    if (peg$r11.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e41); }
+    }
+
+    return s0;
+  }
+
+  function peg$parsee() {
+    var s0, s1, s2;
+
+    s0 = peg$currPos;
+    if (peg$r12.test(input.charAt(peg$currPos))) {
+      s1 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e42); }
+    }
+    if (s1 !== peg$FAILED) {
+      if (peg$r13.test(input.charAt(peg$currPos))) {
+        s2 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s2 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e43); }
+      }
+      if (s2 === peg$FAILED) {
+        s2 = null;
+      }
+      peg$savedPos = s0;
+      s0 = peg$f133(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_NULL() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c30) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e44); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_TRUE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c31) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e45); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_FALSE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c32) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e46); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SHOW() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c33) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e47); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_DROP() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c34) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e48); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SELECT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c35) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e49); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UPDATE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c36) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e50); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CREATE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c37) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e51); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_DELETE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c38) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e52); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_INSERT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c39) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e53); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_RECURSIVE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 9) === peg$c40) {
+      s1 = peg$c40;
+      peg$currPos += 9;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e54); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_REPLACE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c41) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e55); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_EXPLAIN() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c42) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e56); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_INTO() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c43) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e57); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_FROM() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c44) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e58); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SET() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c45) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e59); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_AS() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2).toLowerCase() === peg$c46) {
+      s1 = input.substr(peg$currPos, 2);
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e60); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_TABLE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c47) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e61); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_ON() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2).toLowerCase() === peg$c48) {
+      s1 = input.substr(peg$currPos, 2);
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e62); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_LEFT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c49) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e63); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_RIGHT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c50) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e64); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_FULL() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c51) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e65); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_INNER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c52) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e66); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_JOIN() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c53) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e67); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_OUTER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c54) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e68); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNION() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c55) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e69); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_VALUES() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c56) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e70); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_USING() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c57) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e71); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_WHERE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c58) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e72); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_WITH() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c59) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e73); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_GROUP() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c60) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e74); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_BY() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2).toLowerCase() === peg$c61) {
+      s1 = input.substr(peg$currPos, 2);
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e75); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_ORDER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c62) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e76); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_HAVING() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c63) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e77); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_LIMIT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c64) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e78); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_ASC() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c65) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e79); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f134();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_DESC() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c66) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e80); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f135();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_ALL() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c67) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e81); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f136();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_DISTINCT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 8).toLowerCase() === peg$c68) {
+      s1 = input.substr(peg$currPos, 8);
+      peg$currPos += 8;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e82); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f137();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_BETWEEN() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c69) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e83); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f138();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_IN() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2).toLowerCase() === peg$c70) {
+      s1 = input.substr(peg$currPos, 2);
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e84); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f139();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_IS() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2).toLowerCase() === peg$c71) {
+      s1 = input.substr(peg$currPos, 2);
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e85); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f140();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_LIKE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c72) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e86); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f141();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_EXISTS() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c73) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e87); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f142();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_NOT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c74) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e88); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f143();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_AND() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c75) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e89); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f144();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_OR() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2).toLowerCase() === peg$c76) {
+      s1 = input.substr(peg$currPos, 2);
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e90); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f145();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_COUNT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c77) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e91); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f146();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_MAX() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c78) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e92); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f147();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_MIN() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c79) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e93); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f148();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SUM() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c80) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e94); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f149();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_AVG() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c81) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e95); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f150();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CASE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c82) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e96); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_WHEN() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c83) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e97); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_THEN() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c84) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e98); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_ELSE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c85) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e99); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_END() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c86) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e100); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CAST() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c87) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e101); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        s1 = [s1, s2];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CHAR() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c88) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e102); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f151();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_VARCHAR() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c89) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e103); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f152();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_NUMERIC() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c90) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e104); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f153();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_DECIMAL() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c91) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e105); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f154();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SIGNED() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c92) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e106); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f155();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNSIGNED() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 8).toLowerCase() === peg$c93) {
+      s1 = input.substr(peg$currPos, 8);
+      peg$currPos += 8;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e107); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f156();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_INT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c94) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e108); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f157();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_INTEGER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c95) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e109); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f158();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_JSON() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c96) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e110); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f159();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SMALLINT() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 8).toLowerCase() === peg$c97) {
+      s1 = input.substr(peg$currPos, 8);
+      peg$currPos += 8;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e111); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f160();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_DATE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c98) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e112); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f161();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_TIME() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c99) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e113); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f162();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_TIMESTAMP() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 9).toLowerCase() === peg$c100) {
+      s1 = input.substr(peg$currPos, 9);
+      peg$currPos += 9;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e114); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f163();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_USER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c101) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e115); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f164();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CURRENT_DATE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 12).toLowerCase() === peg$c102) {
+      s1 = input.substr(peg$currPos, 12);
+      peg$currPos += 12;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e116); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f165();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_ADD_DATE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c103) {
+      s1 = input.substr(peg$currPos, 7);
+      peg$currPos += 7;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e117); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f166();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_INTERVAL() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 8).toLowerCase() === peg$c104) {
+      s1 = input.substr(peg$currPos, 8);
+      peg$currPos += 8;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e118); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f167();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNIT_YEAR() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c105) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e119); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f168();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNIT_MONTH() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c106) {
+      s1 = input.substr(peg$currPos, 5);
+      peg$currPos += 5;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e120); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f169();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNIT_DAY() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 3).toLowerCase() === peg$c107) {
+      s1 = input.substr(peg$currPos, 3);
+      peg$currPos += 3;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e121); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f170();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNIT_HOUR() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c108) {
+      s1 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e122); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f171();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNIT_MINUTE() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c109) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e123); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f172();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_UNIT_SECOND() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c110) {
+      s1 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e124); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f173();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CURRENT_TIME() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 12).toLowerCase() === peg$c111) {
+      s1 = input.substr(peg$currPos, 12);
+      peg$currPos += 12;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e125); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f174();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CURRENT_TIMESTAMP() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 17).toLowerCase() === peg$c112) {
+      s1 = input.substr(peg$currPos, 17);
+      peg$currPos += 17;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e126); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f175();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_CURRENT_USER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 12).toLowerCase() === peg$c113) {
+      s1 = input.substr(peg$currPos, 12);
+      peg$currPos += 12;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e127); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f176();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SESSION_USER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 12).toLowerCase() === peg$c114) {
+      s1 = input.substr(peg$currPos, 12);
+      peg$currPos += 12;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e128); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f177();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_SYSTEM_USER() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 11).toLowerCase() === peg$c115) {
+      s1 = input.substr(peg$currPos, 11);
+      peg$currPos += 11;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e129); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$currPos;
+      peg$silentFails++;
+      s3 = peg$parseident_start();
+      peg$silentFails--;
+      if (s3 === peg$FAILED) {
+        s2 = undefined;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+      if (s2 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f178();
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_VAR_PRE() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 36) {
+      s0 = peg$c116;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e130); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_RETURN() {
+    var s0;
+
+    if (input.substr(peg$currPos, 6).toLowerCase() === peg$c117) {
+      s0 = input.substr(peg$currPos, 6);
+      peg$currPos += 6;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e131); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_ASSIGN() {
+    var s0;
+
+    if (input.substr(peg$currPos, 2) === peg$c118) {
+      s0 = peg$c118;
+      peg$currPos += 2;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e132); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseKW_DUAL() {
+    var s0;
+
+    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c119) {
+      s0 = input.substr(peg$currPos, 4);
+      peg$currPos += 4;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e133); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseOPT_SQL_CALC_FOUND_ROWS() {
+    var s0;
+
+    if (input.substr(peg$currPos, 19).toLowerCase() === peg$c120) {
+      s0 = input.substr(peg$currPos, 19);
+      peg$currPos += 19;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e134); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseOPT_SQL_CACHE() {
+    var s0;
+
+    if (input.substr(peg$currPos, 9).toLowerCase() === peg$c121) {
+      s0 = input.substr(peg$currPos, 9);
+      peg$currPos += 9;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e135); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseOPT_SQL_NO_CACHE() {
+    var s0;
+
+    if (input.substr(peg$currPos, 12).toLowerCase() === peg$c122) {
+      s0 = input.substr(peg$currPos, 12);
+      peg$currPos += 12;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e136); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseOPT_SQL_SMALL_RESULT() {
+    var s0;
+
+    if (input.substr(peg$currPos, 16).toLowerCase() === peg$c123) {
+      s0 = input.substr(peg$currPos, 16);
+      peg$currPos += 16;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e137); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseOPT_SQL_BIG_RESULT() {
+    var s0;
+
+    if (input.substr(peg$currPos, 14).toLowerCase() === peg$c124) {
+      s0 = input.substr(peg$currPos, 14);
+      peg$currPos += 14;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e138); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseOPT_SQL_BUFFER_RESULT() {
+    var s0;
+
+    if (input.substr(peg$currPos, 17).toLowerCase() === peg$c125) {
+      s0 = input.substr(peg$currPos, 17);
+      peg$currPos += 17;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e139); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseDOT() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 46) {
+      s0 = peg$c29;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e38); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseCOMMA() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 44) {
+      s0 = peg$c126;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e140); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseSTAR() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 42) {
+      s0 = peg$c12;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e12); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseLPAREN() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 40) {
+      s0 = peg$c0;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e0); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseRPAREN() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 41) {
+      s0 = peg$c1;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e1); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseLBRAKE() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 91) {
+      s0 = peg$c127;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e141); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseRBRAKE() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 93) {
+      s0 = peg$c128;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e142); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseSEMICOLON() {
+    var s0;
+
+    if (input.charCodeAt(peg$currPos) === 59) {
+      s0 = peg$c129;
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e143); }
+    }
+
+    return s0;
+  }
+
+  function peg$parse__() {
+    var s0, s1;
+
+    s0 = [];
+    s1 = peg$parsewhitespace();
+    if (s1 === peg$FAILED) {
+      s1 = peg$parsecomment();
+    }
+    while (s1 !== peg$FAILED) {
+      s0.push(s1);
+      s1 = peg$parsewhitespace();
+      if (s1 === peg$FAILED) {
+        s1 = peg$parsecomment();
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecomment() {
+    var s0;
+
+    s0 = peg$parseblock_comment();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseline_comment();
+    }
+
+    return s0;
+  }
+
+  function peg$parseblock_comment() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2) === peg$c130) {
+      s1 = peg$c130;
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e144); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$currPos;
+      peg$silentFails++;
+      if (input.substr(peg$currPos, 2) === peg$c131) {
+        s5 = peg$c131;
+        peg$currPos += 2;
+      } else {
+        s5 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e145); }
+      }
+      peg$silentFails--;
+      if (s5 === peg$FAILED) {
+        s4 = undefined;
+      } else {
+        peg$currPos = s4;
+        s4 = peg$FAILED;
+      }
+      if (s4 !== peg$FAILED) {
+        s5 = peg$parsechar();
+        if (s5 !== peg$FAILED) {
+          s4 = [s4, s5];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$currPos;
+        peg$silentFails++;
+        if (input.substr(peg$currPos, 2) === peg$c131) {
+          s5 = peg$c131;
+          peg$currPos += 2;
+        } else {
+          s5 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e145); }
+        }
+        peg$silentFails--;
+        if (s5 === peg$FAILED) {
+          s4 = undefined;
+        } else {
+          peg$currPos = s4;
+          s4 = peg$FAILED;
+        }
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parsechar();
+          if (s5 !== peg$FAILED) {
+            s4 = [s4, s5];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      if (input.substr(peg$currPos, 2) === peg$c131) {
+        s3 = peg$c131;
+        peg$currPos += 2;
+      } else {
+        s3 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e145); }
+      }
+      if (s3 !== peg$FAILED) {
+        s1 = [s1, s2, s3];
+        s0 = s1;
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseline_comment() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    if (input.substr(peg$currPos, 2) === peg$c132) {
+      s1 = peg$c132;
+      peg$currPos += 2;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e146); }
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$currPos;
+      peg$silentFails++;
+      s5 = peg$parseEOL();
+      peg$silentFails--;
+      if (s5 === peg$FAILED) {
+        s4 = undefined;
+      } else {
+        peg$currPos = s4;
+        s4 = peg$FAILED;
+      }
+      if (s4 !== peg$FAILED) {
+        s5 = peg$parsechar();
+        if (s5 !== peg$FAILED) {
+          s4 = [s4, s5];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$currPos;
+        peg$silentFails++;
+        s5 = peg$parseEOL();
+        peg$silentFails--;
+        if (s5 === peg$FAILED) {
+          s4 = undefined;
+        } else {
+          peg$currPos = s4;
+          s4 = peg$FAILED;
+        }
+        if (s4 !== peg$FAILED) {
+          s5 = peg$parsechar();
+          if (s5 !== peg$FAILED) {
+            s4 = [s4, s5];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      s1 = [s1, s2];
+      s0 = s1;
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsechar() {
+    var s0;
+
+    if (input.length > peg$currPos) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e147); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseinterval_unit() {
+    var s0;
+
+    s0 = peg$parseKW_UNIT_YEAR();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseKW_UNIT_MONTH();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parseKW_UNIT_DAY();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseKW_UNIT_HOUR();
+          if (s0 === peg$FAILED) {
+            s0 = peg$parseKW_UNIT_MINUTE();
+            if (s0 === peg$FAILED) {
+              s0 = peg$parseKW_UNIT_SECOND();
+            }
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsewhitespace() {
+    var s0;
+
+    if (peg$r14.test(input.charAt(peg$currPos))) {
+      s0 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s0 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e148); }
+    }
+
+    return s0;
+  }
+
+  function peg$parseEOL() {
+    var s0, s1;
+
+    s0 = peg$parseEOF();
+    if (s0 === peg$FAILED) {
+      s0 = [];
+      if (peg$r8.test(input.charAt(peg$currPos))) {
+        s1 = input.charAt(peg$currPos);
+        peg$currPos++;
+      } else {
+        s1 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e37); }
+      }
+      if (s1 !== peg$FAILED) {
+        while (s1 !== peg$FAILED) {
+          s0.push(s1);
+          if (peg$r8.test(input.charAt(peg$currPos))) {
+            s1 = input.charAt(peg$currPos);
+            peg$currPos++;
+          } else {
+            s1 = peg$FAILED;
+            if (peg$silentFails === 0) { peg$fail(peg$e37); }
+          }
+        }
+      } else {
+        s0 = peg$FAILED;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseEOF() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    peg$silentFails++;
+    if (input.length > peg$currPos) {
+      s1 = input.charAt(peg$currPos);
+      peg$currPos++;
+    } else {
+      s1 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e147); }
+    }
+    peg$silentFails--;
+    if (s1 === peg$FAILED) {
+      s0 = undefined;
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_stmts() {
+    var s0, s1;
+
+    s0 = [];
+    s1 = peg$parseproc_stmt();
+    while (s1 !== peg$FAILED) {
+      s0.push(s1);
+      s1 = peg$parseproc_stmt();
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_stmt() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    peg$savedPos = peg$currPos;
+    s1 = peg$f179();
+    if (s1) {
+      s1 = undefined;
+    } else {
+      s1 = peg$FAILED;
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseassign_stmt();
+      if (s3 === peg$FAILED) {
+        s3 = peg$parsereturn_stmt();
+      }
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f180(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseassign_stmt() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parsevar_decl();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseKW_ASSIGN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseproc_expr();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f181(s1, s5);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsereturn_stmt() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_RETURN();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseproc_expr();
+      if (s3 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s0 = peg$f182(s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_expr() {
+    var s0;
+
+    s0 = peg$parseselect_stmt();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parseproc_join();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parseproc_additive_expr();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseproc_array();
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_additive_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseproc_multiplicative_expr();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseadditive_operator();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseproc_multiplicative_expr();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseadditive_operator();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseproc_multiplicative_expr();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f183(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_multiplicative_expr() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseproc_primary();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parsemultiplicative_operator();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseproc_primary();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parsemultiplicative_operator();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseproc_primary();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f184(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_join() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parsevar_decl();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parsejoin_op();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parsevar_decl();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseon_clause();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f185(s1, s3, s5, s7);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_primary() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$parseliteral();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsevar_decl();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parseproc_func_call();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parseparam();
+          if (s0 === peg$FAILED) {
+            s0 = peg$currPos;
+            s1 = peg$parseLPAREN();
+            if (s1 !== peg$FAILED) {
+              s2 = peg$parse__();
+              s3 = peg$parseproc_additive_expr();
+              if (s3 !== peg$FAILED) {
+                s4 = peg$parse__();
+                s5 = peg$parseRPAREN();
+                if (s5 !== peg$FAILED) {
+                  peg$savedPos = s0;
+                  s0 = peg$f186(s3);
+                } else {
+                  peg$currPos = s0;
+                  s0 = peg$FAILED;
+                }
+              } else {
+                peg$currPos = s0;
+                s0 = peg$FAILED;
+              }
+            } else {
+              peg$currPos = s0;
+              s0 = peg$FAILED;
+            }
+          }
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_func_call() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseident();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseproc_primary_list();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseRPAREN();
+          if (s7 !== peg$FAILED) {
+            peg$savedPos = s0;
+            s0 = peg$f187(s1, s5);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_primary_list() {
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+
+    s0 = peg$currPos;
+    s1 = peg$parseproc_primary();
+    if (s1 !== peg$FAILED) {
+      s2 = [];
+      s3 = peg$currPos;
+      s4 = peg$parse__();
+      s5 = peg$parseCOMMA();
+      if (s5 !== peg$FAILED) {
+        s6 = peg$parse__();
+        s7 = peg$parseproc_primary();
+        if (s7 !== peg$FAILED) {
+          s4 = [s4, s5, s6, s7];
+          s3 = s4;
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s3;
+        s3 = peg$FAILED;
+      }
+      while (s3 !== peg$FAILED) {
+        s2.push(s3);
+        s3 = peg$currPos;
+        s4 = peg$parse__();
+        s5 = peg$parseCOMMA();
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseproc_primary();
+          if (s7 !== peg$FAILED) {
+            s4 = [s4, s5, s6, s7];
+            s3 = s4;
+          } else {
+            peg$currPos = s3;
+            s3 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s3;
+          s3 = peg$FAILED;
+        }
+      }
+      peg$savedPos = s0;
+      s0 = peg$f188(s1, s2);
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parseproc_array() {
+    var s0, s1, s2, s3, s4, s5;
+
+    s0 = peg$currPos;
+    s1 = peg$parseLBRAKE();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseproc_primary_list();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = peg$parseRBRAKE();
+        if (s5 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s0 = peg$f189(s3);
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsevar_decl() {
+    var s0, s1, s2, s3;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_VAR_PRE();
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parseident_name();
+      if (s2 !== peg$FAILED) {
+        s3 = peg$parsemem_chain();
+        peg$savedPos = s0;
+        s0 = peg$f190(s2, s3);
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+
+    return s0;
+  }
+
+  function peg$parsemem_chain() {
+    var s0, s1, s2, s3, s4;
+
+    s0 = peg$currPos;
+    s1 = [];
+    s2 = peg$currPos;
+    if (input.charCodeAt(peg$currPos) === 46) {
+      s3 = peg$c29;
+      peg$currPos++;
+    } else {
+      s3 = peg$FAILED;
+      if (peg$silentFails === 0) { peg$fail(peg$e38); }
+    }
+    if (s3 !== peg$FAILED) {
+      s4 = peg$parseident_name();
+      if (s4 !== peg$FAILED) {
+        s3 = [s3, s4];
+        s2 = s3;
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s2;
+      s2 = peg$FAILED;
+    }
+    while (s2 !== peg$FAILED) {
+      s1.push(s2);
+      s2 = peg$currPos;
+      if (input.charCodeAt(peg$currPos) === 46) {
+        s3 = peg$c29;
+        peg$currPos++;
+      } else {
+        s3 = peg$FAILED;
+        if (peg$silentFails === 0) { peg$fail(peg$e38); }
+      }
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parseident_name();
+        if (s4 !== peg$FAILED) {
+          s3 = [s3, s4];
+          s2 = s3;
+        } else {
+          peg$currPos = s2;
+          s2 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s2;
+        s2 = peg$FAILED;
+      }
+    }
+    peg$savedPos = s0;
+    s1 = peg$f191(s1);
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsedata_type() {
+    var s0;
+
+    s0 = peg$parsecharacter_string_type();
+    if (s0 === peg$FAILED) {
+      s0 = peg$parsenumeric_type();
+      if (s0 === peg$FAILED) {
+        s0 = peg$parsedatetime_type();
+        if (s0 === peg$FAILED) {
+          s0 = peg$parsejson_type();
+        }
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsecharacter_string_type() {
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_CHAR();
+    if (s1 === peg$FAILED) {
+      s1 = peg$parseKW_VARCHAR();
+    }
+    if (s1 !== peg$FAILED) {
+      s2 = peg$parse__();
+      s3 = peg$parseLPAREN();
+      if (s3 !== peg$FAILED) {
+        s4 = peg$parse__();
+        s5 = [];
+        if (peg$r9.test(input.charAt(peg$currPos))) {
+          s6 = input.charAt(peg$currPos);
+          peg$currPos++;
+        } else {
+          s6 = peg$FAILED;
+          if (peg$silentFails === 0) { peg$fail(peg$e39); }
+        }
+        if (s6 !== peg$FAILED) {
+          while (s6 !== peg$FAILED) {
+            s5.push(s6);
+            if (peg$r9.test(input.charAt(peg$currPos))) {
+              s6 = input.charAt(peg$currPos);
+              peg$currPos++;
+            } else {
+              s6 = peg$FAILED;
+              if (peg$silentFails === 0) { peg$fail(peg$e39); }
+            }
+          }
+        } else {
+          s5 = peg$FAILED;
+        }
+        if (s5 !== peg$FAILED) {
+          s6 = peg$parse__();
+          s7 = peg$parseRPAREN();
+          if (s7 !== peg$FAILED) {
+            s8 = peg$parse__();
+            peg$savedPos = s0;
+            s0 = peg$f192(s1, s5);
+          } else {
+            peg$currPos = s0;
+            s0 = peg$FAILED;
+          }
+        } else {
+          peg$currPos = s0;
+          s0 = peg$FAILED;
+        }
+      } else {
+        peg$currPos = s0;
+        s0 = peg$FAILED;
+      }
+    } else {
+      peg$currPos = s0;
+      s0 = peg$FAILED;
+    }
+    if (s0 === peg$FAILED) {
+      s0 = peg$currPos;
+      s1 = peg$parseKW_CHAR();
+      if (s1 !== peg$FAILED) {
+        peg$savedPos = s0;
+        s1 = peg$f193(s1);
+      }
+      s0 = s1;
+      if (s0 === peg$FAILED) {
+        s0 = peg$currPos;
+        s1 = peg$parseKW_VARCHAR();
+        if (s1 !== peg$FAILED) {
+          peg$savedPos = s0;
+          s1 = peg$f194(s1);
+        }
+        s0 = s1;
+      }
+    }
+
+    return s0;
+  }
+
+  function peg$parsenumeric_type() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_NUMERIC();
+    if (s1 === peg$FAILED) {
+      s1 = peg$parseKW_DECIMAL();
+      if (s1 === peg$FAILED) {
+        s1 = peg$parseKW_INT();
+        if (s1 === peg$FAILED) {
+          s1 = peg$parseKW_INTEGER();
+          if (s1 === peg$FAILED) {
+            s1 = peg$parseKW_SMALLINT();
+          }
+        }
+      }
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f195(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsedatetime_type() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_DATE();
+    if (s1 === peg$FAILED) {
+      s1 = peg$parseKW_TIME();
+      if (s1 === peg$FAILED) {
+        s1 = peg$parseKW_TIMESTAMP();
+      }
+    }
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f196(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+  function peg$parsejson_type() {
+    var s0, s1;
+
+    s0 = peg$currPos;
+    s1 = peg$parseKW_JSON();
+    if (s1 !== peg$FAILED) {
+      peg$savedPos = s0;
+      s1 = peg$f197(s1);
+    }
+    s0 = s1;
+
+    return s0;
+  }
+
+
+  const reservedMap = {
+    'ALL': true,
+    'AND': true,
+    'AS': true,
+    'ASC': true,
+
+    'BETWEEN': true,
+    'BY': true,
+
+    'CASE': true,
+    'CREATE': true,
+    'CONTAINS': true,
+    'CURRENT_DATE': true,
+    'CURRENT_TIME': true,
+    'CURRENT_TIMESTAMP': true,
+    'CURRENT_USER': true,
+
+    'DELETE': true,
+    'DESC': true,
+    'DISTINCT': true,
+    'DROP': true,
+
+    'ELSE': true,
+    'END': true,
+    'EXISTS': true,
+    'EXPLAIN': true,
+
+    'FALSE': true,
+    'FROM': true,
+    'FULL': true,
+
+    'GROUP': true,
+
+    'HAVING': true,
+
+    'IN': true,
+    'INDEX': true,
+    'INNER': true,
+    'INSERT': true,
+    'INTO': true,
+    'IS': true,
+
+    'JOIN': true,
+    'JSON': true,
+
+    'LEFT': true,
+    'LIKE': true,
+    'LIMIT': true,
+
+    'NOT': true,
+    'NULL': true,
+
+    'ON': true,
+    'OR': true,
+    'ORDER': true,
+    'OUTER': true,
+
+    'RECURSIVE': true,
+    'REPLACE': true,
+    'RIGHT': true,
+
+    'SELECT': true,
+    'SESSION_USER': true,
+    'SET': true,
+    'SHOW': true,
+    'STATUS': true, // reserved (MySQL)
+    'SYSTEM_USER': true,
+
+    'TABLE': true,
+    'THEN': true,
+    'TRUE': true,
+    'TYPE': true,   // reserved (MySQL)
+
+    'UNION': true,
+    'UPDATE': true,
+    'USER': true,
+    'USING': true,
+
+    'VALUES': true,
+
+    'WITH': true,
+    'WHEN': true,
+    'WHERE': true
+  };
+
+  function createUnaryExpr(op, e) {
+    return {
+      type: 'unary_expr',
+      operator: op,
+      expr: e
+    };
+  }
+
+  function createBinaryExpr(op, left, right) {
+    return {
+      type: 'binary_expr',
+      operator: op,
+      left: left,
+      right: right
+    };
+  }
+
+  function createList(head, tail) {
+    const result = [head];
+    for (let i = 0; i < tail.length; i++) {
+      result.push(tail[i][3]);
+    }
+    return result;
+  }
+
+  function createBinaryExprChain(head, tail) {
+    let result = head;
+    for (let i = 0; i < tail.length; i++) {
+      result = createBinaryExpr(tail[i][1], result, tail[i][3]);
+    }
+    return result;
+  }
+
+  const cmpPrefixMap = {
+    '+': true,
+    '-': true,
+    '*': true,
+    '/': true,
+    '>': true,
+    '<': true,
+    '!': true,
+    '=': true,
+
+    //between
+    'B': true,
+    'b': true,
+    //for is or in
+    'I': true,
+    'i': true,
+    //for like
+    'L': true,
+    'l': true,
+    //for not
+    'N': true,
+    'n': true
+  };
+
+  // used for dependency analysis
+  let varList = [];
+
+  const tableList = new Set();
+  const columnList = new Set();
+
+  peg$result = peg$startRuleFunction();
+
+  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
+    return peg$result;
+  } else {
+    if (peg$result !== peg$FAILED && peg$currPos < input.length) {
+      peg$fail(peg$endExpectation());
+    }
+
+    throw peg$buildStructuredError(
+      peg$maxFailExpected,
+      peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
+      peg$maxFailPos < input.length
+        ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
+        : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
+    );
+  }
+}
+
+module.exports = {
+  SyntaxError: peg$SyntaxError,
+  parse: peg$parse
+};
diff --git a/packages/core/database/src/sql-parser/readme.md b/packages/core/database/src/sql-parser/readme.md
new file mode 100644
index 000000000..14f4c2b81
--- /dev/null
+++ b/packages/core/database/src/sql-parser/readme.md
@@ -0,0 +1,2 @@
+use peggy to transform pegjs to sql parser
+https://github.com/peggyjs/peggy
diff --git a/packages/core/database/src/sql-parser/sql.pegjs b/packages/core/database/src/sql-parser/sql.pegjs
new file mode 100644
index 000000000..22a45a4bc
--- /dev/null
+++ b/packages/core/database/src/sql-parser/sql.pegjs
@@ -0,0 +1,1297 @@
+{
+  const reservedMap = {
+    'ALL': true,
+    'AND': true,
+    'AS': true,
+    'ASC': true,
+
+    'BETWEEN': true,
+    'BY': true,
+
+    'CASE': true,
+    'CREATE': true,
+    'CONTAINS': true,
+    'CURRENT_DATE': true,
+    'CURRENT_TIME': true,
+    'CURRENT_TIMESTAMP': true,
+    'CURRENT_USER': true,
+
+    'DELETE': true,
+    'DESC': true,
+    'DISTINCT': true,
+    'DROP': true,
+
+    'ELSE': true,
+    'END': true,
+    'EXISTS': true,
+    'EXPLAIN': true,
+
+    'FALSE': true,
+    'FROM': true,
+    'FULL': true,
+
+    'GROUP': true,
+
+    'HAVING': true,
+
+    'IN': true,
+    'INDEX': true,
+    'INNER': true,
+    'INSERT': true,
+    'INTO': true,
+    'IS': true,
+
+    'JOIN': true,
+    'JSON': true,
+
+    'LEFT': true,
+    'LIKE': true,
+    'LIMIT': true,
+
+    'NOT': true,
+    'NULL': true,
+
+    'ON': true,
+    'OR': true,
+    'ORDER': true,
+    'OUTER': true,
+
+    'RECURSIVE': true,
+    'REPLACE': true,
+    'RIGHT': true,
+
+    'SELECT': true,
+    'SESSION_USER': true,
+    'SET': true,
+    'SHOW': true,
+    'STATUS': true, // reserved (MySQL)
+    'SYSTEM_USER': true,
+
+    'TABLE': true,
+    'THEN': true,
+    'TRUE': true,
+    'TYPE': true,   // reserved (MySQL)
+
+    'UNION': true,
+    'UPDATE': true,
+    'USER': true,
+    'USING': true,
+
+    'VALUES': true,
+
+    'WITH': true,
+    'WHEN': true,
+    'WHERE': true
+  };
+
+  function createUnaryExpr(op, e) {
+    return {
+      type: 'unary_expr',
+      operator: op,
+      expr: e
+    };
+  }
+
+  function createBinaryExpr(op, left, right) {
+    return {
+      type: 'binary_expr',
+      operator: op,
+      left: left,
+      right: right
+    };
+  }
+
+  function createList(head, tail) {
+    const result = [head];
+    for (let i = 0; i < tail.length; i++) {
+      result.push(tail[i][3]);
+    }
+    return result;
+  }
+
+  function createBinaryExprChain(head, tail) {
+    let result = head;
+    for (let i = 0; i < tail.length; i++) {
+      result = createBinaryExpr(tail[i][1], result, tail[i][3]);
+    }
+    return result;
+  }
+
+  const cmpPrefixMap = {
+    '+': true,
+    '-': true,
+    '*': true,
+    '/': true,
+    '>': true,
+    '<': true,
+    '!': true,
+    '=': true,
+
+    //between
+    'B': true,
+    'b': true,
+    //for is or in
+    'I': true,
+    'i': true,
+    //for like
+    'L': true,
+    'l': true,
+    //for not
+    'N': true,
+    'n': true
+  };
+
+  // used for dependency analysis
+  let varList = [];
+
+  const tableList = new Set();
+  const columnList = new Set();
+}
+
+start
+  = multiple_stmt
+  / crud_stmt
+
+crud_stmt
+  = union_stmt
+  / update_stmt
+  / replace_insert_stmt
+  / insert_no_columns_stmt
+  / delete_stmt
+  / proc_stmts
+
+multiple_stmt
+  = head:crud_stmt tail:(__ SEMICOLON __ crud_stmt)+ {
+      const cur = [head && head.ast || head];
+      for (let i = 0; i < tail.length; i++) {
+        if(!tail[i][3] || tail[i][3].length === 0) continue;
+        cur.push(tail[i][3] && tail[i][3].ast || tail[i][3]);
+      }
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+      	ast: cur
+      }
+    }
+
+union_stmt
+  = head:select_stmt tail:(__ KW_UNION __ select_stmt)* {
+      let cur = head;
+      for (let i = 0; i < tail.length; i++) {
+        cur._next = tail[i][3];
+        cur = cur._next
+      }
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+      	ast: head
+      }
+    }
+
+select_stmt
+  = select_stmt_nake
+  / s:('(' __ select_stmt __ ')') {
+      return s[2];
+    }
+
+with_clause
+  = KW_WITH __ head:cte_definition tail:(__ COMMA __ cte_definition)* {
+      return createList(head, tail);
+    }
+  / __ KW_WITH __ KW_RECURSIVE __ cte:cte_definition {
+      cte.recursive = true;
+      return [cte]
+    }
+
+cte_definition
+  = name:ident_name __ columns:cte_column_definition? __ KW_AS __ LPAREN __ stmt:union_stmt __ RPAREN {
+      return { name, stmt, columns };
+    }
+
+cte_column_definition
+  = LPAREN __ head:column tail:(__ COMMA __ column)* __ RPAREN {
+      return createList(head, tail);
+    }
+
+select_stmt_nake
+  = cte:with_clause? __ KW_SELECT __
+    opts:option_clause? __
+    d:KW_DISTINCT?      __
+    c:column_clause     __
+    f:from_clause?      __
+    w:where_clause?     __
+    g:group_by_clause?  __
+    h:having_clause?    __
+    o:order_by_clause?  __
+    l:limit_clause? {
+      if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`));
+      return {
+          with: cte,
+          type: 'select',
+          options: opts,
+          distinct: d,
+          columns: c,
+          from: f,
+          where: w,
+          groupby: g,
+          having: h,
+          orderby: o,
+          limit: l
+      };
+  }
+
+// MySQL extensions to standard SQL
+option_clause
+  = head:query_option tail:(__ query_option)* {
+    const opts = [head];
+    for (let i = 0, l = tail.length; i < l; ++i) {
+      opts.push(tail[i][1]);
+    }
+    return opts;
+  }
+
+query_option
+  = option:(
+        OPT_SQL_CALC_FOUND_ROWS
+        / (OPT_SQL_CACHE / OPT_SQL_NO_CACHE)
+        / OPT_SQL_BIG_RESULT
+        / OPT_SQL_SMALL_RESULT
+        / OPT_SQL_BUFFER_RESULT
+    ) { return option; }
+
+column_clause
+  = (KW_ALL / (STAR !ident_start) / STAR) {
+      columnList.add('select::null::(.*)');
+      return '*';
+    }
+  / head:column_list_item tail:(__ COMMA __ column_list_item)* {
+      return createList(head, tail);
+    }
+
+column_list_item
+  = tbl:ident __ DOT __ STAR {
+      columnList.add(`select::${tbl}::(.*)`);
+      return {
+        expr: {
+          type: 'column_ref',
+          table: tbl,
+          column: '*'
+        },
+        as: null
+      };
+    }
+  / e:expr __ alias:alias_clause? {
+      return { expr: e, as: alias };
+    }
+
+alias_clause
+  = KW_AS __ i:alias_ident { return i; }
+  / KW_AS? __ i:ident { return i; }
+
+from_clause
+  = KW_FROM __ l:table_ref_list { return l; }
+
+table_ref_list
+  = head:table_base
+    tail:table_ref* {
+      tail.unshift(head);
+      return tail;
+    }
+
+table_ref
+  = __ COMMA __ t:table_base { return t; }
+  / __ t:table_join { return t; }
+
+
+table_join
+  = op:join_op __ t:table_base __ KW_USING __ LPAREN __ head:ident_name tail:(__ COMMA __ ident_name)* __ RPAREN {
+      t.join = op;
+      t.using = createList(head, tail);
+      return t;
+    }
+  / op:join_op __ t:table_base __ expr:on_clause? {
+      t.join = op;
+      t.on   = expr;
+      return t;
+    }
+  / op:join_op __ LPAREN __ stmt:union_stmt __ RPAREN __ alias:alias_clause? __ expr:on_clause? {
+    stmt.parentheses = true;
+    return {
+      expr: stmt,
+      as: alias,
+      join: op,
+      on: expr
+    };
+  }
+
+//NOTE that, the table assigned to `var` shouldn't write in `table_join`
+table_base
+  = KW_DUAL {
+      return {
+        type: 'dual'
+      };
+  }
+  / t:table_name __ alias:alias_clause? {
+      if (t.type === 'var') {
+        t.as = alias;
+        return t;
+      } else {
+        return {
+          db: t.db,
+          table: t.table,
+          as: alias
+        };
+      }
+    }
+  / LPAREN __ stmt:union_stmt __ RPAREN __ alias:alias_clause? {
+      stmt.parentheses = true;
+      return {
+        expr: stmt,
+        as: alias
+      };
+    }
+
+join_op
+  = KW_LEFT __ KW_OUTER? __ KW_JOIN { return 'LEFT JOIN'; }
+  / KW_RIGHT __ KW_OUTER? __ KW_JOIN { return 'RIGHT JOIN'; }
+  / KW_FULL __ KW_OUTER? __ KW_JOIN { return 'FULL JOIN'; }
+  / (KW_INNER __)? KW_JOIN { return 'INNER JOIN'; }
+
+table_name
+  = dt:ident tail:(__ DOT __ ident)? {
+      const obj = { db: null, table: dt };
+      if (tail !== null) {
+        obj.db = dt;
+        obj.table = tail[3];
+      }
+      return obj;
+    }
+  / v:var_decl {
+      v.db = null;
+      v.table = v.name;
+      return v;
+    }
+
+on_clause
+  = KW_ON __ e:expr { return e; }
+
+where_clause
+  = KW_WHERE __ e:expr { return e; }
+
+group_by_clause
+  = KW_GROUP __ KW_BY __ l:column_ref_list { return l; }
+
+column_ref_list
+  = head:column_ref tail:(__ COMMA __ column_ref)* {
+      return createList(head, tail);
+    }
+
+having_clause
+  = KW_HAVING __ e:expr { return e; }
+
+order_by_clause
+  = KW_ORDER __ KW_BY __ l:order_by_list { return l; }
+
+order_by_list
+  = head:order_by_element tail:(__ COMMA __ order_by_element)* {
+      return createList(head, tail);
+    }
+
+order_by_element
+  = e:expr __ d:(KW_DESC / KW_ASC)? {
+    const obj = { expr: e, type: 'ASC' };
+    if (d === 'DESC') obj.type = 'DESC';
+    return obj;
+  }
+
+number_or_param
+  = literal_numeric
+  / param
+
+limit_clause
+  = KW_LIMIT __ i1:(number_or_param) __ tail:(COMMA __ number_or_param)? {
+      const res = [i1];
+      if (tail === null) res.unshift({ type: 'number', value: 0 });
+      else res.push(tail[2]);
+      return res;
+    }
+
+update_stmt
+  = KW_UPDATE    __
+    t:table_name __
+    KW_SET       __
+    l:set_list   __
+    w:where_clause? {
+      if(t.table) tableList.add(`update::${t.db}::${t.table}`);
+      if(l) l.forEach(col => columnList.add(`update::${t.table}::${col.column}`));
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: 'update',
+          db: t.db,
+          table: t.table,
+          set: l,
+          where: w
+        }
+      };
+    }
+
+delete_stmt
+  = KW_DELETE    __
+    t: table_ref_list? __
+    f:from_clause __
+    w:where_clause? {
+      if(f) f.forEach(info => {
+        info.table && tableList.add(`delete::${info.db}::${info.table}`);
+        columnList.add(`delete::${info.table}::(.*)`);
+      });
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: 'delete',
+          tables: t,
+          from: f,
+          where: w
+        }
+      };
+    }
+set_list
+  = head:set_item tail:(__ COMMA __ set_item)* {
+      return createList(head, tail);
+    }
+
+/**
+ * here only use `additive_expr` to support 'col1 = col1+2'
+ * if you want to use lower operator, please use '()' like below
+ * 'col1 = (col2 > 3)'
+ */
+set_item
+  = tbl:(ident __ DOT)? __ c:column_name __ '=' __ v:additive_expr {
+      return { column: c, value: v, table: tbl && tbl[0] };
+    }
+
+replace_insert_stmt
+  = ri:replace_insert       __
+    KW_INTO                 __
+    t:table_name  __ LPAREN __
+    c:column_list  __ RPAREN __
+    v:value_clause {
+      if (t.table) tableList.add(`insert::${t.db}::${t.table}`);
+      if (c) c.forEach(c => columnList.add(`insert::${t.table}::${c}`));
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: ri,
+          db: t.db,
+          table: t.table,
+          columns: c,
+          values: v
+        }
+      };
+    }
+
+insert_no_columns_stmt
+  = ri:replace_insert       __
+    KW_INTO                 __
+    t:table_name  __
+    v:value_clause {
+      if (t.table) tableList.add(`insert::${t.db}::${t.table}`);
+      columnList.add(`insert::${t.table}::(.*)`);
+      return {
+        tableList: Array.from(tableList),
+        columnList: Array.from(columnList),
+        ast: {
+          type: ri,
+          db: t.db,
+          table: t.table,
+          columns: null,
+          values: v
+        }
+      };
+    }
+
+replace_insert
+  = KW_INSERT   { return 'insert'; }
+  / KW_REPLACE  { return 'replace'; }
+
+value_clause
+  = KW_VALUES __ l:value_list  { return l; }
+
+value_list
+  = head:value_item tail:(__ COMMA __ value_item)* {
+      return createList(head, tail);
+    }
+
+value_item
+  = LPAREN __ l:expr_list  __ RPAREN {
+      return l;
+    }
+
+expr_list
+  = head:expr tail:(__ COMMA __ expr)* {
+      const el = { type: 'expr_list' };
+      el.value = createList(head, tail);
+      return el;
+    }
+
+interval_expr
+  = KW_INTERVAL                    __
+    n:number                       __
+    u: interval_unit {
+      return {
+        type: 'interval',
+        value: [n, u]
+      }
+    }
+
+case_expr
+  = KW_CASE                         __
+    expr:expr?                      __
+    condition_list:case_when_then+  __
+    otherwise:case_else?            __
+    KW_END __ KW_CASE? {
+      if (otherwise) condition_list.push(otherwise);
+      return {
+        type: 'case',
+        expr: expr || null,
+        args: condition_list
+      };
+    }
+
+case_when_then
+  = KW_WHEN __ condition:expr __ KW_THEN __ result:expr __ {
+    return {
+      type: 'when',
+      cond: condition,
+      result: result
+    };
+  }
+
+case_else = KW_ELSE __ result:expr {
+    return { type: 'else', result: result };
+  }
+
+/**
+ * Borrowed from PL/SQL ,the priority of below list IS ORDER BY DESC
+ * ---------------------------------------------------------------------------------------------------
+ * | +, -                                                     | identity, negation                   |
+ * | *, /                                                     | multiplication, division             |
+ * | +, -                                                     | addition, subtraction, concatenation |
+ * | =, <, >, <=, >=, <>, !=, IS, LIKE, BETWEEN, IN           | comparion                            |
+ * | !, NOT                                                   | logical negation                     |
+ * | AND                                                      | conjunction                          |
+ * | OR                                                       | inclusion                            |
+ * ---------------------------------------------------------------------------------------------------
+ */
+
+expr
+  = or_expr
+  / select_stmt
+
+or_expr
+  = head:and_expr tail:(__ KW_OR __ and_expr)* {
+      return createBinaryExprChain(head, tail);
+    }
+
+and_expr
+  = head:not_expr tail:(__ KW_AND __ not_expr)* {
+      return createBinaryExprChain(head, tail);
+    }
+
+//here we should use `NOT` instead of `comparision_expr` to support chain-expr
+not_expr
+  = comparison_expr
+  / exists_expr
+  / (KW_NOT / "!" !"=") __ expr:not_expr {
+      return createUnaryExpr('NOT', expr);
+    }
+
+comparison_expr
+  = left:additive_expr __ rh:comparison_op_right? {
+      if (rh === null) return left;
+      else if (rh.type === 'arithmetic') return createBinaryExprChain(left, rh.tail);
+      else return createBinaryExpr(rh.op, left, rh.right);
+    }
+
+exists_expr
+  = op:exists_op __ LPAREN __ stmt:union_stmt __ RPAREN {
+    stmt.parentheses = true;
+    return createUnaryExpr(op, stmt);
+  }
+
+exists_op
+  = nk:(KW_NOT __ KW_EXISTS) { return nk[0] + ' ' + nk[2]; }
+  / KW_EXISTS
+
+comparison_op_right
+  = arithmetic_op_right
+  / in_op_right
+  / between_op_right
+  / is_op_right
+  / like_op_right
+
+arithmetic_op_right
+  = l:(__ arithmetic_comparison_operator __ additive_expr)+ {
+      return { type: 'arithmetic', tail: l };
+    }
+
+arithmetic_comparison_operator
+  = ">=" / ">" / "<=" / "<>" / "<" / "=" / "!="
+
+is_op_right
+  = KW_IS __ right:additive_expr {
+      return { op: 'IS', right: right };
+    }
+  / (KW_IS __ KW_NOT) __ right:additive_expr {
+      return { op: 'IS NOT', right: right };
+  }
+
+between_op_right
+  = op:between_or_not_between_op __  begin:additive_expr __ KW_AND __ end:additive_expr {
+      return {
+        op: op,
+        right: {
+          type: 'expr_list',
+          value: [begin, end]
+        }
+      };
+    }
+
+between_or_not_between_op
+  = nk:(KW_NOT __ KW_BETWEEN) { return nk[0] + ' ' + nk[2]; }
+  / KW_BETWEEN
+
+like_op
+  = nk:(KW_NOT __ KW_LIKE) { return nk[0] + ' ' + nk[2]; }
+  / KW_LIKE
+
+in_op
+  = nk:(KW_NOT __ KW_IN) { return nk[0] + ' ' + nk[2]; }
+  / KW_IN
+
+like_op_right
+  = op:like_op __ right:comparison_expr {
+      return { op: op, right: right };
+    }
+
+in_op_right
+  = op:in_op __ LPAREN  __ l:expr_list __ RPAREN {
+      return { op: op, right: l };
+    }
+  / op:in_op __ e:var_decl {
+      return { op: op, right: e };
+    }
+
+additive_expr
+  = head:multiplicative_expr
+    tail:(__ additive_operator  __ multiplicative_expr)* {
+      return createBinaryExprChain(head, tail);
+    }
+
+additive_operator
+  = "+" / "-"
+
+multiplicative_expr
+  = head:primary
+    tail:(__ multiplicative_operator  __ primary)* {
+      return createBinaryExprChain(head, tail)
+    }
+
+multiplicative_operator
+  = "*" / "/" / "%"
+
+primary
+  = literal
+  / cast_expr
+  / aggr_func
+  / func_call
+  / case_expr
+  / interval_expr
+  / column_ref
+  / param
+  / LPAREN __ e:expr __ RPAREN {
+      e.parentheses = true;
+      return e;
+    }
+  / LPAREN __ list:expr_list __ RPAREN {
+        list.parentheses = true;
+        return list;
+    }
+  / var_decl
+
+column_ref
+  = tbl:ident __ DOT __ col:column {
+      columnList.add(`select::${tbl}::${col}`);
+      return {
+        type: 'column_ref',
+        table: tbl,
+        column: col
+      };
+    }
+  / col:column {
+      columnList.add(`select::null::${col}`);
+      return {
+        type: 'column_ref',
+        table: null,
+        column: col
+      };
+    }
+
+column_list
+  = head:column tail:(__ COMMA __ column)* {
+      return createList(head, tail);
+    }
+
+ident
+  = name:ident_name !{ return reservedMap[name.toUpperCase()] === true; } {
+      return name;
+    }
+  / name:quoted_ident {
+      return name;
+    }
+
+alias_ident
+  = name:ident_name !{
+      if (reservedMap[name.toUpperCase()] === true) throw new Error("Error: "+ JSON.stringify(name)+" is a reserved word, can not as alias clause");
+      return false
+    } {
+      return name;
+    }
+  / name:quoted_ident {
+      return name;
+    }
+
+quoted_ident
+  = double_quoted_ident
+  / single_quoted_ident
+  / backticks_quoted_ident
+
+double_quoted_ident
+  = '"' chars:[^"]+ '"' { return chars.join(''); }
+
+single_quoted_ident
+  = "'" chars:[^']+ "'" { return chars.join(''); }
+
+backticks_quoted_ident
+  = "`" chars:[^`]+ "`" { return chars.join(''); }
+
+column
+  = name:column_name !{ return reservedMap[name.toUpperCase()] === true; } { return name; }
+  / quoted_ident
+
+column_name
+  =  start:ident_start parts:column_part* { return start + parts.join(''); }
+
+ident_name
+  =  start:ident_start parts:ident_part* { return start + parts.join(''); }
+
+ident_start = [A-Za-z_]
+
+ident_part  = [A-Za-z0-9_]
+
+// to support column name like `cf1:name` in hbase
+column_part  = [A-Za-z0-9_:]
+
+param
+  = l:(':' ident_name) {
+      return { type: 'param', value: l[1] };
+    }
+
+aggr_func
+  = aggr_fun_count
+  / aggr_fun_smma
+
+aggr_fun_smma
+  = name:KW_SUM_MAX_MIN_AVG  __ LPAREN __ e:additive_expr __ RPAREN {
+      return {
+        type: 'aggr_func',
+        name: name,
+        args: {
+          expr: e
+        }
+      };
+    }
+
+KW_SUM_MAX_MIN_AVG
+  = KW_SUM / KW_MAX / KW_MIN / KW_AVG
+
+aggr_fun_count
+  = name:KW_COUNT __ LPAREN __ arg:count_arg __ RPAREN {
+      return {
+        type: 'aggr_func',
+        name: name,
+        args: arg
+      };
+    }
+
+count_arg
+  = e:star_expr { return { expr: e }; }
+  / d:KW_DISTINCT? __ c:column_ref { return { distinct: d, expr: c }; }
+
+star_expr
+  = "*" { return { type: 'star', value: '*' }; }
+
+func_call
+  = name:ident __ LPAREN __ l:expr_list? __ RPAREN {
+      return {
+        type: 'function',
+        name: name,
+        args: l ? l: { type: 'expr_list', value: [] }
+      };
+    }
+  / name:scalar_func (__ LPAREN RPAREN __)? {
+      return {
+        type: 'function',
+        name: name,
+        args: { type: 'expr_list', value: [] }
+      };
+    }
+
+scalar_func
+  = KW_CURRENT_DATE
+  / KW_CURRENT_TIME
+  / KW_CURRENT_TIMESTAMP
+  / KW_CURRENT_USER
+  / KW_USER
+  / KW_SESSION_USER
+  / KW_SYSTEM_USER
+
+cast_expr
+  = KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN {
+    return {
+      type: 'cast',
+      expr: e,
+      target: t
+    };
+  }
+  / KW_CAST __ LPAREN __ e:expr __ KW_AS __ KW_DECIMAL __ LPAREN __ precision:int __ RPAREN __ RPAREN {
+    return {
+      type: 'cast',
+      expr: e,
+      target: {
+        dataType: 'DECIMAL(' + precision + ')'
+      }
+    };
+  }
+  / KW_CAST __ LPAREN __ e:expr __ KW_AS __ KW_DECIMAL __ LPAREN __ precision:int __ COMMA __ scale:int __ RPAREN __ RPAREN {
+      return {
+        type: 'cast',
+        expr: e,
+        target: {
+          dataType: 'DECIMAL(' + precision + ', ' + scale + ')'
+        }
+      };
+    }
+  / KW_CAST __ LPAREN __ e:expr __ KW_AS __ s:signedness __ t:KW_INTEGER? __ RPAREN { /* MySQL cast to un-/signed integer */
+    return {
+      type: 'cast',
+      expr: e,
+      target: {
+        dataType: s + (t ? ' ' + t: '')
+      }
+    };
+  }
+
+signedness
+  = KW_SIGNED
+  / KW_UNSIGNED
+
+literal
+  = literal_string
+  / literal_numeric
+  / literal_bool
+  / literal_null
+  / literal_datetime
+
+literal_list
+  = head:literal tail:(__ COMMA __ literal)* {
+      return createList(head, tail);
+    }
+
+literal_null
+  = KW_NULL {
+      return { type: 'null', value: null };
+    }
+
+literal_bool
+  = KW_TRUE {
+      return { type: 'bool', value: true };
+    }
+  / KW_FALSE {
+      return { type: 'bool', value: false };
+    }
+
+literal_string
+  = ca:("'" single_char* "'") {
+      return {
+        type: 'string',
+        value: ca[1].join('')
+      };
+    }
+  / ca:("\"" single_quote_char* "\"") {
+      return {
+        type: 'string',
+        value: ca[1].join('')
+      };
+    }
+
+literal_datetime
+  = type:(KW_TIME / KW_DATE / KW_TIMESTAMP) __ ca:("'" single_char* "'") {
+      return {
+        type: type.toLowerCase(),
+        value: ca[1].join('')
+      };
+    }
+
+single_quote_char
+  = [^"\\\0-\x1F\x7f]
+  / escape_char
+
+single_char
+  = [^'\\\0-\x1F\x7f]
+  / escape_char
+
+escape_char
+  = "\\'"  { return "'";  }
+  / '\\"'  { return '"';  }
+  / "\\\\" { return "\\"; }
+  / "\\/"  { return "/";  }
+  / "\\b"  { return "\b"; }
+  / "\\f"  { return "\f"; }
+  / "\\n"  { return "\n"; }
+  / "\\r"  { return "\r"; }
+  / "\\t"  { return "\t"; }
+  / "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit {
+      return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
+    }
+
+line_terminator
+  = [\n\r]
+
+literal_numeric
+  = n:number {
+      return { type: 'number', value: n };
+    }
+
+number
+  = int_:int frac:frac exp:exp __ { return parseFloat(int_ + frac + exp); }
+  / int_:int frac:frac __         { return parseFloat(int_ + frac); }
+  / int_:int exp:exp __           { return parseFloat(int_ + exp); }
+  / int_:int __                   { return parseFloat(int_); }
+
+int
+  = digit19:digit19 digits:digits { return digit19 + digits; }
+  / digit:digit
+  / op:("-" / "+" ) digit19:digit19 digits:digits { return "-" + digit19 + digits; }
+  / op:("-" / "+" ) digit:digit { return "-" + digit; }
+
+frac
+  = "." digits:digits { return "." + digits; }
+
+exp
+  = e:e digits:digits { return e + digits; }
+
+digits
+  = digits:digit+ { return digits.join(""); }
+
+digit   = [0-9]
+digit19 = [1-9]
+
+hexDigit
+  = [0-9a-fA-F]
+
+e
+  = e:[eE] sign:[+-]? { return e + (sign !== null ? sign: ''); }
+
+
+KW_NULL     = "NULL"i       !ident_start
+KW_TRUE     = "TRUE"i       !ident_start
+KW_FALSE    = "FALSE"i      !ident_start
+
+KW_SHOW     = "SHOW"i       !ident_start
+KW_DROP     = "DROP"i       !ident_start
+KW_SELECT   = "SELECT"i     !ident_start
+KW_UPDATE   = "UPDATE"i     !ident_start
+KW_CREATE   = "CREATE"i     !ident_start
+KW_DELETE   = "DELETE"i     !ident_start
+KW_INSERT   = "INSERT"i     !ident_start
+KW_RECURSIVE= "RECURSIVE"   !ident_start
+KW_REPLACE  = "REPLACE"i    !ident_start
+KW_EXPLAIN  = "EXPLAIN"i    !ident_start
+
+KW_INTO     = "INTO"i       !ident_start
+KW_FROM     = "FROM"i       !ident_start
+KW_SET      = "SET"i        !ident_start
+
+KW_AS       = "AS"i         !ident_start
+KW_TABLE    = "TABLE"i      !ident_start
+
+KW_ON       = "ON"i       !ident_start
+KW_LEFT     = "LEFT"i     !ident_start
+KW_RIGHT    = "RIGHT"i    !ident_start
+KW_FULL     = "FULL"i     !ident_start
+KW_INNER    = "INNER"i    !ident_start
+KW_JOIN     = "JOIN"i     !ident_start
+KW_OUTER    = "OUTER"i    !ident_start
+KW_UNION    = "UNION"i    !ident_start
+KW_VALUES   = "VALUES"i   !ident_start
+KW_USING    = "USING"i    !ident_start
+
+KW_WHERE    = "WHERE"i      !ident_start
+KW_WITH     = "WITH"i       !ident_start
+
+KW_GROUP    = "GROUP"i      !ident_start
+KW_BY       = "BY"i         !ident_start
+KW_ORDER    = "ORDER"i      !ident_start
+KW_HAVING   = "HAVING"i     !ident_start
+
+KW_LIMIT    = "LIMIT"i      !ident_start
+
+KW_ASC      = "ASC"i        !ident_start { return 'ASC'; }
+KW_DESC     = "DESC"i       !ident_start { return 'DESC'; }
+
+KW_ALL      = "ALL"i        !ident_start { return 'ALL'; }
+KW_DISTINCT = "DISTINCT"i   !ident_start { return 'DISTINCT';}
+
+KW_BETWEEN  = "BETWEEN"i    !ident_start { return 'BETWEEN'; }
+KW_IN       = "IN"i         !ident_start { return 'IN'; }
+KW_IS       = "IS"i         !ident_start { return 'IS'; }
+KW_LIKE     = "LIKE"i       !ident_start { return 'LIKE'; }
+KW_EXISTS   = "EXISTS"i     !ident_start { return 'EXISTS'; }
+
+KW_NOT      = "NOT"i        !ident_start { return 'NOT'; }
+KW_AND      = "AND"i        !ident_start { return 'AND'; }
+KW_OR       = "OR"i         !ident_start { return 'OR'; }
+
+KW_COUNT    = "COUNT"i      !ident_start { return 'COUNT'; }
+KW_MAX      = "MAX"i        !ident_start { return 'MAX'; }
+KW_MIN      = "MIN"i        !ident_start { return 'MIN'; }
+KW_SUM      = "SUM"i        !ident_start { return 'SUM'; }
+KW_AVG      = "AVG"i        !ident_start { return 'AVG'; }
+
+KW_CASE     = "CASE"i       !ident_start
+KW_WHEN     = "WHEN"i       !ident_start
+KW_THEN     = "THEN"i       !ident_start
+KW_ELSE     = "ELSE"i       !ident_start
+KW_END      = "END"i        !ident_start
+
+KW_CAST     = "CAST"i       !ident_start
+
+KW_CHAR     = "CHAR"i     !ident_start { return 'CHAR'; }
+KW_VARCHAR  = "VARCHAR"i  !ident_start { return 'VARCHAR';}
+KW_NUMERIC  = "NUMERIC"i  !ident_start { return 'NUMERIC'; }
+KW_DECIMAL  = "DECIMAL"i  !ident_start { return 'DECIMAL'; }
+KW_SIGNED   = "SIGNED"i   !ident_start { return 'SIGNED'; }
+KW_UNSIGNED = "UNSIGNED"i !ident_start { return 'UNSIGNED'; }
+KW_INT      = "INT"i      !ident_start { return 'INT'; }
+KW_INTEGER  = "INTEGER"i  !ident_start { return 'INTEGER'; }
+KW_JSON     = "JSON"i     !ident_start { return 'JSON'; }
+KW_SMALLINT = "SMALLINT"i !ident_start { return 'SMALLINT'; }
+KW_DATE     = "DATE"i     !ident_start { return 'DATE'; }
+KW_TIME     = "TIME"i     !ident_start { return 'TIME'; }
+KW_TIMESTAMP= "TIMESTAMP"i!ident_start { return 'TIMESTAMP'; }
+KW_USER     = "USER"i     !ident_start { return 'USER'; }
+
+KW_CURRENT_DATE     = "CURRENT_DATE"i !ident_start { return 'CURRENT_DATE'; }
+KW_ADD_DATE         = "ADDDATE"i !ident_start { return 'ADDDATE'; }
+KW_INTERVAL         = "INTERVAL"i !ident_start { return 'INTERVAL'; }
+KW_UNIT_YEAR        = "YEAR"i !ident_start { return 'YEAR'; }
+KW_UNIT_MONTH       = "MONTH"i !ident_start { return 'MONTH'; }
+KW_UNIT_DAY         = "DAY"i !ident_start { return 'DAY'; }
+KW_UNIT_HOUR        = "HOUR"i !ident_start { return 'HOUR'; }
+KW_UNIT_MINUTE      = "MINUTE"i !ident_start { return 'MINUTE'; }
+KW_UNIT_SECOND      = "SECOND"i !ident_start { return 'SECOND'; }
+KW_CURRENT_TIME     = "CURRENT_TIME"i !ident_start { return 'CURRENT_TIME'; }
+KW_CURRENT_TIMESTAMP= "CURRENT_TIMESTAMP"i !ident_start { return 'CURRENT_TIMESTAMP'; }
+KW_CURRENT_USER     = "CURRENT_USER"i !ident_start { return 'CURRENT_USER'; }
+KW_SESSION_USER     = "SESSION_USER"i !ident_start { return 'SESSION_USER'; }
+KW_SYSTEM_USER      = "SYSTEM_USER"i !ident_start { return 'SYSTEM_USER'; }
+
+KW_VAR_PRE = '$'
+KW_RETURN = 'return'i
+KW_ASSIGN = ':='
+
+KW_DUAL = "DUAL"i
+
+// MySQL extensions to SQL
+OPT_SQL_CALC_FOUND_ROWS = "SQL_CALC_FOUND_ROWS"i
+OPT_SQL_CACHE           = "SQL_CACHE"i
+OPT_SQL_NO_CACHE        = "SQL_NO_CACHE"i
+OPT_SQL_SMALL_RESULT    = "SQL_SMALL_RESULT"i
+OPT_SQL_BIG_RESULT      = "SQL_BIG_RESULT"i
+OPT_SQL_BUFFER_RESULT   = "SQL_BUFFER_RESULT"i
+
+//special character
+DOT       = '.'
+COMMA     = ','
+STAR      = '*'
+LPAREN    = '('
+RPAREN    = ')'
+
+LBRAKE    = '['
+RBRAKE    = ']'
+
+SEMICOLON = ';'
+
+// separator
+__
+  = (whitespace / comment)*
+
+comment
+  = block_comment
+  / line_comment
+
+block_comment
+  = "/*" (!"*/" char)* "*/"
+
+line_comment
+  = "--" (!EOL char)*
+
+char = .
+
+interval_unit
+  = KW_UNIT_YEAR
+  / KW_UNIT_MONTH
+  / KW_UNIT_DAY
+  / KW_UNIT_HOUR
+  / KW_UNIT_MINUTE
+  / KW_UNIT_SECOND
+
+whitespace =
+  [ \t\n\r]
+
+EOL
+  = EOF
+  / [\n\r]+
+
+EOF = !.
+
+//begin procedure extension
+proc_stmts
+  = proc_stmt*
+
+proc_stmt
+  = &{ varList = []; return true; } __ s:(assign_stmt / return_stmt) {
+      return { stmt: s, vars: varList };
+    }
+
+assign_stmt
+  = va:var_decl __ KW_ASSIGN __ e:proc_expr {
+    return {
+      type: 'assign',
+      left: va,
+      right: e
+    };
+  }
+
+return_stmt
+  = KW_RETURN __ e:proc_expr {
+      return { type: 'return', expr: e };
+    }
+
+proc_expr
+  = select_stmt
+  / proc_join
+  / proc_additive_expr
+  / proc_array
+
+proc_additive_expr
+  = head:proc_multiplicative_expr
+    tail:(__ additive_operator  __ proc_multiplicative_expr)* {
+      return createBinaryExprChain(head, tail);
+    }
+
+proc_multiplicative_expr
+  = head:proc_primary
+    tail:(__ multiplicative_operator  __ proc_primary)* {
+      return createBinaryExprChain(head, tail);
+    }
+
+proc_join
+  = lt:var_decl __ op:join_op  __ rt:var_decl __ expr:on_clause {
+      return {
+        type: 'join',
+        ltable: lt,
+        rtable: rt,
+        op: op,
+        on: expr
+      };
+    }
+
+proc_primary
+  = literal
+  / var_decl
+  / proc_func_call
+  / param
+  / LPAREN __ e:proc_additive_expr __ RPAREN {
+      e.parentheses = true;
+      return e;
+    }
+
+proc_func_call
+  = name:ident __ LPAREN __ l:proc_primary_list __ RPAREN {
+      //compatible with original func_call
+      return {
+        type: 'function',
+        name: name,
+        args: {
+          type: 'expr_list',
+          value: l
+        }
+      };
+    }
+
+proc_primary_list
+  = head:proc_primary tail:(__ COMMA __ proc_primary)* {
+      return createList(head, tail);
+    }
+
+proc_array =
+  LBRAKE __ l:proc_primary_list __ RBRAKE {
+    return { type: 'array', value: l };
+  }
+
+var_decl
+  = KW_VAR_PRE name:ident_name m:mem_chain {
+    //push for analysis
+    varList.push(name);
+    return {
+      type: 'var',
+      name: name,
+      members: m
+    };
+  }
+
+mem_chain
+  = l:('.' ident_name)* {
+    const s = [];
+    for (let i = 0; i < l.length; i++) {
+      s.push(l[i][1]);
+    }
+    return s;
+  }
+
+data_type
+  = character_string_type
+  / numeric_type
+  / datetime_type
+  / json_type
+
+character_string_type
+  = t:(KW_CHAR / KW_VARCHAR) __ LPAREN __ l:[0-9]+ __ RPAREN __ {
+    return { dataType: t, length: parseInt(l.join(''), 10) };
+  }
+  / t:KW_CHAR { return { dataType: t }; }
+  / t:KW_VARCHAR { return { dataType: t }; }
+
+numeric_type
+  = t:(KW_NUMERIC / KW_DECIMAL / KW_INT / KW_INTEGER / KW_SMALLINT) { return { dataType: t }; }
+
+datetime_type
+  = t:(KW_DATE / KW_TIME / KW_TIMESTAMP) { return { dataType: t }; }
+
+json_type
+  = t:KW_JSON { return { dataType: t }; }
diff --git a/packages/core/database/src/view-collection.ts b/packages/core/database/src/view-collection.ts
new file mode 100644
index 000000000..ff8f9eafd
--- /dev/null
+++ b/packages/core/database/src/view-collection.ts
@@ -0,0 +1,20 @@
+import { Collection, CollectionContext, CollectionOptions } from './collection';
+
+export class ViewCollection extends Collection {
+  constructor(options: CollectionOptions, context: CollectionContext) {
+    options.autoGenId = false;
+    options.timestamps = false;
+
+    super(options, context);
+  }
+
+  protected sequelizeModelOptions(): any {
+    const modelOptions = super.sequelizeModelOptions();
+    modelOptions.tableName = this.options.viewName || this.options.name;
+    return modelOptions;
+  }
+
+  isView() {
+    return true;
+  }
+}
diff --git a/packages/core/database/src/view/field-type-map.ts b/packages/core/database/src/view/field-type-map.ts
new file mode 100644
index 000000000..b9ab6b6ac
--- /dev/null
+++ b/packages/core/database/src/view/field-type-map.ts
@@ -0,0 +1,56 @@
+const postgres = {
+  'character varying': 'string',
+  varchar: 'string',
+  text: 'text',
+  char: 'string',
+
+  smallint: 'integer',
+  integer: 'integer',
+  bigint: 'bigInt',
+  decimal: 'float',
+  numeric: 'float',
+  'double precision': 'float',
+
+  'timestamp without time zone': 'date',
+  'timestamp with time zone': 'date',
+  date: 'date',
+  boolean: 'boolean',
+
+  json: ['json', 'array'],
+  jsonb: ['jsonb', 'array'],
+};
+
+const mysql = {
+  varchar: 'string',
+  text: 'text',
+  int: 'integer',
+  integer: 'integer',
+  bigint: 'bigInt',
+  float: 'float',
+  double: 'float',
+  boolean: 'boolean',
+
+  tinyint: 'integer',
+  datetime: 'date',
+  timestamp: 'date',
+  json: ['json', 'array'],
+};
+
+const sqlite = {
+  text: 'text',
+  varchar: 'string',
+
+  integer: 'integer',
+  real: 'real',
+
+  datetime: 'date',
+  date: 'date',
+  time: 'time',
+
+  boolean: 'boolean',
+
+  numeric: 'decimal',
+  json: ['json', 'array'],
+};
+
+export default { postgres, mysql, sqlite };
diff --git a/packages/core/database/src/view/view-inference.ts b/packages/core/database/src/view/view-inference.ts
new file mode 100644
index 000000000..efa08c19e
--- /dev/null
+++ b/packages/core/database/src/view/view-inference.ts
@@ -0,0 +1,106 @@
+import Database from '../database';
+import FieldTypeMap from './field-type-map';
+import { isArray } from 'mathjs';
+
+type InferredField = {
+  name: string;
+  type: string;
+  source?: string;
+};
+
+type InferredFieldResult = {
+  [key: string]: InferredField;
+};
+
+export class ViewFieldInference {
+  static async inferFields(options: {
+    db: Database;
+    viewName: string;
+    viewSchema?: string;
+  }): Promise<InferredFieldResult> {
+    const { db } = options;
+    if (!db.inDialect('postgres')) {
+      options.viewSchema = undefined;
+    }
+
+    const columns = await db.sequelize.getQueryInterface().describeTable(options.viewName, options.viewSchema);
+
+    const columnUsage = await db.queryInterface.viewColumnUsage({
+      viewName: options.viewName,
+      schema: options.viewSchema,
+    });
+
+    // @ts-ignore
+    return Object.fromEntries(
+      Object.entries(columns).map(([name, column]) => {
+        const usage = columnUsage.find((item) => item.column_name === name);
+
+        if (usage) {
+          const collectionField = (() => {
+            const tableName = `${usage.table_schema ? `${usage.table_schema}.` : ''}${usage.table_name}`;
+            const collection = db.tableNameCollectionMap.get(tableName);
+            if (!collection) return false;
+
+            const fieldValue = Object.values(collection.model.rawAttributes).find(
+              (field) => field.field === usage.column_name,
+            );
+
+            if (!fieldValue) {
+              return false;
+            }
+
+            // @ts-ignore
+            const fieldName = fieldValue?.fieldName;
+
+            return collection.getField(fieldName);
+          })();
+
+          if (collectionField && collectionField.options.interface) {
+            return [
+              name,
+              {
+                name,
+                type: collectionField.type,
+                source: `${collectionField.collection.name}.${collectionField.name}`,
+              },
+            ];
+          }
+        }
+
+        return [
+          name,
+          {
+            name,
+            ...this.inferToFieldType({ db, name, type: column.type }),
+          },
+        ];
+      }),
+    );
+  }
+
+  static inferToFieldType(options: { db: Database; name: string; type: string }) {
+    const { db } = options;
+    const dialect = db.sequelize.getDialect();
+    const fieldTypeMap = FieldTypeMap[dialect];
+
+    if (!options.type) {
+      return {
+        possibleTypes: Object.keys(fieldTypeMap),
+      };
+    }
+
+    const queryType = options.type.toLowerCase().replace(/\(\d+\)/, '');
+    const mappedType = fieldTypeMap[queryType];
+
+    if (isArray(mappedType)) {
+      return {
+        type: mappedType[0],
+        possibleTypes: mappedType,
+      };
+    }
+
+    return {
+      type: mappedType,
+    };
+  }
+}
diff --git a/packages/plugins/acl/src/__tests__/association-field.test.ts b/packages/plugins/acl/src/__tests__/association-field.test.ts
index 95c579c81..5a289391c 100644
--- a/packages/plugins/acl/src/__tests__/association-field.test.ts
+++ b/packages/plugins/acl/src/__tests__/association-field.test.ts
@@ -1,8 +1,8 @@
-import { ACL } from '@nocobase/acl';
-import { Database, HasManyRepository } from '@nocobase/database';
+import {ACL} from '@nocobase/acl';
+import {Database, HasManyRepository} from '@nocobase/database';
 import UsersPlugin from '@nocobase/plugin-users';
-import { MockServer } from '@nocobase/test';
-import { prepareApp } from './prepare';
+import {MockServer} from '@nocobase/test';
+import {prepareApp} from './prepare';
 
 describe('association test', () => {
   let app: MockServer;
@@ -36,6 +36,7 @@ describe('association test', () => {
       context: {},
     });
 
+
     await db.getRepository('collections').create({
       values: {
         name: 'comments',
diff --git a/packages/plugins/collection-manager/src/__tests__/field-options/indexes.test.ts b/packages/plugins/collection-manager/src/__tests__/field-options/indexes.test.ts
index f87046628..9cdeef2ea 100644
--- a/packages/plugins/collection-manager/src/__tests__/field-options/indexes.test.ts
+++ b/packages/plugins/collection-manager/src/__tests__/field-options/indexes.test.ts
@@ -60,6 +60,7 @@ describe('field indexes', () => {
 
   it('field value cannot be duplicated with unique index', async () => {
     const tableName = 'test1';
+
     // create a field with unique constraint
     const field = await agent.resource('collections.fields', tableName).create({
       values: {
diff --git a/packages/plugins/collection-manager/src/__tests__/http-api/view-collection.test.ts b/packages/plugins/collection-manager/src/__tests__/http-api/view-collection.test.ts
new file mode 100644
index 000000000..5e7a3c947
--- /dev/null
+++ b/packages/plugins/collection-manager/src/__tests__/http-api/view-collection.test.ts
@@ -0,0 +1,381 @@
+import { MockServer } from '@nocobase/test';
+import { createApp } from '../index';
+import { uid } from '@nocobase/utils';
+
+describe('view collection', () => {
+  let app: MockServer;
+  let agent;
+  let testViewName;
+
+  beforeEach(async () => {
+    app = await createApp({
+      database: {
+        tablePrefix: '',
+      },
+    });
+    agent = app.agent();
+    testViewName = `view_${uid(6)}`;
+    const dropSQL = `DROP VIEW IF EXISTS ${testViewName}`;
+    await app.db.sequelize.query(dropSQL);
+    const viewSQL = (() => {
+      if (app.db.inDialect('sqlite')) {
+        return `CREATE VIEW ${testViewName} AS WITH RECURSIVE numbers(n) AS (
+  SELECT CAST(1 AS INTEGER)
+  UNION ALL
+  SELECT CAST(1 + n AS INTEGER) FROM numbers WHERE n < 20
+)
+SELECT * FROM numbers;
+`;
+      }
+
+      return `CREATE VIEW ${testViewName} AS WITH RECURSIVE numbers(n) AS (
+  SELECT 1
+  UNION ALL
+  SELECT n + 1 FROM numbers WHERE n < 20
+)
+SELECT * FROM numbers;
+`;
+    })();
+    await app.db.sequelize.query(viewSQL);
+  });
+
+  afterEach(async () => {
+    await app.destroy();
+  });
+
+  it('should list views', async () => {
+    const response = await agent.resource('dbViews').list();
+    expect(response.status).toBe(200);
+    expect(response.body.data.find((item) => item.name === testViewName)).toBeTruthy();
+  });
+
+  it('should query views data', async () => {
+    const response = await agent.resource('dbViews').query({
+      filterByTk: testViewName,
+      pageSize: 20,
+    });
+
+    expect(response.status).toBe(200);
+    expect(response.body.data.length).toBe(20);
+  });
+
+  it('should list views fields', async () => {
+    const response = await agent.resource('dbViews').get({
+      filterByTk: testViewName,
+      schema: 'public',
+    });
+
+    expect(response.status).toBe(200);
+    const data = response.body.data;
+    if (app.db.options.dialect === 'mysql') {
+      expect(data.fields.n.type).toBe('bigInt');
+    } else if (app.db.options.dialect == 'postgres') {
+      expect(data.fields.n.type).toBe('integer');
+    }
+
+    // cannot get field type in sqlite
+    if (app.db.options.dialect === 'sqlite') {
+      expect(data.fields.n.possibleTypes).toBeTruthy();
+    }
+  });
+
+  it('should return possible types for json fields', async () => {
+    const jsonViewName = 'json_view';
+    const dropSql = `DROP VIEW IF EXISTS ${jsonViewName}`;
+    await app.db.sequelize.query(dropSql);
+
+    const jsonViewSQL = (() => {
+      if (app.db.inDialect('postgres')) {
+        return `CREATE VIEW ${jsonViewName} AS SELECT '{"a": 1}'::json as json_field`;
+      }
+      return `CREATE VIEW ${jsonViewName} AS SELECT JSON_OBJECT('key1', 1, 'key2', 'abc') as json_field`;
+    })();
+
+    await app.db.sequelize.query(jsonViewSQL);
+
+    const response = await agent.resource('dbViews').get({
+      filterByTk: jsonViewName,
+      schema: app.db.inDialect('postgres') ? 'public' : undefined,
+    });
+
+    expect(response.status).toBe(200);
+    const data = response.body.data;
+    if (!app.db.inDialect('sqlite')) {
+      expect(data.fields.json_field.type).toBe('json');
+    }
+    expect(data.fields.json_field.possibleTypes).toBeTruthy();
+  });
+
+  it('should list collections fields with source interface', async () => {
+    await app.db.getCollection('collections').repository.create({
+      values: {
+        name: 'users',
+        fields: [
+          {
+            name: 'name',
+            type: 'string',
+            interface: 'text',
+            uiSchema: 'name-uiSchema',
+          },
+          {
+            name: 'age',
+            type: 'integer',
+            interface: 'number',
+            uiSchema: 'age-uiSchema',
+          },
+        ],
+      },
+      context: {},
+    });
+
+    await app.db.sync();
+    const UserCollection = app.db.getCollection('users');
+
+    const viewName = `t_${uid(6)}`;
+    const dropSQL = `DROP VIEW IF EXISTS ${viewName}`;
+    await app.db.sequelize.query(dropSQL);
+    const viewSQL = `CREATE VIEW ${viewName} AS SELECT * FROM ${UserCollection.quotedTableName()}`;
+    await app.db.sequelize.query(viewSQL);
+
+    // create view collection
+    const viewCollection = await app.db.getCollection('collections').repository.create({
+      values: {
+        name: viewName,
+        view: true,
+        schema: app.db.inDialect('postgres') ? 'public' : undefined,
+        fields: [
+          {
+            name: 'name',
+            type: 'string',
+            source: 'users.name',
+          },
+          {
+            name: 'age',
+            type: 'integer',
+            source: 'users.age',
+          },
+        ],
+      },
+      context: {},
+    });
+
+    const response = await agent.resource('collections').list({
+      appends: ['fields'],
+      paginate: false,
+    });
+
+    const listResult = response.body.data.find((item) => item.name === viewName);
+
+    const fields = listResult.fields;
+
+    const nameField = fields.find((item) => item.name === 'name');
+    expect(nameField.interface).toBe('text');
+    expect(nameField.uiSchema).toBe('name-uiSchema');
+
+    const viewFieldsResponse = await agent.resource('collections.fields', viewName).list({
+      filter: {
+        $or: {
+          'interface.$not': null,
+          'options.source.$notEmpty': true,
+        },
+      },
+    });
+
+    expect(viewFieldsResponse.status).toEqual(200);
+    const viewFieldsData = viewFieldsResponse.body.data;
+    expect(viewFieldsData.length).toEqual(2);
+
+    expect(viewFieldsData.find((item) => item.name === 'name').interface).toEqual('text');
+
+    const fieldDetailResponse = await agent.resource('collections.fields', viewName).get({
+      filterByTk: 'name',
+    });
+
+    const fieldDetailData = fieldDetailResponse.body.data;
+    expect(fieldDetailData.interface).toEqual('text');
+
+    UserCollection.addField('email', { type: 'string' });
+
+    await app.db.sync();
+
+    // update view in database
+    await app.db.sequelize.query(dropSQL);
+    const viewSQL2 = `CREATE VIEW ${viewName} AS SELECT * FROM ${UserCollection.quotedTableName()}`;
+    await app.db.sequelize.query(viewSQL2);
+
+    const viewDetailResponse = await agent.resource('dbViews').get({
+      filterByTk: viewName,
+      schema: 'public',
+    });
+
+    const viewDetail = viewDetailResponse.body.data;
+    const viewFields = viewDetail.fields;
+
+    const updateFieldsResponse = await agent.resource('collections').setFields({
+      filterByTk: viewName,
+      values: {
+        fields: Object.values(viewFields),
+      },
+    });
+
+    expect(updateFieldsResponse.status).toEqual(200);
+
+    const viewCollectionWithEmail = app.db.getCollection(viewName);
+    expect(viewCollectionWithEmail.getField('email')).toBeTruthy();
+  });
+
+  it('should access view collection resource', async () => {
+    const UserCollection = app.db.collection({
+      name: 'users',
+      fields: [
+        {
+          name: 'name',
+          type: 'string',
+        },
+      ],
+    });
+
+    await app.db.sync();
+
+    await UserCollection.repository.create({
+      values: {
+        name: 'John',
+      },
+    });
+
+    // create view
+    const viewName = `t_${uid(6)}`;
+    const dropSQL = `DROP VIEW IF EXISTS ${viewName}`;
+    await app.db.sequelize.query(dropSQL);
+    const viewSQL = `CREATE VIEW ${viewName} AS SELECT * FROM ${UserCollection.quotedTableName()}`;
+    await app.db.sequelize.query(viewSQL);
+
+    // create view collection
+    await app.db.getCollection('collections').repository.create({
+      values: {
+        name: viewName,
+        view: true,
+        schema: app.db.inDialect('postgres') ? 'public' : undefined,
+        fields: [
+          {
+            name: 'id',
+            type: 'integer',
+          },
+          {
+            name: 'name',
+            type: 'string',
+          },
+        ],
+      },
+      context: {},
+    });
+
+    const viewCollection = app.db.getCollection(viewName);
+
+    // access view collection list
+    const listResponse = await agent.resource(viewCollection.name).list({});
+    expect(listResponse.status).toEqual(200);
+
+    const item = listResponse.body.data[0];
+
+    // access detail
+    const detailResponse = await agent.resource(viewCollection.name).get({
+      filterByTk: item['id'],
+    });
+
+    expect(detailResponse.status).toEqual(200);
+  });
+
+  it('should get view in difference schema', async () => {
+    if (!app.db.inDialect('postgres')) return;
+
+    const schemaName = `t_${uid(6)}`;
+    const testSchemaSql = `CREATE SCHEMA IF NOT EXISTS ${schemaName};`;
+    await app.db.sequelize.query(testSchemaSql);
+
+    const viewName = `v_${uid(6)}`;
+
+    const viewSQL = `CREATE OR REPLACE VIEW ${schemaName}.${viewName} AS SELECT 1+1 as result`;
+    await app.db.sequelize.query(viewSQL);
+
+    const response = await agent.resource('dbViews').query({
+      filterByTk: viewName,
+      schema: schemaName,
+      pageSize: 20,
+    });
+
+    expect(response.status).toEqual(200);
+  });
+
+  it('should edit uiSchema in view collection field', async () => {
+    await app.db.getCollection('collections').repository.create({
+      values: {
+        name: 'users',
+        fields: [
+          {
+            name: 'name',
+            type: 'string',
+            uiSchema: {
+              title: 'hello',
+            },
+          },
+        ],
+      },
+      context: {},
+    });
+
+    await app.db.sync();
+
+    const UserCollection = app.db.getCollection('users');
+
+    // create view
+    const viewName = `t_${uid(6)}`;
+    const dropSQL = `DROP VIEW IF EXISTS ${viewName}`;
+    await app.db.sequelize.query(dropSQL);
+    const viewSQL = `CREATE VIEW ${viewName} AS SELECT * FROM ${UserCollection.quotedTableName()}`;
+    await app.db.sequelize.query(viewSQL);
+
+    // create view collection
+    await app.db.getCollection('collections').repository.create({
+      values: {
+        name: viewName,
+        view: true,
+        schema: 'public',
+        fields: [
+          {
+            name: 'id',
+            type: 'integer',
+          },
+          {
+            name: 'name',
+            type: 'string',
+            source: 'users.name',
+          },
+        ],
+      },
+      context: {},
+    });
+
+    await app.db.getCollection('fields').repository.update({
+      filter: {
+        name: 'name',
+        collectionName: viewName,
+      },
+
+      values: {
+        uiSchema: {
+          title: 'bars',
+        },
+      },
+      context: {},
+    });
+
+    const viewCollection = app.db.getCollection(viewName);
+
+    expect(viewCollection.getField('name').options.uiSchema.title).toEqual('bars');
+
+    const viewFieldsResponse = await agent.resource('collections.fields', viewName).list({});
+    const nameField = viewFieldsResponse.body.data.find((item) => item.name === 'name');
+    expect(nameField.uiSchema.title).toEqual('bars');
+  });
+});
diff --git a/packages/plugins/collection-manager/src/__tests__/view/view-collection.test.ts b/packages/plugins/collection-manager/src/__tests__/view/view-collection.test.ts
new file mode 100644
index 000000000..73c841093
--- /dev/null
+++ b/packages/plugins/collection-manager/src/__tests__/view/view-collection.test.ts
@@ -0,0 +1,122 @@
+import Database, { Repository, ViewCollection } from '@nocobase/database';
+import Application from '@nocobase/server';
+import { createApp } from '../index';
+
+describe('view collection', function () {
+  let db: Database;
+  let app: Application;
+
+  let collectionRepository: Repository;
+
+  let fieldsRepository: Repository;
+
+  beforeEach(async () => {
+    app = await createApp({
+      database: {
+        tablePrefix: '',
+      },
+    });
+
+    db = app.db;
+
+    collectionRepository = db.getCollection('collections').repository;
+    fieldsRepository = db.getCollection('fields').repository;
+  });
+
+  afterEach(async () => {
+    await app.destroy();
+  });
+
+  it('should support view with dot field', async () => {
+    const dropViewSQL = `DROP VIEW IF EXISTS test_view`;
+    await db.sequelize.query(dropViewSQL);
+    const viewSQL = `CREATE VIEW test_view AS select 1+1 as "dot.results"`;
+    await db.sequelize.query(viewSQL);
+
+    await collectionRepository.create({
+      values: {
+        name: 'view_collection',
+        viewName: 'test_view',
+        fields: [{ type: 'string', name: 'dot_result', field: 'dot.results' }],
+        schema: db.inDialect('postgres') ? 'public' : undefined,
+      },
+      context: {},
+    });
+
+    const viewCollection = db.getCollection('view_collection');
+
+    const results = await viewCollection.repository.find();
+    expect(results.length).toBe(1);
+  });
+
+  it('should create view collection by view name', async () => {
+    const dropViewSQL = `DROP VIEW IF EXISTS test_view`;
+    await db.sequelize.query(dropViewSQL);
+    const viewSQL = `CREATE VIEW test_view AS select 1+1 as result`;
+    await db.sequelize.query(viewSQL);
+
+    await collectionRepository.create({
+      values: {
+        name: 'view_collection',
+        viewName: 'test_view',
+        fields: [{ type: 'string', name: 'result' }],
+        schema: db.inDialect('postgres') ? 'public' : undefined,
+      },
+      context: {},
+    });
+
+    const viewCollection = db.getCollection('view_collection');
+    expect(viewCollection).toBeInstanceOf(ViewCollection);
+
+    const results = await viewCollection.repository.find();
+    expect(results.length).toBe(1);
+  });
+
+  it('should destroy collection view', async () => {
+    const dropViewSQL = `DROP VIEW IF EXISTS test_view`;
+    await db.sequelize.query(dropViewSQL);
+    const viewSQL = `CREATE VIEW test_view AS select 1+1 as result`;
+    await db.sequelize.query(viewSQL);
+
+    await collectionRepository.create({
+      values: {
+        name: 'view_collection',
+        viewName: 'test_view',
+        fields: [{ type: 'string', name: 'result' }],
+      },
+      context: {},
+    });
+
+    expect(
+      await fieldsRepository.findOne({
+        filter: {
+          collectionName: 'view_collection',
+          name: 'result',
+        },
+      }),
+    ).toBeTruthy();
+
+    await fieldsRepository.destroy({
+      filter: {
+        collectionName: 'view_collection',
+        name: 'result',
+      },
+      context: {},
+    });
+
+    expect(
+      await fieldsRepository.findOne({
+        filter: {
+          collectionName: 'view_collection',
+          name: 'result',
+        },
+      }),
+    ).toBeFalsy();
+
+    await collectionRepository.destroy({
+      filterByTk: 'view_collection',
+    });
+
+    expect(db.getCollection('view_collection')).toBeUndefined();
+  });
+});
diff --git a/packages/plugins/collection-manager/src/hooks/beforeCreateForViewCollection.ts b/packages/plugins/collection-manager/src/hooks/beforeCreateForViewCollection.ts
new file mode 100644
index 000000000..d44ea868e
--- /dev/null
+++ b/packages/plugins/collection-manager/src/hooks/beforeCreateForViewCollection.ts
@@ -0,0 +1,16 @@
+import { Database } from '@nocobase/database';
+
+export function beforeCreateForViewCollection(db: Database) {
+  return async (model, { transaction, context }) => {
+    if (model.get('viewSQL')) {
+      const name = model.get('name');
+      const sql = model.get('viewSQL');
+
+      await db.sequelize.query(`CREATE OR REPLACE VIEW "${name}" AS ${sql}`, {
+        transaction,
+      });
+
+      model.set('viewName', name);
+    }
+  };
+}
diff --git a/packages/plugins/collection-manager/src/resourcers/collections.ts b/packages/plugins/collection-manager/src/resourcers/collections.ts
new file mode 100644
index 000000000..258241af2
--- /dev/null
+++ b/packages/plugins/collection-manager/src/resourcers/collections.ts
@@ -0,0 +1,32 @@
+import { Database } from '@nocobase/database';
+
+export default {
+  async ['collections:setFields'](ctx, next) {
+    const { filterByTk, values } = ctx.action.params;
+
+    // WARN: 删掉 key 才能保存
+    const fields = values.fields?.map(f => {
+      delete f.key;
+      return f;
+    });
+
+    const db = ctx.app.db as Database;
+
+    const collection = await db.getRepository('collections').findOne({
+      filter: {
+        name: filterByTk,
+      },
+    });
+
+    await db.getRepository('collections').update({
+      filterByTk,
+      values: {
+        fields,
+      },
+    });
+
+    await collection.loadFields();
+
+    await next();
+  },
+};
diff --git a/packages/plugins/collection-manager/src/resourcers/views.ts b/packages/plugins/collection-manager/src/resourcers/views.ts
new file mode 100644
index 000000000..7676362aa
--- /dev/null
+++ b/packages/plugins/collection-manager/src/resourcers/views.ts
@@ -0,0 +1,55 @@
+import { Database, ViewFieldInference } from '@nocobase/database';
+
+export default {
+  name: 'dbViews',
+  actions: {
+    async get(ctx, next) {
+      const { filterByTk, schema } = ctx.action.params;
+      const db = ctx.app.db as Database;
+
+      const fields = await ViewFieldInference.inferFields({
+        db,
+        viewName: filterByTk,
+        viewSchema: schema,
+      });
+
+      ctx.body = {
+        fields,
+        sources: [
+          ...new Set(
+            Object.values(fields)
+              .map((field) => field.source)
+              .filter(Boolean)
+              .map((source) => source.split('.')[0]),
+          ),
+        ],
+      };
+
+      await next();
+    },
+    async list(ctx, next) {
+      const db = ctx.app.db as Database;
+      const dbViews = await db.queryInterface.listViews();
+      ctx.body = dbViews.map((dbView) => {
+        return {
+          ...dbView,
+        };
+      });
+
+      await next();
+    },
+
+    async query(ctx, next) {
+      const { filterByTk, schema = 'public', page = 1, pageSize = 10 } = ctx.action.params;
+
+      const offset = (page - 1) * pageSize;
+      const limit = 1 * pageSize;
+
+      const sql = `SELECT *
+                   FROM ${ctx.app.db.utils.quoteTable(ctx.app.db.utils.addSchema(filterByTk, schema))} LIMIT ${limit} OFFSET ${offset}`;
+
+      ctx.body = await ctx.app.db.sequelize.query(sql, { type: 'SELECT' });
+      await next();
+    },
+  },
+};
diff --git a/packages/plugins/collection-manager/src/server.ts b/packages/plugins/collection-manager/src/server.ts
index f989ab999..7d639b4ca 100644
--- a/packages/plugins/collection-manager/src/server.ts
+++ b/packages/plugins/collection-manager/src/server.ts
@@ -15,9 +15,13 @@ import {
 } from './hooks';
 
 import { InheritedCollection } from '@nocobase/database';
-import lodash from 'lodash';
+import lodash, { castArray } from 'lodash';
 import * as process from 'process';
 import { CollectionModel, FieldModel } from './models';
+import collectionActions from './resourcers/collections';
+import viewResourcer from './resourcers/views';
+
+import { beforeCreateForViewCollection } from './hooks/beforeCreateForViewCollection';
 
 export class CollectionManagerPlugin extends Plugin {
   public schema: string;
@@ -46,19 +50,17 @@ export class CollectionManagerPlugin extends Plugin {
 
     this.app.acl.registerSnippet({
       name: `pm.${this.name}.collections`,
-      actions: [
-        'collections:*',
-        // 'fields:*',
-        'collections.fields:*',
-      ],
+      actions: ['collections:*', 'collections.fields:*', 'dbViews:*'],
     });
 
     this.app.db.on('collections.beforeCreate', async (model) => {
-      if (this.app.db.inDialect('postgres') && this.schema && model.get('from') != 'db2cm') {
+      if (this.app.db.inDialect('postgres') && this.schema && model.get('from') != 'db2cm' && !model.get('schema')) {
         model.set('schema', this.schema);
       }
     });
 
+    this.app.db.on('collections.beforeCreate', beforeCreateForViewCollection(this.db));
+
     this.app.db.on(
       'collections.afterCreateWithAssociations',
       async (model: CollectionModel, { context, transaction }) => {
@@ -90,6 +92,13 @@ export class CollectionManagerPlugin extends Plugin {
       }
     });
 
+    this.app.db.on('fields.beforeValidate', async (model) => {
+      if (model.get('name') && model.get('name').includes('.')) {
+        model.set('field', model.get('name'));
+        model.set('name', model.get('name').replace(/\./g, '_'));
+      }
+    });
+
     this.app.db.on('fields.beforeCreate', async (model, options) => {
       const type = model.get('type');
       const fn = beforeInitOptions[type];
@@ -261,6 +270,55 @@ export class CollectionManagerPlugin extends Plugin {
       await next();
     });
 
+    this.app.resource(viewResourcer);
+    this.app.actions(collectionActions);
+
+    const handleFieldSource = (fields) => {
+      for (const field of castArray(fields)) {
+        if (field.get('source')) {
+          const [collectionSource, fieldSource] = field.get('source').split('.');
+          const collectionField = this.app.db.getCollection(collectionSource).getField(fieldSource);
+
+          const newOptions = {};
+          lodash.merge(newOptions, collectionField.options);
+          lodash.mergeWith(newOptions, field.get(), (objValue, srcValue) => {
+            if (srcValue === null) {
+              return objValue;
+            }
+          });
+
+          field.set('options', newOptions);
+        }
+      }
+    };
+
+    this.app.resourcer.use(async (ctx, next) => {
+      await next();
+
+      // handle collections:list
+      if (
+        ctx.action.resourceName === 'collections' &&
+        ctx.action.actionName == 'list' &&
+        ctx.action.params?.paginate == 'false'
+      ) {
+        for (const collection of ctx.body) {
+          if (collection.get('view')) {
+            const fields = collection.fields;
+            handleFieldSource(fields);
+          }
+        }
+      }
+
+      //handle collections:fields:list
+      if (ctx.action.resourceName == 'collections.fields' && ctx.action.actionName == 'list') {
+        handleFieldSource(ctx.action.params?.paginate == 'false' ? ctx.body : ctx.body.rows);
+      }
+
+      if (ctx.action.resourceName == 'collections.fields' && ctx.action.actionName == 'get') {
+        handleFieldSource(ctx.body);
+      }
+    });
+
     this.app.db.extendCollection({
       name: 'collectionCategory',
       namespace: 'collection-manager',
diff --git a/packages/plugins/duplicator/src/server/__tests__/dump-action.test.ts b/packages/plugins/duplicator/src/server/__tests__/dump-action.test.ts
index 1f141fcbe..eace87249 100644
--- a/packages/plugins/duplicator/src/server/__tests__/dump-action.test.ts
+++ b/packages/plugins/duplicator/src/server/__tests__/dump-action.test.ts
@@ -1,8 +1,7 @@
 import { mockServer, MockServer } from '@nocobase/test';
-import { Database, Model } from '@nocobase/database';
+import { Database } from '@nocobase/database';
 import * as os from 'os';
 import path from 'path';
-import lodash from 'lodash';
 import fsPromises from 'fs/promises';
 import { Dumper } from '../dumper';
 import { readLines } from '../utils';
diff --git a/packages/plugins/duplicator/src/server/dumper.ts b/packages/plugins/duplicator/src/server/dumper.ts
index 5b7925c61..a7018fe1a 100644
--- a/packages/plugins/duplicator/src/server/dumper.ts
+++ b/packages/plugins/duplicator/src/server/dumper.ts
@@ -147,17 +147,22 @@ export class Dumper extends AppMigrator {
 
       // get user defined views in postgres
       const views = await db.sequelize.query(
-        `SELECT table_schema, table_name, pg_get_viewdef("table_name", true) as def
-         FROM information_schema.views
-         WHERE table_schema NOT IN ('information_schema', 'pg_catalog')
-         ORDER BY table_schema, table_name`,
+        `SELECT n.nspname    AS schema_name,
+                v.viewname   AS view_name,
+                v.definition AS view_definition
+         FROM pg_views v
+                JOIN
+              pg_namespace n ON v.schemaname = n.nspname
+         WHERE n.nspname NOT IN ('information_schema', 'pg_catalog')
+         ORDER BY schema_name,
+                  view_name;`,
         {
           type: 'SELECT',
         },
       );
 
       for (const v of views) {
-        sqlContent.push(`CREATE OR REPLACE VIEW ${v['table_name']} AS ${v['def']}`);
+        sqlContent.push(`CREATE OR REPLACE VIEW ${v['view_name']} AS ${v['view_definition']}`);
       }
     }
 
diff --git a/packages/plugins/import/src/client/ImportInitializerProvider.tsx b/packages/plugins/import/src/client/ImportInitializerProvider.tsx
index f9990db99..7728cfddd 100644
--- a/packages/plugins/import/src/client/ImportInitializerProvider.tsx
+++ b/packages/plugins/import/src/client/ImportInitializerProvider.tsx
@@ -1,4 +1,4 @@
-import { SchemaInitializerContext } from '@nocobase/client';
+import { SchemaInitializerContext, useCollection } from '@nocobase/client';
 import { useContext } from 'react';
 
 export const ImportInitializerProvider = (props: any) => {
@@ -18,6 +18,10 @@ export const ImportInitializerProvider = (props: any) => {
           skipScopeCheck: true,
         },
       },
+      visible: () => {
+        const collection = useCollection();
+        return (collection as any).template !== 'view';
+      },
     });
   return props.children;
 };