生成查询SQL
@access public
@param array $options 表达式
@return string
5529
public function buildSelectSql($options=array()) {
        if(isset($options['page'])) {
            // 根据页数计算limit
            list($page,$listRows)   =   $options['page'];
            $page    =  $page>0 ? $page : 1;
            $listRows=  $listRows>0 ? $listRows : (is_numeric($options['limit'])?$options['limit']:20);
            $offset  =  $listRows*($page-1);
            $options['limit'] =  $offset.','.$listRows;
        }
        $sql  =   $this->parseSql($this->selectSql,$options);
        return $sql;
    }
1060925
protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
    {
        $columnListSql = $this->getColumnDeclarationListSQL($columns);

        if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
            foreach ($options['uniqueConstraints'] as $name => $definition) {
                $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition);
            }
        }

        if (isset($options['primary']) && ! empty($options['primary'])) {
            $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')';
        }

        if (isset($options['indexes']) && ! empty($options['indexes'])) {
            foreach ($options['indexes'] as $index => $definition) {
                $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition);
            }
        }

        $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql;

        $check = $this->getCheckDeclarationSQL($columns);
        if (! empty($check)) {
            $query .= ', ' . $check;
        }
        $query .= ')';

        $sql[] = $query;

        if (isset($options['foreignKeys'])) {
            foreach ((array) $options['foreignKeys'] as $definition) {
                $sql[] = $this->getCreateForeignKeySQL($definition, $tableName);
            }
        }

        return $sql;
    }
360188
public function parseSql($sql,$options=array()){
        $sql   = str_replace(
            array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%LOCK%','%COMMENT%','%FORCE%'),
            array(
                $this->parseTable($options['table']),
                $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
                $this->parseField(!empty($options['field'])?$options['field']:'*'),
                $this->parseJoin(!empty($options['join'])?$options['join']:''),
                $this->parseWhere(!empty($options['where'])?$options['where']:''),
                $this->parseGroup(!empty($options['group'])?$options['group']:''),
                $this->parseHaving(!empty($options['having'])?$options['having']:''),
                $this->parseOrder(!empty($options['order'])?$options['order']:''),
                $this->parseLimit(!empty($options['limit'])?$options['limit']:''),
                $this->parseUnion(!empty($options['union'])?$options['union']:''),
                $this->parseLock(isset($options['lock'])?$options['lock']:false),
                $this->parseComment(!empty($options['comment'])?$options['comment']:''),
                $this->parseForce(!empty($options['force'])?$options['force']:'')
            ),$sql);
        return $sql;
    }
931711
protected function prepareConstructOption($options) {
        if ($options instanceof DatabaseConfiguration) {
            $options = $options->toArray();
        }
        $opts    = array_merge([
            'encoding'       => 'UTF8',
            'dbname'         => '',
            'host'           => 'localhost',
            'port'           => 3306,
            'user'           => 'root',
            'password'       => 'root',
            'driver_options' => [
                \PDO::MYSQL_ATTR_COMPRESS => true
            ]
        ], $options);
        $charset = isset ($opts ['encoding']) && !empty ($opts ['encoding']) ? $opts ['encoding'] : 'UTF8';
        if ($charset == null) {
            $dsn = "mysql:dbname={$opts['dbname']};host={$opts['host']};port={$opts['port']}";
        } else {
            $dsn = "mysql:dbname={$opts['dbname']};host={$opts['host']};port={$opts['port']};charset={$charset}";
        }
        $this->charset = $charset;

        return [$dsn, $opts ['user'], $opts ['password'], $opts ['driver_options']];
    }
590568
private function buildTableOptions(array $options)
    {
        if (isset($options['table_options'])) {
            return $options['table_options'];
        }

        $tableOptions = [];

        // Collate
        if (! isset($options['collate'])) {
            $options['collate'] = 'utf8_unicode_ci';
        }

        $tableOptions[] = sprintf('COLLATE %s', $options['collate']);

        // Engine
        if (! isset($options['engine'])) {
            $options['engine'] = 'InnoDB';
        }

        $tableOptions[] = sprintf('ENGINE = %s', $options['engine']);

        // Auto increment
        if (isset($options['auto_increment'])) {
            $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']);
        }

        // Comment
        if (isset($options['comment'])) {
            $comment = trim($options['comment'], " '");

            $tableOptions[] = sprintf('COMMENT = %s ', $this->quoteStringLiteral($comment));
        }

        // Row format
        if (isset($options['row_format'])) {
            $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']);
        }

        return implode(' ', $tableOptions);
    }
1217040
public static function toQueryString($options = array())
    {
        $temp = array();
        uksort($options, 'strnatcasecmp');
        foreach ($options as $key => $value) {
            if (is_string($key) && !is_array($value)) {
                $temp[] = rawurlencode($key) . '=' . rawurlencode($value);
            }
        }
        return implode('&', $temp);
    }
1238622
public function get($options = []) {
		$result = [
			'success' => false,
			'error' => [],
			'data' => [],
			'max_records' => []
		];
		do {
			// if we have import from command line we need to intialize
			if (method_exists($this->primary_model->db_object->object, 'initialzeWhenNeeded')) {
				$this->primary_model->db_object->object->initialzeWhenNeeded(['import' => true]);
			}
			$this->primary_model->db_object->begin();
			// building query
			$query = $this->primary_model->queryBuilder([
				'initiator' => 'collection',
				'skip_acl' => $this->options['skip_acl']
			])->select()->columns('a.*');
			// process column overrides
			$query->columnOverrides($this->primary_model->columns);
			// where
			if (!empty($options['where'])) {
				$query->whereMultiple('AND', $options['where']);
			}
			// for update
			if (!empty($options['for_update'])) {
				$query->forUpdate();
			}
			// single row
			if (!empty($options['single_row'])) {
				$query->limit(1);
			}
			$query_result = $query->query(null);
			if (!$query_result['success']) {
				$this->primary_model->db_object->rollback();
				$result['error'] = array_merge($result['error'], $query_result['error']);
				break;
			}
			// process data, convert keys
			if (!empty($query_result['rows'])) {
				$data = [];
				foreach ($query_result['rows'] as $k => $v) {
					if (count($this->data['pk']) == 1) {
						$temp_pk = $v[$this->data['pk'][0]];
					} else {
						$temp_pk = [];
						foreach ($this->data['pk'] as $v2) {
							$temp_pk[] = $v[$v2];
						}
						$temp_pk = implode('::', $temp_pk);
					}
					$data[$temp_pk] = $v;
				}
				$query_result['rows'] = $data;
				unset($data);
			}
			// processing details
			if (!empty($query_result['rows']) && !empty($this->data['details'])) {
				$detail_result = $this->processDetails($this->data['details'], $query_result['rows'], $options);
				if (!$detail_result['success']) {
					$result['error'] = array_merge($result['error'], $detail_result['error']);
					break;
				} else {
					if (!empty($detail_result['max_records'])) {
						$result['max_records'] = $detail_result['max_records'];
					}
				}
			}
			// single row
			if (!empty($options['single_row'])) {
				$result['data'] = current($query_result['rows']);
			} else {
				$result['data'] = $query_result['rows'];
			}
			// commit
			$this->primary_model->db_object->commit();
			$result['success'] = true;
		} while(0);
		return $result;
	}
483167
public function prepare(string $sql, array $driverOptions = [])
    {
        $isCache = !isset($driverOptions['IMI_NO_CACHE']) || $driverOptions['IMI_NO_CACHE'];
        if($isCache && $stmtCache = StatementManager::get($this, $sql))
        {
            $stmt = $stmtCache['statement'];
        }
        else
        {
            // 处理支持 :xxx 参数格式
            $this->lastSql = $sql;
            $this->lastStmt = $this->instance->prepare($sql, $driverOptions);
            if(false === $this->lastStmt)
            {
                throw new DbException('sql prepare error: [' . $this->errorCode() . '] ' . $this->errorInfo() . PHP_EOL . 'sql: ' . $sql . PHP_EOL);
            }
            $stmt = BeanFactory::newInstance(Statement::class, $this, $this->lastStmt);
            if($isCache)
            {
                $stmtCache = StatementManager::get($this, $sql);
                if($stmtCache)
                {
                    StatementManager::unUsingStatement($stmtCache['statement']);
                }
                else
                {
                    StatementManager::set($stmt, true);
                }
            }
        }

        return $stmt;
    }
209955
public function getQuery(array $options = array())
    {
        $query = $this->query;
        $query['query'] = $this->expr->getQuery();
        $query['newObj'] = $this->expr->getNewObj();
        return new Query($this->collection, $query, $options);
    }
210440
public function createTable($table, $options)
    {
        $table = $this->buildRealTableName($table);
        $sql = $this->getSchema()->getCreateTableSql($table, $options);
        $ret = $this->query($sql);
        return $ret;
    }
1070377
public function buildWhere($where, $options)
    {
        if (empty($where)) {
            $where = [];
        }

        if ($where instanceof Query) {
            return $this->buildWhere($where->getOptions('where'), $options);
        }

        $whereStr = '';
        $binds    = $this->query->getFieldsBind($options['table']);
        foreach ($where as $key => $val) {
            $str = [];
            foreach ($val as $field => $value) {
                if ($value instanceof \Closure) {
                    // 使用闭包查询
                    $query = new Query($this->connection);
                    call_user_func_array($value, [& $query]);
                    $whereClause = $this->buildWhere($query->getOptions('where'), $options);
                    if (!empty($whereClause)) {
                        $str[] = ' ' . $key . ' ( ' . $whereClause . ' )';
                    }
                } elseif (strpos($field, '|')) {
                    // 不同字段使用相同查询条件（OR）
                    $array = explode('|', $field);
                    $item  = [];
                    foreach ($array as $k) {
                        $item[] = $this->parseWhereItem($k, $value, '', $options, $binds);
                    }
                    $str[] = ' ' . $key . ' ( ' . implode(' OR ', $item) . ' )';
                } elseif (strpos($field, '&')) {
                    // 不同字段使用相同查询条件（AND）
                    $array = explode('&', $field);
                    $item  = [];
                    foreach ($array as $k) {
                        $item[] = $this->parseWhereItem($k, $value, '', $options, $binds);
                    }
                    $str[] = ' ' . $key . ' ( ' . implode(' AND ', $item) . ' )';
                } else {
                    // 对字段使用表达式查询
                    $field = is_string($field) ? $field : '';
                    $str[] = ' ' . $key . ' ' . $this->parseWhereItem($field, $value, $key, $options, $binds);
                }
            }

            $whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($key) + 1) : implode(' ', $str);
        }

        return $whereStr;
    }
297477
public function find($options=array()) {
        if(is_numeric($options) || is_string($options)) {
            $where[$this->getPk()]  =   $options;
            $options                =   array();
            $options['where']       =   $where;
        }
        // 根据复合主键查找记录
        $pk  =  $this->getPk();
        if (is_array($options) && (count($options) > 0) && is_array($pk)) {
            // 根据复合主键查询
            $count = 0;
            foreach (array_keys($options) as $key) {
                if (is_int($key)) $count++; 
            } 
            if ($count == count($pk)) {
                $i = 0;
                foreach ($pk as $field) {
                    $where[$field] = $options[$i];
                    unset($options[$i++]);
                }
                $options['where']  =  $where;
            } else {
                return false;
            }
        }
        // 总是查找一条记录
        $options['limit']   =   1;
        // 分析表达式
        $options            =   $this->_parseOptions($options);
        // 判断查询缓存
        if(isset($options['cache'])){
            $cache  =   $options['cache'];
            $key    =   is_string($cache['key'])?$cache['key']:md5(serialize($options));
            $data   =   S($key,'',$cache);
            if(false !== $data){
                $this->data     =   $data;
                return $data;
            }
        }
        $resultSet          =   $this->db->select($options);
        if(false === $resultSet) {
            return false;
        }
        if(empty($resultSet)) {// 查询结果为空
            return null;
        }
        if(is_string($resultSet)){
            return $resultSet;
        }

        // 读取数据后的处理
        $data   =   $this->_read_data($resultSet[0]);
        $this->_after_find($data,$options);
        if(!empty($this->options['result'])) {
            return $this->returnResult($data,$this->options['result']);
        }
        $this->data     =   $data;
        if(isset($cache)){
            S($key,$data,$cache);
        }
        return $this->data;
    }
624432
protected function createTableBuilder(array $options = array(), $type = DataTableType::class)
    {
        return $this->get(DataTableFactory::class)->createBuilder($type, $options);
    }
989033
private function create($options = [])
	{
		$this->before_create();

		$statement = 'INSERT INTO ' . static::$table_name . ' (';

		if (isset($options['include_primary_key'])) {
			$statement .= implode(', ', $this->_keys(false, true)) . ') VALUES (';
			$values = $this->_values(false);
		} else {
			$statement .= implode(', ', $this->_keys(true, true)) . ') VALUES (';
			$values = $this->_values();
		}

		$value_set = [];

		foreach ($values as $value) {
			$value_set[] = '?';
		}

		$statement .= implode(', ', $value_set) . ')';

		$result = $this->db->query($statement, $values, 'last_id');

		/* NOTE: PDO's lastInsertId does not work with PostgreSQL unless we supply
		 *       the sequence name. This is a hack to circumvent this.
		 *
		 *       Also: it would be nice to handle this in the DB wrapper, but
		 *       unfortunately we don't have any information about the query or table
		 *       there, so the hack has to stay here for now.
		 */
		if ('pgsql' === $this->db->type()) {
			$result = $this->db->lastInsertId(static::$table_name . '_id_seq');
		}

		$this->stored = true;
		$this->updated = false;
		$this->id = $result;

		$this->after_create();

		return true;
	}
507581
public function insert(array $data, $options = [], $replace = false)
    {
        // 分析并处理数据
        $data = $this->parseData($data, $options);
        if (empty($data)) {
            return 0;
        }
        $fields = array_keys($data);
        $values = array_values($data);

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

        return $sql;
    }
1222025
public static function getAllRecords($options = [])
    {
        $options = Util::prepareOptions($options, [
            'indexField' => false,
            'order' => false,
            'limit' => false,
            'calcFoundRows' => false,
            'offset' => 0,
        ]);

        $query = 'SELECT '.($options['calcFoundRows'] ? 'SQL_CALC_FOUND_ROWS' : '').'* FROM `%s`';
        $params = [
            static::$tableName,
        ];

        if ($options['order']) {
            $query .= ' ORDER BY ' . join(',', static::_mapFieldOrder($options['order']));
        }

        if ($options['limit']) {
            $query .= sprintf(' LIMIT %u,%u', $options['offset'], $options['limit']);
        }

        if ($options['indexField']) {
            return DB::table(static::_cn($options['indexField']), $query, $params, null, [static::class,'handleError']);
        } else {
            return DB::allRecords($query, $params, [static::class,'handleError']);
        }
    }
1000504
public function getList(array $options)
    {
        $result = null;
        $this->hook->attach('translation.entity.list.before', $options, $result, $this);

        if (isset($result)) {
            return (array) $result;
        }

        $table = $this->getTable($options['entity']);
        $sql = "SELECT * FROM `$table` WHERE {$options['entity']}_id = ?";

        $conditions = array($options['entity_id']);

        if (isset($options['language'])) {
            $sql .= ' AND language = ?';
            $conditions[] = $options['language'];
        }

        $result = $this->db->fetchAll($sql, $conditions);
        $this->hook->attach('translation.entity.list.after', $options, $result, $this);
        return (array) $result;
    }