[ 'adapter' => AdapterMySQL::class, 'charset' => 'UTF8', 'driver' => 'pdo_mysql', 'wrapperClass' => Connection::class, ], 'oci' => [ 'adapter' => AdapterOCI8::class, 'charset' => 'AL32UTF8', 'driver' => 'oci8', 'wrapperClass' => OracleConnection::class, ], 'pgsql' => [ 'adapter' => AdapterPgSql::class, 'driver' => 'pdo_pgsql', 'wrapperClass' => Connection::class, ], 'sqlite3' => [ 'adapter' => AdapterSqlite::class, 'driver' => 'pdo_sqlite', 'wrapperClass' => Connection::class, ], ]; private ShardConnectionManager $shardConnectionManager; private ICacheFactory $cacheFactory; public function __construct( private SystemConfig $config, ?ICacheFactory $cacheFactory = null, ) { if ($this->config->getValue('mysql.utf8mb4', false)) { $this->defaultConnectionParams['mysql']['charset'] = 'utf8mb4'; } $collationOverride = $this->config->getValue('mysql.collation', null); if ($collationOverride) { $this->defaultConnectionParams['mysql']['collation'] = $collationOverride; } $this->shardConnectionManager = new ShardConnectionManager($this->config, $this); $this->cacheFactory = $cacheFactory ?? Server::get(ICacheFactory::class); } /** * @brief Get default connection parameters for a given DBMS. * @param string $type DBMS type * @throws \InvalidArgumentException If $type is invalid * @return array Default connection parameters. */ public function getDefaultConnectionParams($type) { $normalizedType = $this->normalizeType($type); if (!isset($this->defaultConnectionParams[$normalizedType])) { throw new \InvalidArgumentException("Unsupported type: $type"); } $result = $this->defaultConnectionParams[$normalizedType]; // \PDO::MYSQL_ATTR_FOUND_ROWS may not be defined, e.g. when the MySQL // driver is missing. In this case, we won't be able to connect anyway. if ($normalizedType === 'mysql' && defined('\PDO::MYSQL_ATTR_FOUND_ROWS')) { $result['driverOptions'] = [ \PDO::MYSQL_ATTR_FOUND_ROWS => true, ]; } return $result; } /** * @brief Get default connection parameters for a given DBMS. * @param string $type DBMS type * @param array $additionalConnectionParams Additional connection parameters * @return \OC\DB\Connection */ public function getConnection(string $type, array $additionalConnectionParams): Connection { $normalizedType = $this->normalizeType($type); $eventManager = new EventManager(); $eventManager->addEventSubscriber(new SetTransactionIsolationLevel()); $connectionParams = $this->createConnectionParams('', $additionalConnectionParams); switch ($normalizedType) { case 'pgsql': // pg_connect used by Doctrine DBAL does not support URI notation (enclosed in brackets) $matches = []; if (preg_match('/^\[([^\]]+)\]$/', $connectionParams['host'], $matches)) { // Host variable carries a port or socket. $connectionParams['host'] = $matches[1]; } break; case 'oci': $eventManager->addEventSubscriber(new OracleSessionInit); // the driverOptions are unused in dbal and need to be mapped to the parameters if (isset($connectionParams['driverOptions'])) { $connectionParams = array_merge($connectionParams, $connectionParams['driverOptions']); } $host = $connectionParams['host']; $port = $connectionParams['port'] ?? null; $dbName = $connectionParams['dbname']; // we set the connect string as dbname and unset the host to coerce doctrine into using it as connect string if ($host === '') { $connectionParams['dbname'] = $dbName; // use dbname as easy connect name } else { $connectionParams['dbname'] = '//' . $host . (!empty($port) ? ":{$port}" : '') . '/' . $dbName; } unset($connectionParams['host']); break; case 'sqlite3': $journalMode = $connectionParams['sqlite.journal_mode']; $connectionParams['platform'] = new OCSqlitePlatform(); $eventManager->addEventSubscriber(new SQLiteSessionInit(true, $journalMode)); break; } /** @var Connection $connection */ $connection = DriverManager::getConnection( $connectionParams, new Configuration(), $eventManager ); return $connection; } /** * @brief Normalize DBMS type * @param string $type DBMS type * @return string Normalized DBMS type */ public function normalizeType($type) { return $type === 'sqlite' ? 'sqlite3' : $type; } /** * Checks whether the specified DBMS type is valid. * * @param string $type * @return bool */ public function isValidType($type) { $normalizedType = $this->normalizeType($type); return isset($this->defaultConnectionParams[$normalizedType]); } /** * Create the connection parameters for the config * * @param string $configPrefix * @return array */ public function createConnectionParams(string $configPrefix = '', array $additionalConnectionParams = []) { $type = $this->config->getValue('dbtype', 'sqlite'); $connectionParams = array_merge($this->getDefaultConnectionParams($type), [ 'user' => $this->config->getValue($configPrefix . 'dbuser', $this->config->getValue('dbuser', '')), 'password' => $this->config->getValue($configPrefix . 'dbpassword', $this->config->getValue('dbpassword', '')), ]); $name = $this->config->getValue($configPrefix . 'dbname', $this->config->getValue('dbname', self::DEFAULT_DBNAME)); if ($this->normalizeType($type) === 'sqlite3') { $dataDir = $this->config->getValue('datadirectory', \OC::$SERVERROOT . '/data'); $connectionParams['path'] = $dataDir . '/' . $name . '.db'; } else { $host = $this->config->getValue($configPrefix . 'dbhost', $this->config->getValue('dbhost', '')); $connectionParams = array_merge($connectionParams, $this->splitHostFromPortAndSocket($host)); $connectionParams['dbname'] = $name; } $connectionParams['tablePrefix'] = $this->config->getValue('dbtableprefix', self::DEFAULT_DBTABLEPREFIX); $connectionParams['sqlite.journal_mode'] = $this->config->getValue('sqlite.journal_mode', 'WAL'); //additional driver options, eg. for mysql ssl $driverOptions = $this->config->getValue($configPrefix . 'dbdriveroptions', $this->config->getValue('dbdriveroptions', null)); if ($driverOptions) { $connectionParams['driverOptions'] = $driverOptions; } // set default table creation options $connectionParams['defaultTableOptions'] = [ 'collate' => 'utf8_bin', 'tablePrefix' => $connectionParams['tablePrefix'] ]; if ($this->config->getValue('mysql.utf8mb4', false)) { $connectionParams['defaultTableOptions'] = [ 'collate' => 'utf8mb4_bin', 'charset' => 'utf8mb4', 'tablePrefix' => $connectionParams['tablePrefix'] ]; } if ($this->config->getValue('dbpersistent', false)) { $connectionParams['persistent'] = true; } $connectionParams['sharding'] = $this->config->getValue('dbsharding', []); if (!empty($connectionParams['sharding'])) { $connectionParams['shard_connection_manager'] = $this->shardConnectionManager; $connectionParams['auto_increment_handler'] = new AutoIncrementHandler( $this->cacheFactory, $this->shardConnectionManager, ); } else { // just in case only the presence could lead to funny behaviour unset($connectionParams['sharding']); } $connectionParams = array_merge($connectionParams, $additionalConnectionParams); $replica = $this->config->getValue($configPrefix . 'dbreplica', $this->config->getValue('dbreplica', [])) ?: [$connectionParams]; return array_merge($connectionParams, [ 'primary' => $connectionParams, 'replica' => $replica, ]); } /** * @param string $host * @return array */ protected function splitHostFromPortAndSocket($host): array { $params = [ 'host' => $host, ]; $matches = []; if (preg_match('/^(.*):([^\]:]+)$/', $host, $matches)) { // Host variable carries a port or socket. $params['host'] = $matches[1]; if (is_numeric($matches[2])) { $params['port'] = (int)$matches[2]; } else { $params['unix_socket'] = $matches[2]; } } return $params; } } Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>jQuery UI Autocomplete - Scrollable results</title>
	<link rel="stylesheet" href="../../themes/base/all.css">
	<link rel="stylesheet" href="../demos.css">
	<style>
	.ui-autocomplete {
		max-height: 100px;
		overflow-y: auto;
		/* prevent horizontal scrollbar */
		overflow-x: hidden;
	}
	/* IE 6 doesn't support max-height
	 * we use height instead, but this forces the menu to always be this tall
	 */
	* html .ui-autocomplete {
		height: 100px;
	}
	</style>
	<script src="../../external/requirejs/require.js"></script>
	<script src="../bootstrap.js">
		var availableTags = [
			"ActionScript",
			"AppleScript",
			"Asp",
			"BASIC",
			"C",
			"C++",
			"Clojure",
			"COBOL",
			"ColdFusion",
			"Erlang",
			"Fortran",
			"Groovy",
			"Haskell",
			"Java",
			"JavaScript",
			"Lisp",
			"Perl",
			"PHP",
			"Python",
			"Ruby",
			"Scala",
			"Scheme"
		];
		$( "#tags" ).autocomplete({
			source: availableTags
		});
	</script>
</head>
<body>

<div class="ui-widget">
	<label for="tags">Tags: </label>
	<input id="tags">
</div>

<div class="demo-description">
<p>When displaying a long list of options, you can simply set the max-height for the autocomplete menu to prevent the menu from growing too large. Try typing "a" or "s" above to get a long list of results that you can scroll through.</p>
</div>
</body>
</html>