aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeuner <github@quidecco.de>2017-01-09 17:03:13 +0100
committerNer'zhul <nerzhul@users.noreply.github.com>2017-01-09 17:03:13 +0100
commit11df7e886a674e280e3ec6f895c11fc1e70eb7b3 (patch)
tree965e8a13c9060408650006be4e0e1d135a54fa5b
parent73fdb635974cb11521d80f15261b97d6fac53cd0 (diff)
downloadminetest-11df7e886a674e280e3ec6f895c11fc1e70eb7b3.tar.gz
minetest-11df7e886a674e280e3ec6f895c11fc1e70eb7b3.tar.bz2
minetest-11df7e886a674e280e3ec6f895c11fc1e70eb7b3.zip
support older PostGreSQL versions (#4999)
* support older PostGreSQL versions * documentation accuracy * improve performance by affecting less rows in UPDATE queries
-rw-r--r--README.txt2
-rw-r--r--src/database-postgresql.cpp31
2 files changed, 26 insertions, 7 deletions
diff --git a/README.txt b/README.txt
index 8bd8554ed..4c02763ca 100644
--- a/README.txt
+++ b/README.txt
@@ -178,7 +178,7 @@ ENABLE_FREETYPE - Build with FreeType2; Allows using TTF fonts
ENABLE_GETTEXT - Build with Gettext; Allows using translations
ENABLE_GLES - Search for Open GLES headers & libraries and use them
ENABLE_LEVELDB - Build with LevelDB; Enables use of LevelDB map backend
-ENABLE_POSTGRESQL - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater required)
+ENABLE_POSTGRESQL - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended)
ENABLE_REDIS - Build with libhiredis; Enables use of Redis map backend
ENABLE_SPATIAL - Build with LibSpatial; Speeds up AreaStores
ENABLE_SOUND - Build with OpenAL, libogg & libvorbis; in-game Sounds
diff --git a/src/database-postgresql.cpp b/src/database-postgresql.cpp
index 3b6b42aea..03a69566b 100644
--- a/src/database-postgresql.cpp
+++ b/src/database-postgresql.cpp
@@ -80,12 +80,12 @@ void Database_PostgreSQL::connectToDatabase()
/*
* We are using UPSERT feature from PostgreSQL 9.5
- * to have the better performance,
- * set the minimum version to 90500
+ * to have the better performance where possible.
*/
if (m_pgversion < 90500) {
- throw DatabaseException("PostgreSQL database error: "
- "Server version 9.5 or greater required.");
+ warningstream << "Your PostgreSQL server lacks UPSERT "
+ << "support. Use version 9.5 or better if possible."
+ << std::endl;
}
infostream << "PostgreSQL Database: Version " << m_pgversion
@@ -125,11 +125,25 @@ void Database_PostgreSQL::initStatements()
"WHERE posX = $1::int4 AND posY = $2::int4 AND "
"posZ = $3::int4");
- prepareStatement("write_block",
+ if (m_pgversion < 90500) {
+ prepareStatement("write_block_insert",
+ "INSERT INTO blocks (posX, posY, posZ, data) SELECT "
+ "$1::int4, $2::int4, $3::int4, $4::bytea "
+ "WHERE NOT EXISTS (SELECT true FROM blocks "
+ "WHERE posX = $1::int4 AND posY = $2::int4 AND "
+ "posZ = $3::int4)");
+
+ prepareStatement("write_block_update",
+ "UPDATE blocks SET data = $4::bytea "
+ "WHERE posX = $1::int4 AND posY = $2::int4 AND "
+ "posZ = $3::int4");
+ } else {
+ prepareStatement("write_block",
"INSERT INTO blocks (posX, posY, posZ, data) VALUES "
"($1::int4, $2::int4, $3::int4, $4::bytea) "
"ON CONFLICT ON CONSTRAINT blocks_pkey DO "
"UPDATE SET data = $4::bytea");
+ }
prepareStatement("delete_block", "DELETE FROM blocks WHERE "
"posX = $1::int4 AND posY = $2::int4 AND posZ = $3::int4");
@@ -218,7 +232,12 @@ bool Database_PostgreSQL::saveBlock(const v3s16 &pos,
};
const int argFmt[] = { 1, 1, 1, 1 };
- execPrepared("write_block", ARRLEN(args), args, argLen, argFmt);
+ if (m_pgversion < 90500) {
+ execPrepared("write_block_update", ARRLEN(args), args, argLen, argFmt);
+ execPrepared("write_block_insert", ARRLEN(args), args, argLen, argFmt);
+ } else {
+ execPrepared("write_block", ARRLEN(args), args, argLen, argFmt);
+ }
return true;
}
a id='n283' href='#n283'>283 284 285 286 287 288 289 290 291 292 293
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#pragma once

#include <string>
#include <vector>
#include <list>

#include "irrlichttypes.h"
#include "util/enriched_string.h"
#include "settings.h"

// Chat console related classes

struct ChatLine
{
	// age in seconds
	f32 age = 0.0f;
	// name of sending player, or empty if sent by server
	EnrichedString name;
	// message text
	EnrichedString text;

	ChatLine(const std::wstring &a_name, const std::wstring &a_text):
		name(a_name),
		text(a_text)
	{
	}

	ChatLine(const EnrichedString &a_name, const EnrichedString &a_text):
		name(a_name),
		text(a_text)
	{
	}
};

struct ChatFormattedFragment
{
	// text string
	EnrichedString text;
	// starting column
	u32 column;
	// formatting
	//u8 bold:1;
};

struct ChatFormattedLine
{
	// Array of text fragments
	std::vector<ChatFormattedFragment> fragments;
	// true if first line of one formatted ChatLine
	bool first;
};

class ChatBuffer
{
public:
	ChatBuffer(u32 scrollback);
	~ChatBuffer() = default;

	// Append chat line
	// Removes oldest chat line if scrollback size is reached
	void addLine(const std::wstring &name, const std::wstring &text);

	// Remove all chat lines
	void clear();

	// Get number of lines currently in buffer.
	u32 getLineCount() const;
	// Get reference to i-th chat line.
	const ChatLine& getLine(u32 index) const;

	// Increase each chat line's age by dtime.
	void step(f32 dtime);
	// Delete oldest N chat lines.
	void deleteOldest(u32 count);
	// Delete lines older than maxAge.
	void deleteByAge(f32 maxAge);

	// Get number of columns, 0 if reformat has not been called yet.
	u32 getColumns() const;
	// Get number of rows, 0 if reformat has not been called yet.
	u32 getRows() const;
	// Update console size and reformat all formatted lines.
	void reformat(u32 cols, u32 rows);
	// Get formatted line for a given row (0 is top of screen).
	// Only valid after reformat has been called at least once
	const ChatFormattedLine& getFormattedLine(u32 row) const;
	// Scrolling in formatted buffer (relative)
	// positive rows == scroll up, negative rows == scroll down
	void scroll(s32 rows);
	// Scrolling in formatted buffer (absolute)
	void scrollAbsolute(s32 scroll);
	// Scroll to bottom of buffer (newest)
	void scrollBottom();
	// Scroll to top of buffer (oldest)
	void scrollTop();

	// Format a chat line for the given number of columns.
	// Appends the formatted lines to the destination array and
	// returns the number of formatted lines.
	u32 formatChatLine(const ChatLine& line, u32 cols,
			std::vector<ChatFormattedLine>& destination) const;

	void resize(u32 scrollback);
protected:
	s32 getTopScrollPos() const;
	s32 getBottomScrollPos() const;

private:
	// Scrollback size
	u32 m_scrollback;
	// Array of unformatted chat lines
	std::vector<ChatLine> m_unformatted;

	// Number of character columns in console
	u32 m_cols = 0;
	// Number of character rows in console
	u32 m_rows = 0;
	// Scroll position (console's top line index into m_formatted)
	s32 m_scroll = 0;
	// Array of formatted lines
	std::vector<ChatFormattedLine> m_formatted;
	// Empty formatted line, for error returns
	ChatFormattedLine m_empty_formatted_line;
};

class ChatPrompt
{
public:
	ChatPrompt(const std::wstring &prompt, u32 history_limit);
	~ChatPrompt() = default;

	// Input character or string
	void input(wchar_t ch);
	void input(const std::wstring &str);

	// Add a string to the history
	void addToHistory(const std::wstring &line);

	// Get current line
	std::wstring getLine() const { return m_line; }

	// Get section of line that is currently selected
	std::wstring getSelection() const { return m_line.substr(m_cursor, m_cursor_len); }

	// Clear the current line
	void clear();

	// Replace the current line with the given text
	std::wstring replace(const std::wstring &line);

	// Select previous command from history
	void historyPrev();
	// Select next command from history
	void historyNext();

	// Nick completion
	void nickCompletion(const std::list<std::string>& names, bool backwards);

	// Update console size and reformat the visible portion of the prompt
	void reformat(u32 cols);
	// Get visible portion of the prompt.
	std::wstring getVisiblePortion() const;
	// Get cursor position (relative to visible portion). -1 if invalid
	s32 getVisibleCursorPosition() const;
	// Get length of cursor selection
	s32 getCursorLength() const { return m_cursor_len; }

	// Cursor operations
	enum CursorOp {
		CURSOROP_MOVE,
		CURSOROP_SELECT,
		CURSOROP_DELETE
	};

	// Cursor operation direction
	enum CursorOpDir {
		CURSOROP_DIR_LEFT,
		CURSOROP_DIR_RIGHT
	};

	// Cursor operation scope
	enum CursorOpScope {
		CURSOROP_SCOPE_CHARACTER,
		CURSOROP_SCOPE_WORD,
		CURSOROP_SCOPE_LINE,
		CURSOROP_SCOPE_SELECTION
	};

	// Cursor operation
	// op specifies whether it's a move or delete operation
	// dir specifies whether the operation goes left or right
	// scope specifies how far the operation will reach (char/word/line)
	// Examples:
	//   cursorOperation(CURSOROP_MOVE, CURSOROP_DIR_RIGHT, CURSOROP_SCOPE_LINE)
	//     moves the cursor to the end of the line.
	//   cursorOperation(CURSOROP_DELETE, CURSOROP_DIR_LEFT, CURSOROP_SCOPE_WORD)
	//     deletes the word to the left of the cursor.
	void cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope scope);

protected:
	// set m_view to ensure that 0 <= m_view <= m_cursor < m_view + m_cols
	// if line can be fully shown, set m_view to zero
	// else, also ensure m_view <= m_line.size() + 1 - m_cols
	void clampView();

private:
	// Prompt prefix
	std::wstring m_prompt = L"";
	// Currently edited line
	std::wstring m_line = L"";
	// History buffer
	std::vector<std::wstring> m_history;
	// History index (0 <= m_history_index <= m_history.size())
	u32 m_history_index = 0;
	// Maximum number of history entries
	u32 m_history_limit;

	// Number of columns excluding columns reserved for the prompt
	s32 m_cols = 0;
	// Start of visible portion (index into m_line)
	s32 m_view = 0;
	// Cursor (index into m_line)
	s32 m_cursor = 0;
	// Cursor length (length of selected portion of line)
	s32 m_cursor_len = 0;

	// Last nick completion start (index into m_line)
	s32 m_nick_completion_start = 0;
	// Last nick completion start (index into m_line)
	s32 m_nick_completion_end = 0;
};

class ChatBackend
{
public:
	ChatBackend();
	~ChatBackend() = default;

	// Add chat message
	void addMessage(const std::wstring &name, std::wstring text);
	// Parse and add unparsed chat message
	void addUnparsedMessage(std::wstring line);

	// Get the console buffer
	ChatBuffer& getConsoleBuffer();
	// Get the recent messages buffer
	ChatBuffer& getRecentBuffer();
	// Concatenate all recent messages
	EnrichedString getRecentChat() const;
	// Get the console prompt
	ChatPrompt& getPrompt();

	// Reformat all buffers
	void reformat(u32 cols, u32 rows);

	// Clear all recent messages
	void clearRecentChat();

	// Age recent messages
	void step(float dtime);

	// Scrolling
	void scroll(s32 rows);
	void scrollPageDown();
	void scrollPageUp();

	// Resize recent buffer based on settings
	void applySettings();

private:
	ChatBuffer m_console_buffer;
	ChatBuffer m_recent_buffer;
	ChatPrompt m_prompt;
};