TP5兼容达梦国产数据库

发布于:2025-05-01 ⋅ 阅读:(22) ⋅ 点赞:(0)

1.首先数据库安装,部署时需配置大小写不敏感
2.安装PHP达梦扩展,一定要是对应版本(兼容操作系统)的扩展,否则会出现各种报错。参考官方文档:https://eco.dameng.com/document/dm/zh-cn/app-dev/php_php_new.html,注意拷贝扩展时根据安装的php版本,拷贝对应的线程安全或非安全版本扩展。
3.进入框架兼容改造部分,Config/database.php配置:
'type'            => 'dm', 
'quote'           => '"', //库名(模式名)引用符号" 或 ` 等
4.添加对应驱动文件:thinkphp/library/think/db/connector/Dm.php 和 thinkphp/library/think/db/builder/Dm.php,具体代码看项目

thinkphp/library/think/db/connector/Dm.php:

<?php
// +----------------------------------------------------------------------
// | Modified for Dameng Database
// +----------------------------------------------------------------------

namespace think\db\connector;

use PDO;
use think\Container;
use think\db\Connection;
use think\db\Query;

/**
 * 达梦数据库驱动
 */
class Dm extends Connection
{
    protected $builder = '\\think\\db\\builder\\Dm'; // 使用达梦的 SQL 构造器

    /**
     * 初始化
     * @access protected
     * @return void
     */
    protected function initialize()
    {
        // 可以在这里扩展达梦数据库特有的功能
    }

    /**
     * 解析pdo连接的dsn信息
     * @access protected
     * @param  array $config 连接信息
     * @return string
     */
    protected function parseDsn($config)
    {
        $dsn = 'dm:host=' . $config['hostname'] . ';port=' . $config['hostport'] . ';schema="' . $config['database'] . '"';

        if (!empty($config['charset'])) {
            $dsn .= ';charset=' . $config['charset'];
        }

        return $dsn;
    }

    /**
     * 取得数据表的字段信息
     * @access public
     * @param  string $tableName
     * @return array
     */
    public function getFields($tableName)
    {
        list($tableName) = explode(' ', $tableName);

        if (strpos($tableName, '.')) {
            list($schema, $tableName) = explode('.', $tableName);
        }

        // 达梦数据库获取表结构
        $sql    = "SELECT COLUMN_NAME, DATA_TYPE,DATA_DEFAULT, DATA_LENGTH, NULLABLE
            FROM DBA_TAB_COLUMNS
            WHERE TABLE_NAME = '{$tableName}'";
        $pdo    = $this->query($sql, [], false, true);
        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);
        $info   = [];

        if ($result) {
            foreach ($result as $key => $val) {
                $val                 = array_change_key_case($val);
                $info[$val['column_name']] = [
                    'name'    => $val['column_name'],
                    'type'    => $val['data_type'],
                    'notnull' => 'N' == $val['nullable'],
                    'default' => $val['data_default'],
                    'primary' => $val['column_name'] == 'id', //表主键基本都是id,为方便获取信息省略查询
                    'autoinc' => $val['column_name'] == 'id', //表自增字段基本都是id,为方便获取信息省略查询
                ];
            }
        }

        /*
         * 查询主键及自增示例
         * -- 获取主键字段
        SELECT
            c.COLUMN_NAME AS pk
        FROM
            DBA_CONSTRAINTS con
        JOIN
            DBA_CONS_COLUMNS c ON con.CONSTRAINT_NAME = c.CONSTRAINT_NAME
        WHERE
            con.TABLE_NAME = 'ss_logs_select'
            AND con.OWNER = 'self-service'
            AND con.CONSTRAINT_TYPE = 'P';

        -- 检查字段是否为自增字段
        select b.table_name,a.name COL_NAME from  SYS.SYSCOLUMNS a,all_tables b,sys.sysobjects c where a.INFO2 & 0x01 = 0x01
        and a.id=c.id and c.name= b.table_name AND b.table_name='ss_logs'
         * */

        return $this->fieldCase($info);
    }

    /**
     * 取得数据库的表信息
     * @access public
     * @param  string $dbName
     * @return array
     */
    public function getTables($dbName = '')
    {
        // 达梦数据库使用 SHOW TABLES 语句获取表信息
        $sql    = !empty($dbName) ? "SELECT TABLE_NAME FROM DBA_TABLES WHERE OWNER = '" . $dbName . "'" : 'SELECT TABLE_NAME FROM DBA_TABLES';
        $pdo    = $this->query($sql, [], false, true);
        $result = $pdo->fetchAll(PDO::FETCH_ASSOC);
        $info   = [];

        foreach ($result as $key => $val) {
            $info[$key] = current($val);
        }

        return $info;
    }

    /**
     * 获取数据表信息
     * @access public
     * @param  mixed  $tableName 数据表名 留空自动获取
     * @param  string $fetch     获取信息类型 包括 fields type bind pk
     * @return mixed
     */
    public function getTableInfo($tableName, $fetch = '')
    {
        if (is_array($tableName)) {
            $tableName = key($tableName) ?: current($tableName);
        }

        if (strpos($tableName, ',')) {
            // 多表不获取字段信息
            return false;
        } else {
            $tableName = $this->parseSqlTable($tableName);
        }

        // 修正子查询作为表名的问题
        if (strpos($tableName, ')')) {
            return [];
        }

        list($tableName) = explode(' ', $tableName);

        if (false === strpos($tableName, '.')) {
            $schema = $this->getConfig('database') . '.' . $tableName;
        } else {
            $schema = $tableName;
        }

        if (!isset(self::$info[$schema])) {
            // 读取缓存
            $cacheFile = Container::get('app')->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR . $schema . '.php';

            if (!$this->config['debug'] && is_file($cacheFile)) {
                $info = include $cacheFile;
            } else {
                $info = $this->getFields($tableName);
            }

            $fields = array_keys($info);
            $bind   = $type   = [];

            foreach ($info as $key => $val) {
                // 记录字段类型
                $type[$key] = $val['type'];
                $bind[$key] = $this->getFieldBindType($val['type']);

                if (!empty($val['primary'])) {
                    $pk[] = $key;
                }
            }

            if (isset($pk)) {
                // 设置主键
                $pk = count($pk) > 1 ? $pk : $pk[0];
            } else {
                $pk = null;
            }

            self::$info[$schema] = ['fields' => $fields, 'type' => $type, 'bind' => $bind, 'pk' => $pk];
        }

        //针对性处理字段名是desc这个关键词的情况
        if($fetch == "bind" && isset(self::$info[$schema][$fetch]['desc'])){
            self::$info[$schema][$fetch]['"desc"'] = self::$info[$schema][$fetch]['desc'];
            unset(self::$info[$schema][$fetch]['desc']);
        }

        return $fetch ? self::$info[$schema][$fetch] : self::$info[$schema];
    }

    /**
     * 查找单条记录
     * @access public
     * @param  Query  $query        查询对象
     * @return array|null|\PDOStatement|string
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     */
    public function find(Query $query)
    {
        // 分析查询表达式
        $options = $query->getOptions();
        $pk      = $query->getPk($options);

        $data = $options['data'];
        $query->setOption('limit', 1);

        if (empty($options['fetch_sql']) && !empty($options['cache'])) {
            // 判断查询缓存
            $cache = $options['cache'];

            if (is_string($cache['key'])) {
                $key = $cache['key'];
            } else {
                $key = $this->getCacheKey($query, $data);
            }

            $result = Container::get('cache')->get($key);

            if (false !== $result) {
                return $result;
            }
        }

        if (is_string($pk) && !is_array($data)) {
            if (isset($key) && strpos($key, '|')) {
                list($a, $val) = explode('|', $key);
                $item[$pk]     = $val;
            } else {
                $item[$pk] = $data;
            }
            $data = $item;
        }

        $query->setOption('data', $data);

        // 生成查询SQL
        $sql = $this->builder->select($query);

        $query->removeOption('limit');

        $bind = $query->getBind();

        if (!empty($options['fetch_sql'])) {
            // 获取实际执行的SQL语句
            return $this->getRealSql($sql, $bind);
        }

        // 事件回调
        $result = $query->trigger('before_find');

        if (!$result) {
            // 执行查询
            $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);

            if ($resultSet instanceof \PDOStatement) {
                // 返回PDOStatement对象
                return $resultSet;
            }

            $result = isset($resultSet[0]) ? $resultSet[0] : null;
        }

        if (isset($cache) && $result) {
            // 缓存数据
            $this->cacheData($key, $result, $cache);
        }

        return $result;
    }

    /**
     * SQL性能分析
     * @access protected
     * @param  string $sql
     * @return array
     */
    protected function getExplain($sql)
    {
        // 达梦数据库可能不支持 EXPLAIN,需要根据实际情况调整
        return [];
    }

    protected function supportSavepoint()
    {
        return true;
    }

    /**
     * 启动 XA 事务
     * @access public
     * @param  string $xid XA 事务 ID
     * @return void
     */
    public function startTransXa($xid)
    {
        $this->initConnect(true);
        if (!$this->linkID) {
            return false;
        }

        // 达梦数据库使用 DBMS_XA 包启动 XA 事务
        $this->linkID->exec("CALL DBMS_XA.START('{$xid}')");
    }

    /**
     * 预编译 XA 事务
     * @access public
     * @param  string $xid XA 事务 ID
     * @return void
     */
    public function prepareXa($xid)
    {
        $this->initConnect(true);
        // 达梦数据库使用 DBMS_XA 包结束并准备 XA 事务
        $this->linkID->exec("CALL DBMS_XA.END('{$xid}')");
        $this->linkID->exec("CALL DBMS_XA.PREPARE('{$xid}')");
    }

    /**
     * 提交 XA 事务
     * @access public
     * @param  string $xid XA 事务 ID
     * @return void
     */
    public function commitXa($xid)
    {
        $this->initConnect(true);
        // 达梦数据库使用 DBMS_XA 包提交 XA 事务
        $this->linkID->exec("CALL DBMS_XA.COMMIT('{$xid}')");
    }

    /**
     * 回滚 XA 事务
     * @access public
     * @param  string $xid XA 事务 ID
     * @return void
     */
    public function rollbackXa($xid)
    {
        $this->initConnect(true);
        // 达梦数据库使用 DBMS_XA 包回滚 XA 事务
        $this->linkID->exec("CALL DBMS_XA.ROLLBACK('{$xid}')");
    }
}

thinkphp/library/think/db/builder/Dm.php:

<?php
// +----------------------------------------------------------------------
// | Adapted for Dameng Database
// +----------------------------------------------------------------------

namespace think\db\builder;

use think\db\Builder;
use think\db\Expression;
use think\db\Query;
use think\Exception;

/**
 * 达梦数据库驱动
 */
class Dm extends Builder
{
    // 查询表达式解析
    protected $parser = [
        'parseCompare'     => ['=', '<>', '>', '>=', '<', '<='],
        'parseLike'        => ['LIKE', 'NOT LIKE'],
        'parseBetween'     => ['NOT BETWEEN', 'BETWEEN'],
        'parseIn'          => ['NOT IN', 'IN'],
        'parseExp'         => ['EXP'],
        'parseRegexp'      => ['REGEXP', 'NOT REGEXP'],
        'parseNull'        => ['NOT NULL', 'NULL'],
        'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'],
        'parseTime'        => ['< TIME', '> TIME', '<= TIME', '>= TIME'],
        'parseExists'      => ['NOT EXISTS', 'EXISTS'],
        'parseColumn'      => ['COLUMN'],
    ];

    protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES %DATA% %COMMENT%';
    protected $updateSql    = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';

    /**
     * 生成insertall SQL
     * @access public
     * @param  Query     $query   查询对象
     * @param  array     $dataSet 数据集
     * @param  bool      $replace 是否replace
     * @return string
     */
    public function insertAll(Query $query, $dataSet, $replace = false)
    {
        $options = $query->getOptions();

        // 获取合法的字段
        if ('*' == $options['field']) {
            $allowFields = $this->connection->getTableFields($options['table']);
        } else {
            $allowFields = $options['field'];
        }

        // 获取绑定信息
        $bind = $this->connection->getFieldsBind($options['table']);

        foreach ($dataSet as $k => $data) {
            $data = $this->parseData($query, $data, $allowFields, $bind);

            $values[] = '( ' . implode(',', array_values($data)) . ' )';

            if (!isset($insertFields)) {
                $insertFields = array_keys($data);
            }
        }

        $fields = [];
        foreach ($insertFields as $field) {
            $fields[] = $this->parseKey($query, $field);
        }

        return str_replace(
            ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
            [
                $replace ? 'REPLACE' : 'INSERT',
                $this->parseTable($query, $options['table']),
                implode(' , ', $fields),
                implode(' , ', $values),
                $this->parseComment($query, $options['comment']),
            ],
            $this->insertAllSql);
    }

    /**
     * 正则查询
     * @access protected
     * @param  Query        $query        查询对象
     * @param  string       $key
     * @param  string       $exp
     * @param  mixed        $value
     * @param  string       $field
     * @return string
     */
    protected function parseRegexp(Query $query, $key, $exp, $value, $field)
    {
        if ($value instanceof Expression) {
            $value = $value->getValue();
        }

        // REGEXP约等于达梦数据库parseRegexp(),若行不通也可以使用 LIKE 或其他方式替代
        return "parseRegexp({$key}, {$value})";
    }

    /**
     * 字段和表名处理
     * @access public
     * @param  Query     $query 查询对象
     * @param  mixed     $key   字段名
     * @param  bool      $strict   严格检测
     * @return string
     */
    public function parseKey(Query $query, $key, $strict = false)
    {
        if (is_numeric($key)) {
            return $key;
        } elseif ($key instanceof Expression) {
            return $key->getValue();
        }

        $key = trim($key);

        // 达梦数据库不支持 JSON 字段的 `->>` 或 `->` 语法
        if (strpos($key, '->') || strpos($key, '->>')) {
            throw new Exception('JSON field syntax is not supported in Dameng Database.');
        }

        if (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
            list($table, $key) = explode('.', $key, 2);

            $alias = $query->getOptions('alias');

            if ('__TABLE__' == $table) {
                $table = $query->getOptions('table');
                $table = is_array($table) ? array_shift($table) : $table;
            }

            if (isset($alias[$table])) {
                $table = $alias[$table];
            }
        }

        /*if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) { //desc这种关键词形式需加""的字段会导致匹配失败
            throw new Exception('not support data:' . $key);
        }*/

        /*if ('*' != $key && !preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
            $key = '"' . $key . '"'; // 达梦数据库使用双引号
        }*/

        if (isset($table)) {
            $key = $table . '.' . $key;
        }

        return $key;
    }

    /**
     * 生成查询SQL
     * @access public
     * @param  Query  $query  查询对象
     * @return string
     */
    public function select(Query $query)
    {
        $options = $query->getOptions();

        return str_replace(
            ['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'],
            [
                $this->parseTable($query, $options['table']),
                $this->parseDistinct($query, $options['distinct']),
                $this->parseField($query, $options['field']),
                $this->parseJoin($query, $options['join']),
                $this->parseWhere($query, $options['where']),
                $this->parseGroup($query, $options['group']),
                $this->parseHaving($query, $options['having']),
                $this->parseOrder($query, $options['order']),
                $this->parseLimit($query, $options['limit']),
                $this->parseUnion($query, $options['union']),
                $this->parseLock($query, $options['lock']),
                $this->parseComment($query, $options['comment']),
                $this->parseForce($query, $options['force']),
            ],
            $this->selectSql);
    }

    /**
     * table分析
     * @access protected
     * @param  Query     $query         查询对象
     * @param  mixed     $tables        表名
     * @return string
     */
    protected function parseTable(Query $query, $tables)
    {
        $item    = [];
        $options = $query->getOptions();

        foreach ((array) $tables as $key => $table) {
            if (!is_numeric($key)) {
                $key    = $this->connection->parseSqlTable($key);
                $item[] = $this->parseKey($query, $key) . ' ' . $this->parseKey($query, $table);
            } else {
                $table = $this->connection->parseSqlTable($table);

                if (isset($options['alias'][$table])) {
                    $item[] = $this->parseKey($query, $table) . ' ' . $this->parseKey($query, $options['alias'][$table]);
                } else {
                    $item[] = $this->parseKey($query, $table);
                }
            }
        }

        return implode(',', $item);
    }

    /**
     * 随机排序
     * @access protected
     * @param  Query     $query        查询对象
     * @return string
     */
    protected function parseRand(Query $query)
    {
        // 达梦数据库不支持 MySQL 的 rand() 函数,可以使用其他方式替代
        return 'DBMS_RANDOM.VALUE';
    }
}

5.Application/common.php添加方法:

//判断是否使用的达梦数据库
function isDMBase()
{
    return config('database.type') == 'dm';
}

6.相关group 分组sql语句与南大通用类似,group by的字段必须和查询字段相对应,不能出现字段分组模棱两可的情况。

7.Sql条件中存在逻辑或使用||的,更换成OR。

8.sql语句中使用了date_format()的地方全部更换成公共方法getSqlDateFormat()

格式符参考”DM8 SQL.pdf”文件里格式符:


/**
 * 根据提供的参数返回计算日期时间的sql语句
 * 为兼容达梦等数据库语法差异
 * 支持达梦group by
 * @param $intval 日期时间偏差,必须严格按照格式传输例如: -1 day
 * @param $time 日期时间
 * @param $format 日期时间格式
 * @return string
 */
function getSqlDateFormat($intval, $format = '', $time = '')
{
    if($time == ''){
        $time = 'NOW()';
    }elseif(substr($time, 0, 5) == 'left('){ //兼容sql语句left(date_field_name, len),如left(create_time,10)
        $time = $time;
    }else{
        $time = "'{$time}'"; //具体日期字符串
    }
    $format = $format ?: '%Y-%m-%d';
    if(isDMBase()){
        //达梦语法
        $time = $time == 'NOW()' ? 'SYSDATE' : $time;
        $intvalArr = explode(' ', $intval);
        if(count($intvalArr) != 2){ //必须严格按照格式传输例如: -1 day
            return '';
        }
        $offset = $intvalArr[0]; //偏移量
        $unit = strtolower($intvalArr[1]); //取最后一个单位(day,hour,month等)
        $unitFormat = '';
        switch ($unit){
            case 'day':
                $unitFormat = 'DD';
                break;
            case 'month':
                $unitFormat = 'MM';
                break;
            case 'hour':
                $unitFormat = 'HH';
                break;
            case 'week':
                $unitFormat = 'WW';
                break;
            case 'year':
                $unitFormat = 'YYYY';
                break;
        }
        $format = str_replace(['%Y', '%m', '%d', '%H', '%u', '%i', '%s'], ['YYYY', 'MM', 'DD', 'HH24', 'WW', 'MI', 'SS'], $format);
        $sql = "TO_CHAR(DATEADD({$unitFormat}, {$offset}, {$time}), '{$format}')";
    }elseif(isKBASEDataBase()){
        //人大金仓语法
        if(substr($time, 0, 5) == 'left('){
            $leftParams = explode(',', substr($time, 5, -1));
            $time = 'to_timestamp(substring(' . $leftParams[0] . ' FROM 1 FOR ' . $leftParams[1] . '))';
        }else{
            $time = $time == 'NOW()' ? 'CURRENT_DATE' : 'TIMESTAMP ' . $time;
        }

        $intvalArr = explode(' ', $intval);
        if(count($intvalArr) != 2){ //必须严格按照格式传输例如: -1 day
            return '';
        }
        $offset = intval($intvalArr[0]); //偏移量
        $sign = $offset < 0 ? '-' : '+'; //符号位
        $offset = abs($offset);
        $unit = strtolower($intvalArr[1]); //取最后一个单位(day,hour,month等)
        $intvalstr = $offset == 0 ? '' : " {$sign} INTERVAL '{$offset} {$unit}'";
        $format = str_replace(['%Y', '%m', '%d', '%H', '%u', '%i', '%s'], ['YYYY', 'MM', 'DD', 'HH24', 'IW', 'MI', 'SS'], $format);
        $sql = "TO_CHAR({$time}{$intvalstr},'{$format}')";
    }else{
        $sql = "DATE_FORMAT(DATE_ADD({$time}, INTERVAL {$intval}), '{$format}')";
    }
    return $sql;
}

/**
 * 根据提供的参数返回计算日期时间的sql语句
 * 为兼容达梦等数据库语法差异
 * 注:达梦不支持group by DATE_FORMAT()
 * @param $intval 日期时间偏差,必须严格按照格式传输例如: -1 day
 * @param $time 日期时间
 * @param $format 日期时间格式
 * @return string
 */
/*function getSqlDateFormat($intval, $format = '', $time = '')
{
    if($time == ''){
        $time = 'NOW()';
    }elseif(substr($time, 0, 5) == 'left('){ //兼容sql语句left(date_field_name, len),如left(create_time,10)
        $time = $time;
    }else{
        $time = "'{$time}'"; //具体日期字符串
    }
    $format = $format ?: '%Y-%m-%d';
    if(isDMBase()){
        //达梦语法
        $intvalArr = explode(' ', $intval);
        if(count($intvalArr) != 2){ //必须严格按照格式传输例如: -1 day
            return '';
        }
        $offset = $intvalArr[0]; //偏移量
        $unit = strtolower($intvalArr[1]); //取最后一个单位(day,hour,month等)
        if($unit == 'week'){
            $offset = intval($offset) * 7;
            $unit = 'day';
        }
        $sql = "DATE_FORMAT(DATE_ADD({$time}, INTERVAL '{$offset}' {$unit}), '{$format}')";
    }else{
        $sql = "DATE_FORMAT(DATE_ADD({$time}, INTERVAL {$intval}), '{$format}')";
    }
    return $sql;
}*/

相关测试代码:

SELECT TO_CHAR(ADD_DAYS('2021-08-16', -1), 'YYYY-MM-DD');

SELECT TO_CHAR(DATEADD(HH, -8, SYSDATE), 'YYYY-MM-DD HH24');

SELECT TO_CHAR(DATEADD(DD, -1, SYSDATE), 'YYYY-MM-DD HH24');

SELECT TO_CHAR(DATEADD(WW, -1, SYSDATE), 'YYYY-MM-DD HH24');



SELECT TO_CHAR(SYSDATE, 'YYYY-MM-WW HH24');

SELECT TO_CHAR(DATEADD(MM, -1, SYSDATE), 'YYYY-MM-DD HH24 MI SS');

SELECT TO_CHAR(DATEADD(MM, -1, '2016-08-27'), 'YYYY-MM-DD HH24');

SELECT TO_CHAR(DATEADD(DD, -0, left(create_time,18)), 'YYYY-WW') FROM ss_payment ORDER BY create_time desc LIMIT 1;

SELECT TO_CHAR(DATEADD(WW, -1, SYSDATE), 'YYYY-MM-DD HH24') AS date;

后又查看达梦网站相关支持函数文档:函数 | 达梦技术文档

将TO_CHAR切换成了DATE_FORMAT(DATE_ADD(datetime, interval), format)

,同时要注意函数DATE_ADD在达梦和mysql中的差异,达梦中interval的数值必须用’’包含,且数值和符号(-+)之间不能存在空格,且达梦不支持“周”需手动进行转化

但后续因为DATE_FORMAT()不支持group by,又切换回TO_CHAR()了。

9.达梦数据库要求 SELECT 列表中的所有非聚合字段(如 dname、dcode、ddate)必须出现在 GROUP BY 子句中,同时字段不能是别名,支持函数分组如left(),修改所有group by date,其中date是函数计算结果的别名,将别名替换成计算表达式,同时后面要加上所有非聚合字段。如:

group by left(create_time,10),非聚合字段...

10.sql错误:试图修改自增列[id],将更新数据中的自增字段过滤掉

11.字段赋值时使用单引号,看似简单实则很多地方都容易出现。

12.更新数据时报错:SQLSTATE[HY000]: General error: -2007 第 1 行, 第 447 列[desc]附近出现错误:
语法分析出错

根据报错极有可能是desc关键字相同字段名导致的,这种情况根据测试需要将字段名用双引号引用,但又会触发报错:不支持的数据表达式:"desc",需要删除think\db\builder\Dm

里面的parseKey方法里的严格模式判断逻辑去掉。

13.插入数据时报错:SQLSTATE[HY000]: General error: -2007 第 1 行, 第 155 列[desc]附近出现错误:语法分析出错

以上错误同10情况类似,只不过换成了插入操作。将desc换成”desc”会触发严格模式检测到字段”desc”不存在,根据builder.php中报错位置代码,大概浏览db/Query.php相关方法,大概有几种方式实现设置非严格模式:setOption()、option()、strict()以及配置config/database里的”fields_strict”=>false(影响全局),为降低影响范围,选择在调用insert()前调用->strict(false)

其实最好的办法还是在数据表设计初期禁用以关键字作为字段名称,

原以为设置上就可以解决问题,报错确实是不报错了,但是desc数据也确实是没更新,经排查似乎是认为”desc”字段不存在给直接过滤掉了

跟踪代码,最后通过connector/Dm.php重写getTableInfo()方法,针对desc字段解析单独处理,实现了插入成功。

14.达梦不支持group by date_format()表达式,更换application/common.php中getSqlDateFormat()切换成TO_CHAR()形式,上面已提过。

15.将DATE_SUB(now(), INTERVAL 60 second)更改成DATE_SUB(now(), INTERVAL '60' second), 数值加单引号

16.检查表是否存在使用新添加的公共方法checkTableExists()

/**
 * @param $table 表名
 * @param $isFullName 是否为全名
 * @return mixed
 */
function checkTableExists($table = '', $isFullName = 0)
{
    $tableName = $isFullName ? $table : Config('database.prefix') . $table;
    $sql = "SHOW TABLES LIKE '{$tableName}'";
    if(isDMBase()){
        $database = Config('database.database');
        $sql = "SELECT TABLE_NAME
            FROM DBA_TABLES
            WHERE OWNER = '{$database}' AND TABLE_NAME LIKE '{$tableName}'";
    }elseif(isGBASEDataBase()){ //这里是南大通用的,没有的情况下可以忽略或删除
        $sql = "SELECT tablename
                FROM pg_catalog.pg_tables
                WHERE schemaname != 'pg_catalog' AND schemaname != 'information_schema'
                 AND tablename LIKE '{$tableName}'";
    }
    $exists = \think\Db::query($sql);
    return $exists;
}

17.CONCAT()不支持单参数,所以单个参数需要把concat去掉

18.SHOW TABLES;查看所有表更换成SELECT TABLE_NAME FROM DBA_TABLES WHERE OWNER = '模式名';

综上,只是本项目遇到的兼容问题,遇到新问题还是推荐参考官网文档尤其是函数方面,进行测试修改。