From b663b422800b8874d6cc1f0fd60400c0a677b7be Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Tue, 9 Aug 2022 16:32:18 +0200 Subject: [PATCH 01/57] initial changes that allow the creation of a new interface (psql) --- docker-compose.yml | 24 +-- postgresql-interface/build.gradle | 66 +++++++ postgresql-interface/lombok.config | 4 + .../db/postgresql/PostgresqlInterface.java | 166 ++++++++++++++++++ .../src/main/resources/log4j2.xml | 22 +++ settings.gradle | 1 + 6 files changed, 271 insertions(+), 12 deletions(-) create mode 100644 postgresql-interface/build.gradle create mode 100644 postgresql-interface/lombok.config create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java create mode 100644 postgresql-interface/src/main/resources/log4j2.xml diff --git a/docker-compose.yml b/docker-compose.yml index e87cf3c3c2..2605a37921 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,15 @@ version: "3.4" services: - remote-api: - image: polypheny/polypheny-connector - restart: unless-stopped - container_name: polypheny-connector - ports: - - "2376:443" - environment: - - CREATE_CERTS_WITH_PW=supersecret - - CERT_HOSTNAME=localhost + remote-api: + image: polypheny/polypheny-connector + restart: unless-stopped + container_name: polypheny-connector + ports: + - "2376:443" + environment: + - CREATE_CERTS_WITH_PW=supersecret + - CERT_HOSTNAME=localhost - CERT_EXPIRATION_DAYS=3650 - volumes: - - ${POLYPHENY_HOME:-~}/.polypheny/certs/localhost:/data/certs - - /var/run/docker.sock:/var/run/docker.sock:ro \ No newline at end of file + volumes: + - ${POLYPHENY_HOME:-~}/.polypheny/certs/localhost:/data/certs + - /var/run/docker.sock:/var/run/docker.sock:ro \ No newline at end of file diff --git a/postgresql-interface/build.gradle b/postgresql-interface/build.gradle new file mode 100644 index 0000000000..11f5b33d01 --- /dev/null +++ b/postgresql-interface/build.gradle @@ -0,0 +1,66 @@ +group "org.polypheny" + + +configurations { + tests { + extendsFrom testRuntimeOnly + } +} + +dependencies { + implementation project(":core") + implementation project(":monitoring") + + + // --- Test Compile --- + testImplementation project(path: ":core", configuration: "tests") + + testImplementation group: "junit", name: "junit", version: junit_version +} + + +sourceSets { + main { + java { + srcDirs = ["src/main/java"] + outputDir = file(project.buildDir.absolutePath + "/classes") + } + resources { + srcDirs = ["src/main/resources"] + } + output.resourcesDir = file(project.buildDir.absolutePath + "/classes") + } + test { + java { + srcDirs = ["src/test/java"] + outputDir = file(project.buildDir.absolutePath + "/test-classes") + } + resources { + srcDirs = ["src/test/resources"] + } + output.resourcesDir = file(project.buildDir.absolutePath + "/test-classes") + } +} + + +/** + * Tests + */ +test { + maxHeapSize = "2g" // Increase heap size (default is 512MB) +} + +/** + * JARs + */ +jar { + manifest { + attributes "Manifest-Version": "1.0" + attributes "Copyright": "The Polypheny Project (polypheny.org)" + attributes "Version": "$project.version" + } +} +java { + withJavadocJar() + withSourcesJar() +} diff --git a/postgresql-interface/lombok.config b/postgresql-interface/lombok.config new file mode 100644 index 0000000000..b034fcb60e --- /dev/null +++ b/postgresql-interface/lombok.config @@ -0,0 +1,4 @@ +# This file is generated by the 'io.freefair.lombok' Gradle plugin +config.stopBubbling = true +lombok.val.flagUsage = error +lombok.var.flagUsage = error diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java new file mode 100644 index 0000000000..d29bb11f81 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java @@ -0,0 +1,166 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + + +import com.google.common.collect.ImmutableList; +import lombok.extern.slf4j.Slf4j; +import org.polypheny.db.catalog.Catalog.QueryLanguage; +import org.polypheny.db.iface.Authenticator; +import org.polypheny.db.iface.QueryInterface; +import org.polypheny.db.information.InformationGroup; +import org.polypheny.db.information.InformationManager; +import org.polypheny.db.information.InformationPage; +import org.polypheny.db.information.InformationTable; +import org.polypheny.db.transaction.TransactionManager; +import org.polypheny.db.util.Util; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + + + +@Slf4j +public class PostgresqlInterface extends QueryInterface { + + @SuppressWarnings("WeakerAccess") + public static final String INTERFACE_NAME = "Postgresql Interface"; + @SuppressWarnings("WeakerAccess") + //TODO: Text abändern + public static final String INTERFACE_DESCRIPTION = "HTTP-based query interface, which supports all available languages via specific routes."; + @SuppressWarnings("WeakerAccess") + public static final List AVAILABLE_SETTINGS = ImmutableList.of( + new QueryInterfaceSettingInteger( "port", false, true, false, 13137 ) + //new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ) + //kann mehr selber hinzufügen + ); + + + private final int port; + private final String uniqueName; + + // Counters + private final Map statementCounters = new HashMap<>(); + + private final MonitoringPage monitoringPage; + + + public PostgresqlInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { + super( transactionManager, authenticator, ifaceId, uniqueName, settings, true, true ); + this.uniqueName = uniqueName; + this.port = Integer.parseInt( settings.get( "port" ) ); + if ( !Util.checkIfPortIsAvailable( port ) ) { + // Port is already in use + throw new RuntimeException( "Unable to start " + INTERFACE_NAME + " on port " + port + "! The port is already in use." ); + } + // Add information page + monitoringPage = new MonitoringPage(); + } + + + @Override + public void run() { + //ToDo: Instantiate Server (open port...) + + } + + + + @Override + public List getAvailableSettings() { + return AVAILABLE_SETTINGS; + } + + + @Override + public void shutdown() { + //todo: end things from run() + } + + + @Override + public String getInterfaceType() { + return INTERFACE_NAME; + } + + + @Override + protected void reloadSettings( List updatedSettings ) { + //Todo: if settings are mutable, change it here (can make them mutable) + } + + + private class MonitoringPage { + //TodO: vergliiche met anderne interfaces (zeigt infos em ui aah) + + private final InformationPage informationPage; + private final InformationGroup informationGroupRequests; + private final InformationTable statementsTable; + + + public MonitoringPage() { + InformationManager im = InformationManager.getInstance(); + + informationPage = new InformationPage( uniqueName, INTERFACE_NAME ).fullWidth().setLabel( "Interfaces" ); + informationGroupRequests = new InformationGroup( informationPage, "Requests" ); + + im.addPage( informationPage ); + im.addGroup( informationGroupRequests ); + + statementsTable = new InformationTable( + informationGroupRequests, + Arrays.asList( "Language", "Percent", "Absolute" ) + ); + statementsTable.setOrder( 2 ); + im.registerInformation( statementsTable ); + + informationGroupRequests.setRefreshFunction( this::update ); + } + + + //reload button + public void update() { + double total = 0; + for ( AtomicLong counter : statementCounters.values() ) { + total += counter.get(); + } + + DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(); + symbols.setDecimalSeparator( '.' ); + DecimalFormat df = new DecimalFormat( "0.0", symbols ); + statementsTable.reset(); + for ( Map.Entry entry : statementCounters.entrySet() ) { + statementsTable.addRow( entry.getKey().name(), df.format( total == 0 ? 0 : (entry.getValue().longValue() / total) * 100 ) + " %", entry.getValue().longValue() ); + } + } + + + public void remove() { + InformationManager im = InformationManager.getInstance(); + im.removeInformation( statementsTable ); + im.removeGroup( informationGroupRequests ); + im.removePage( informationPage ); + } + + } + +} diff --git a/postgresql-interface/src/main/resources/log4j2.xml b/postgresql-interface/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..5f6546b74f --- /dev/null +++ b/postgresql-interface/src/main/resources/log4j2.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 5b88423a1f..83e5bd45ae 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,6 +30,7 @@ include 'plugins:jdbc-adapter-framework' include 'plugins:avatica-interface' include 'plugins:rest-interface' include 'plugins:http-interface' +include 'plugins:postgresql-interface' // adapters plugins include 'plugins:hsqldb-adapter' From a9d6f4124d14780d69ae5f53920e955d750a9d3f Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Tue, 16 Aug 2022 13:08:56 +0200 Subject: [PATCH 02/57] 1.)deletes a HttpRestServer interface correctly -- 2.) It is now possible to receive a message from a psql client. But it does not send a correct reply to the client, neither does it anything with the message. --- postgresql-interface/build.gradle | 4 + .../org/polypheny/db/postgresql/Decoder.java | 73 +++++++++++++++++++ .../org/polypheny/db/postgresql/Encoder.java | 20 +++++ .../org/polypheny/db/postgresql/Message.java | 60 +++++++++++++++ .../db/postgresql/PostgresqlInterface.java | 73 +++++++++++++++++-- .../db/postgresql/ServerHandler.java | 60 +++++++++++++++ .../polypheny/db/restapi/HttpRestServer.java | 0 7 files changed, 285 insertions(+), 5 deletions(-) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java create mode 100644 rest-interface/src/main/java/org/polypheny/db/restapi/HttpRestServer.java diff --git a/postgresql-interface/build.gradle b/postgresql-interface/build.gradle index 11f5b33d01..0413dddda5 100644 --- a/postgresql-interface/build.gradle +++ b/postgresql-interface/build.gradle @@ -11,6 +11,10 @@ dependencies { implementation project(":core") implementation project(":monitoring") + ////// NETTY + // https://mvnrepository.com/artifact/io.netty/netty-all + implementation group: 'io.netty', name: 'netty-all', version: '4.1.24.Final' + // --- Test Compile --- testImplementation project(path: ":core", configuration: "tests") diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java new file mode 100644 index 0000000000..e841c88663 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java @@ -0,0 +1,73 @@ +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.polypheny.db.StatusService; + +import java.util.List; + +public class Decoder extends LengthFieldBasedFrameDecoder { + + private static final int HEADER_SIZE = 1; + private byte type; + private int length; + private String msgBody; + private ChannelHandlerContext ctx; + private ByteBuf in; + private List out; + + + public Decoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) throws Exception { + super(maxFrameLength, lengthFieldOffset, lengthFieldLength, + lengthAdjustment, initialBytesToStrip); + Object decoded = decode(ctx, in); + ctx.write(decoded); + } + + + /* + @Override + protected void decode (ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + this.ctx = ctx; + this.in = in; + Object decoded = decode(ctx, in); + if (decoded != null) { + out.add(decoded); + } + + } + + @Override + protected Object decode (ChannelHandlerContext ctx, ByteBuf in) throws Exception { + if (in == null) { + return null; + } + if (in.readableBytes() < HEADER_SIZE) { + throw new Exception("Only Header"); + } + + + type = in.readByte(); + length = in.readByte(); + + if(in.readableBytes() < length) { + //throw new Exception("The message is too short"); + } + + ByteBuf buf = in.readBytes(length); + byte[] b = new byte[buf.readableBytes()]; + buf.readBytes(b); + + msgBody = new String(b, "UTF-8"); + Message msg = new Message(type, length, msgBody); + + //StatusService.printInfo(String.format("decoded message:" + msgBody)); + + return msg; + + + } + + */ +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java new file mode 100644 index 0000000000..793b29037c --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java @@ -0,0 +1,20 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class Encoder { +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java new file mode 100644 index 0000000000..556097eb25 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class Message { + + //Message type + private byte type; + + //Message length + private int length; + + //Message body + private String msgBody; + + public Message(byte type, int length, String msgBody) { + this.type = type; + this.length = length; + this.msgBody = msgBody; + } + + public byte getType() { + return type; + } + + public void setType(byte type) { + this.type = type; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public String getMsgBody() { + return msgBody; + } + + public void setMsgBody(String msgBody) { + this.msgBody = msgBody; + } + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java index d29bb11f81..1a596c27f8 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java @@ -18,7 +18,18 @@ import com.google.common.collect.ImmutableList; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.handler.codec.LengthFieldPrepender; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; import lombok.extern.slf4j.Slf4j; +import org.polypheny.db.StatusService; import org.polypheny.db.catalog.Catalog.QueryLanguage; import org.polypheny.db.iface.Authenticator; import org.polypheny.db.iface.QueryInterface; @@ -29,6 +40,7 @@ import org.polypheny.db.transaction.TransactionManager; import org.polypheny.db.util.Util; +import java.nio.ByteOrder; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Arrays; @@ -45,13 +57,14 @@ public class PostgresqlInterface extends QueryInterface { @SuppressWarnings("WeakerAccess") public static final String INTERFACE_NAME = "Postgresql Interface"; @SuppressWarnings("WeakerAccess") - //TODO: Text abändern - public static final String INTERFACE_DESCRIPTION = "HTTP-based query interface, which supports all available languages via specific routes."; + // TODO: Update description text + public static final String INTERFACE_DESCRIPTION = "PostgreSQL-based query interface - in development"; @SuppressWarnings("WeakerAccess") public static final List AVAILABLE_SETTINGS = ImmutableList.of( - new QueryInterfaceSettingInteger( "port", false, true, false, 13137 ) - //new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ) - //kann mehr selber hinzufügen + new QueryInterfaceSettingInteger( "port", false, true, false, 5432 ) + // new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ), + // new QueryInterfaceSettingList( "serialization", false, true, false, ImmutableList.of( "PROTOBUF", "JSON" ) ) + // Possible to add more myself ); @@ -63,6 +76,11 @@ public class PostgresqlInterface extends QueryInterface { private final MonitoringPage monitoringPage; + // Server things + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); + + public PostgresqlInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { super( transactionManager, authenticator, ifaceId, uniqueName, settings, true, true ); @@ -81,6 +99,47 @@ public PostgresqlInterface(TransactionManager transactionManager, Authenticator public void run() { //ToDo: Instantiate Server (open port...) + try { + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel socketChannel) throws Exception { + ChannelPipeline channelPipeline = socketChannel.pipeline(); + + //Inbound + //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, Integer.MAX_VALUE, 1, 4, -4, 0, true)); + //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 1, 4, -4, 0)); + //channelPipeline.addLast("DecoderText", new Decoder(Integer.MAX_VALUE, 1, 4, -4, 0)); + //channelPipeline.addLast("headerdecoder", new StringDecoder()); + channelPipeline.addLast("decoder", new StringDecoder()); + + + //Outbound + channelPipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); + channelPipeline.addLast("encoder", new StringEncoder()); + + //Handler + channelPipeline.addLast("handler", new ServerHandler()); + + } + }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); + + // Start accepting incoming connections + ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); + + // Waits until server socket is closed --> introduces bugs --> polypheny not starting (without reset) and not displaying interface correctly + //channelFuture.channel().closeFuture().sync(); + + + } catch (Exception e) { + log.error("Exception while starting" + INTERFACE_NAME, e); + + } + + + StatusService.printInfo(String.format("%s started and is listening on port %d.", INTERFACE_NAME, port )); } @@ -94,6 +153,9 @@ public List getAvailableSettings() { @Override public void shutdown() { //todo: end things from run() + workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + monitoringPage.remove(); } @@ -106,6 +168,7 @@ public String getInterfaceType() { @Override protected void reloadSettings( List updatedSettings ) { //Todo: if settings are mutable, change it here (can make them mutable) + //nothing in avatica/http interface } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java new file mode 100644 index 0000000000..5ecb151f81 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.CharsetUtil; +import org.polypheny.db.StatusService; + +public class ServerHandler extends ChannelInboundHandlerAdapter { + @Override + public void channelRead (ChannelHandlerContext ctx, Object msg) { + //ECHO-protocol... write buffers it, the flushes + //alt: ctx. writeAndFlush(msg); + StatusService.printInfo(String.format("channel read reached...")); + + String in = (String) msg; + + ctx.write("AuthenticationOk"); + ctx.flush(); + + /* + + ChannelFuture channelFuture = ctx.write("AuthenticationOk"); + //channelFuture = ctx.write("ReadyForQuery"); + channelFuture.addListener(ChannelFutureListener.CLOSE); + + //ctx.write(msg); + //ctx.flush(); + + ByteBuf in = (ByteBuf) msg; + + */ + + } + + @Override + public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +} + diff --git a/rest-interface/src/main/java/org/polypheny/db/restapi/HttpRestServer.java b/rest-interface/src/main/java/org/polypheny/db/restapi/HttpRestServer.java new file mode 100644 index 0000000000..e69de29bb2 From e258b1d81e35a4a9b4167a1e17fdf71881e7beb9 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 25 Aug 2022 16:24:40 +0200 Subject: [PATCH 03/57] working version for a simple connection (using assumeMinServerVersion=9.0), renamed classes, started to implement structure for later --- .../org/polypheny/db/postgresql/Message.java | 60 ------ ...tgresqlInterface.java => PGInterface.java} | 19 +- .../PGInterfaceHeaderPrepender.java | 38 ++++ .../db/postgresql/PGInterfaceHeaders.java | 114 ++++++++++++ .../db/postgresql/PGInterfaceMessage.java | 75 ++++++++ .../db/postgresql/PGInterfaceServer.java | 20 ++ .../postgresql/PGInterfaceServerHandler.java | 171 ++++++++++++++++++ .../postgresql/PGInterfaceServerReader.java | 30 +++ .../postgresql/PGInterfaceServerWriter.java | 51 ++++++ ...ServerHandler.java => ServerHandler2.java} | 48 ++--- 10 files changed, 524 insertions(+), 102 deletions(-) delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java rename postgresql-interface/src/main/java/org/polypheny/db/postgresql/{PostgresqlInterface.java => PGInterface.java} (91%) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java rename postgresql-interface/src/main/java/org/polypheny/db/postgresql/{ServerHandler.java => ServerHandler2.java} (53%) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java deleted file mode 100644 index 556097eb25..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -public class Message { - - //Message type - private byte type; - - //Message length - private int length; - - //Message body - private String msgBody; - - public Message(byte type, int length, String msgBody) { - this.type = type; - this.length = length; - this.msgBody = msgBody; - } - - public byte getType() { - return type; - } - - public void setType(byte type) { - this.type = type; - } - - public int getLength() { - return length; - } - - public void setLength(int length) { - this.length = length; - } - - public String getMsgBody() { - return msgBody; - } - - public void setMsgBody(String msgBody) { - this.msgBody = msgBody; - } - -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java similarity index 91% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java rename to postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 1a596c27f8..24c043f8b2 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -19,15 +19,11 @@ import com.google.common.collect.ImmutableList; import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ByteBuf; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import io.netty.handler.codec.LengthFieldPrepender; import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.StatusService; import org.polypheny.db.catalog.Catalog.QueryLanguage; @@ -40,7 +36,6 @@ import org.polypheny.db.transaction.TransactionManager; import org.polypheny.db.util.Util; -import java.nio.ByteOrder; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Arrays; @@ -52,7 +47,7 @@ @Slf4j -public class PostgresqlInterface extends QueryInterface { +public class PGInterface extends QueryInterface { @SuppressWarnings("WeakerAccess") public static final String INTERFACE_NAME = "Postgresql Interface"; @@ -82,7 +77,7 @@ public class PostgresqlInterface extends QueryInterface { - public PostgresqlInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { + public PGInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { super( transactionManager, authenticator, ifaceId, uniqueName, settings, true, true ); this.uniqueName = uniqueName; this.port = Integer.parseInt( settings.get( "port" ) ); @@ -117,11 +112,15 @@ public void initChannel(SocketChannel socketChannel) throws Exception { //Outbound - channelPipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); - channelPipeline.addLast("encoder", new StringEncoder()); + // only accepts bytebuf + //channelPipeline.addLast("frameEncoder", new LengthFieldPrepender(4, true)); + //channelPipeline.addLast("headerPrepender", new HeaderPrepender()); + //channelPipeline.addLast("encoder", new StringEncoder()); //Handler - channelPipeline.addLast("handler", new ServerHandler()); + channelPipeline.addLast("handler", new PGInterfaceServerHandler()); + //channelPipeline.addLast("handler2", new ServerHandler2()); + //channelPipeline.addLast("handler", new ServerHandler3()); } }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java new file mode 100644 index 0000000000..a0ce4b5b25 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +import java.nio.charset.StandardCharsets; + +public class PGInterfaceHeaderPrepender extends MessageToByteEncoder { + String header = "R"; //Authentication request header + //public HeaderPrepender() { } + + @Override + protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { + ByteBuf headerBuf = Unpooled.copiedBuffer(header.getBytes(StandardCharsets.UTF_8)); + out.writeBytes(headerBuf); + //out.writeBytes(msg); + } + + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java new file mode 100644 index 0000000000..9f7f0156b6 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java @@ -0,0 +1,114 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + + +/** + * All the different header, alphabetically and sender ordered. + * There exist some special cases (as numbers as header, or no header) + * For more information look at the Postgresql documentation: https://www.postgresql.org/docs/current/protocol-message-formats.html + */ +//TODO: not complete with all commands yet (especially for copy commands, extended query cycle and different authentication methods) +public enum PGInterfaceHeaders { + + //----------------------------------------------- server to client ------------------------------------------------ + + /** + * CommandComplete - from server to client + */ + C, + + /** + * DataRow - from server to client - identifies message as a data row + */ + D, + + /** + * ErrorResponse - from server to client - message is error + * Execute - from client to server - used in extended query cycle + */ + E, + + /** + * EmptyQueryResponse - from server to client - response to empty query String  substitutes for CommandComplete + */ + I, + + /** + * NoticeResponse - from server to client + */ + N, + + /** + * no data indicator - from server to client - indicator + */ + n, + + /** + * Authenticatio request - from server to client - used by several different messages + */ + R, + + /** + * RowDescription - from server to client + */ + T, + + /** + * ParameterDescription - from server to client + */ + t, + + /** + * ReadyForQuery - from server to client - whenever backend is ready for new query cycle + */ + Z, + + /** + * ParseComplete - from server to client - indicator (actually sent as 1) + */ + //TODO: does it make sense to use the word? + ONE, + + //----------------------------------------------- client to server ------------------------------------------------ + + //E - also used from server to client, described there + //some messages with no header (StartUpMessage, CancelREquest, and some authentication requests) + + /** + * Simple Query - from client to server - used in simple query cycle + */ + Q, + + /** + * Termination message - from client to server + */ + X + +} + +/* +ONE(1); + + private final int value; + + Headers(final int newVal) { + value = newVal; + } + + public int getValue() { return value; } + */ diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java new file mode 100644 index 0000000000..abf10449bd --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class PGInterfaceMessage { + + private PGInterfaceHeaders header; + private String msgBody; + private int length; //default is 4, if a different length is mentioned in protocol, this is given + private int sizeMsgBody; //how many subparts are in the message. seperated by delimiter + private final char delimiter = '§'; + + public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, int sizeMsgBody) { + this.header = header; + this.msgBody = msgBody; + this.length = length; + this.sizeMsgBody = sizeMsgBody; + } + + public PGInterfaceHeaders getHeader() { + return this.header; + } + + public void setHeader(PGInterfaceHeaders header) { + this.header = header; + } + + public int getLength() { + return this.length; + } + + public void setLength(int length) { + this.length = length; + } + + public String getMsgBody() { + return msgBody; + } + + public void setMsgBody(String msgBody) { + this.msgBody = msgBody; + } + + + + /** + * gets the different subparts of a message + * @param part the index of the requested part(s), starting at 0 + * @return a string array with each requested part + */ + public String[] getMsgPart(int[] part) { + String subStrings[] = msgBody.split("§"); + String result[] = new String[0]; + + for (int i=0; i<(part.length); i++) { + result[i] = subStrings[i]; + } + return result; + } + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java new file mode 100644 index 0000000000..9f0dfd646e --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java @@ -0,0 +1,20 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class PGInterfaceServer { +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java new file mode 100644 index 0000000000..1669c55aad --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -0,0 +1,171 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.polypheny.db.StatusService; + +import java.lang.management.ManagementFactory; +import java.net.DatagramPacket; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.ThreadLocalRandom; + +public class PGInterfaceServerHandler extends ChannelInboundHandlerAdapter { + @Override + public void channelRead (ChannelHandlerContext ctx, Object msg) { + //ECHO-protocol... write buffers it, the flushes + //alt: ctx. writeAndFlush(msg); + StatusService.printInfo(String.format("channel read reached...")); + + String in = (String) msg; + + //----------------------------------------- alti version -------------------------------------------- + //char header = 'R'; + String header ="R"; + ByteBuf headerBuf = Unpooled.copiedBuffer(header.getBytes(StandardCharsets.UTF_8),0, 1); + //headerBuf.setByte('R', ) + + String message = "0"; + //int message = 0; + ByteBuf msgBuf = Unpooled.copiedBuffer(message.getBytes(StandardCharsets.UTF_8)); + + int size = 8; //+ msgBuf.readableBytes(); + //capacity: Returns the number of bytes (octets) this buffer can contain. + ByteBuf sizeBuf = Unpooled.copyInt(size); + + //---------------------------------------- diräkt of de buffer schriibe---------------------------------- + + //authenticationOk + ByteBuf buffer = ctx.alloc().buffer(9); + buffer.writeByte('R'); + buffer.writeInt(8); // size excluding char + buffer.writeInt(0); + //StatusService.printInfo(String.format("channel read reached...")); + ctx.writeAndFlush(buffer); + + //int x = DatagramPacket.sender; + + + + /* + String paramu = "client_encoding"; + String paramValu = "UTF8"; + ByteBuf buffer3u = ctx.alloc().buffer(4+paramu.length() + 1 + paramValu.length() + 2); + buffer3u.writeByte('S'); + buffer3u.writeInt(4+paramu.length() + 1 + paramValu.length() + 1); // size excluding char + buffer3u.writeBytes(paramu.getBytes(StandardCharsets.UTF_8)); + buffer3u.writeBytes(paramValu.getBytes(StandardCharsets.UTF_8)); + ctx.writeAndFlush(buffer3u); + + */ + + + /* + ByteBuf buffer5 = ctx.alloc().buffer(50); + buffer5.writeByte('K'); + buffer5.writeInt(12); + String pidName = ManagementFactory.getRuntimeMXBean().getName(); + int pid = Integer.parseInt(pidName.split("@")[0]); + int secretKey = ThreadLocalRandom.current().nextInt(); + buffer5.writeInt(pid); + buffer5.writeInt(secretKey); + ctx.writeAndFlush(buffer5); + + */ + + + String param = "server_version"; //.14.4 (Debian 14.4-1.pgdg110+1) + //String paramVal = "13.8"; //PG_SERVER_VERSION + String paramVal = "14"; //PG_SERVER_VERSION + //byte[] paramb = param.getBytes(StandardCharsets.UTF_8); + //byte[] paramValb = paramVal.getBytes(StandardCharsets.UTF_8); + //ByteBuf buffer3 = ctx.alloc().buffer(4+param.length() + 1 + paramVal.length() + 2); + ByteBuf buffer3 = ctx.alloc().buffer(100); + buffer3.writeByte('S'); + //int x = 4+paramb.length + 1 + paramValb.length + 2; + //int y = 4+param.length() + 1 + paramVal.length() + 2; + buffer3.writeInt(4+param.length() + 1 + paramVal.length() + 1); // size excluding char + //buffer3.writeInt(4+param.length() + 1 + paramVal.length() + 2); // size excluding char + buffer3.writeBytes(param.getBytes(StandardCharsets.US_ASCII)); + buffer3.writeByte(0); + buffer3.writeBytes(paramVal.getBytes(StandardCharsets.US_ASCII)); + buffer3.writeByte(0); + //buffer3.writeBytes(param.getBytes(StandardCharsets.UTF_8)); + //buffer3.writeByte(0); + //buffer3.writeBytes(paramVal.getBytes(StandardCharsets.UTF_8)); + ctx.writeAndFlush(buffer3); + + + + + + /* + //gibt protookollfehler wenn an dieser stelle gesendet... - no data indicator + ByteBuf buffer4 = ctx.alloc().buffer(5); + buffer4.writeByte('n'); + buffer4.writeInt(4); + ctx.writeAndFlush(buffer4); + + */ + + + ByteBuf buffer2 = ctx.alloc().buffer(6); + buffer2.writeByte('Z'); + buffer2.writeInt(5); // size excluding char + buffer2.writeByte('I'); + //StatusService.printInfo(String.format("channel read reached...")); + ctx.writeAndFlush(buffer2); + + + + //ctx.flush(); + + + + /* + ctx.write(headerBuf); + ctx.write(sizeBuf); + ctx.write(msgBuf); + ctx.flush(); + + */ + + /* + + ChannelFuture channelFuture = ctx.write("AuthenticationOk"); + //channelFuture = ctx.write("ReadyForQuery"); + channelFuture.addListener(ChannelFutureListener.CLOSE); + + //ctx.write(msg); + //ctx.flush(); + + ByteBuf in = (ByteBuf) msg; + + */ + + } + + @Override + public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +} + diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java new file mode 100644 index 0000000000..5aabc4937f --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class PGInterfaceServerReader { + + public PGInterfaceServerReader(String wholeMsg, PGInterfaceServer server) { + + switch (wholeMsg.substring(0, 1)) { + case "C": + PGInterfaceMessage msg = null; + msg.setHeader(PGInterfaceHeaders.C); + //msg.setMsgBody(); + } + } +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java new file mode 100644 index 0000000000..aaeb3f0cc2 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +public class PGInterfaceServerWriter { + String type; + PGInterfaceMessage msg; + ChannelHandlerContext ctx; + + public PGInterfaceServerWriter (String type, PGInterfaceMessage msg, ChannelHandlerContext ctx) { + this.type = type; + this.msg = msg; + this.ctx = ctx; + } + + public ByteBuf writeOnByteBuf(String type, PGInterfaceMessage msg, ChannelHandlerContext ctx) { + ByteBuf buffer = ctx.alloc().buffer(); + switch (type) { + case "s": + //write string + break; + case "c": + //write byte (char) + break; + case "i": + //write int + break; + case "ss": + //write two strings (tag and message) + } + return buffer; + } + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java similarity index 53% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java rename to postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java index 5ecb151f81..b21953ce8e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java @@ -17,44 +17,28 @@ package org.polypheny.db.postgresql; import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.util.CharsetUtil; import org.polypheny.db.StatusService; -public class ServerHandler extends ChannelInboundHandlerAdapter { - @Override - public void channelRead (ChannelHandlerContext ctx, Object msg) { - //ECHO-protocol... write buffers it, the flushes - //alt: ctx. writeAndFlush(msg); - StatusService.printInfo(String.format("channel read reached...")); - - String in = (String) msg; - - ctx.write("AuthenticationOk"); - ctx.flush(); - - /* - - ChannelFuture channelFuture = ctx.write("AuthenticationOk"); - //channelFuture = ctx.write("ReadyForQuery"); - channelFuture.addListener(ChannelFutureListener.CLOSE); - - //ctx.write(msg); - //ctx.flush(); +import java.nio.charset.StandardCharsets; - ByteBuf in = (ByteBuf) msg; - - */ - - } +public class ServerHandler2 extends ChannelInboundHandlerAdapter { @Override - public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) { - cause.printStackTrace(); - ctx.close(); + public void channelRead (ChannelHandlerContext ctx, Object msg) { + StatusService.printInfo(String.format("channel read reached...2")); + + String param = "client_encoding"; + String paramVal = "UTF8"; + ByteBuf buffer3 = ctx.alloc().buffer(4+param.length() + 1 + paramVal.length() + 2); + buffer3.writeByte('S'); + buffer3.writeInt(4+param.length() + 1 + paramVal.length() + 1); // size excluding char + buffer3.writeBytes(param.getBytes(StandardCharsets.UTF_8)); + buffer3.writeBytes(paramVal.getBytes(StandardCharsets.UTF_8)); + //StatusService.printInfo(String.format("channel read reached...")); + ctx.writeAndFlush(buffer3); } -} +} From 18075ca0df2afed94fccba394dc13d6dc6c705b0 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 14 Sep 2022 19:44:45 +0200 Subject: [PATCH 04/57] not yet able to handle queries, but set up to start doing so, expanded/generalized responses the 'server' is sending --- .../{Encoder.java => PGInterfaceClient.java} | 25 ++- .../db/postgresql/PGInterfaceHeaders.java | 22 ++- ...GInterfaceInboundCommunicationHandler.java | 176 ++++++++++++++++++ .../db/postgresql/PGInterfaceMessage.java | 59 +++++- .../postgresql/PGInterfaceQueryHandler.java | 129 +++++++++++++ .../postgresql/PGInterfaceServerHandler.java | Bin 5824 -> 5247 bytes .../postgresql/PGInterfaceServerWriter.java | 75 +++++++- .../db/postgresql/ServerHandler2.java | 44 ----- 8 files changed, 472 insertions(+), 58 deletions(-) rename postgresql-interface/src/main/java/org/polypheny/db/postgresql/{Encoder.java => PGInterfaceClient.java} (52%) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java similarity index 52% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java rename to postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java index 793b29037c..abe97739a5 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java @@ -16,5 +16,28 @@ package org.polypheny.db.postgresql; -public class Encoder { +import io.netty.channel.ChannelHandlerContext; + +import java.net.InetSocketAddress; + +public class PGInterfaceClient { + public static ChannelHandlerContext ctx = null; + public String state; + + public PGInterfaceClient (ChannelHandlerContext ctx) { + this.ctx = ctx; + //int port = ((InetSocketAddress)ctx.channel().remoteAddress()).getPort(); + } + + public static ChannelHandlerContext getCtx() { + return ctx; + } + + public void setState(String state) { + this.state = state; + } + + public String getState() { + return state; + } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java index 9f7f0156b6..690c161727 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java @@ -25,6 +25,7 @@ //TODO: not complete with all commands yet (especially for copy commands, extended query cycle and different authentication methods) public enum PGInterfaceHeaders { + //----------------------------------------------- server to client ------------------------------------------------ /** @@ -59,10 +60,15 @@ public enum PGInterfaceHeaders { n, /** - * Authenticatio request - from server to client - used by several different messages + * Authenticatio request - from server to client - (used by several different messages */ R, + /** + * ParameterStatus message - from server to client - (shauld actually be) voluntary + */ + S, + /** * RowDescription - from server to client */ @@ -81,9 +87,18 @@ public enum PGInterfaceHeaders { /** * ParseComplete - from server to client - indicator (actually sent as 1) */ - //TODO: does it make sense to use the word? ONE, + /** + * BindComplete - from server to client - indicator + */ + TWO, + + /** + * CloseComplete - from server to client - indicator + */ + THREE, + //----------------------------------------------- client to server ------------------------------------------------ //E - also used from server to client, described there @@ -99,8 +114,11 @@ public enum PGInterfaceHeaders { */ X + + } + /* ONE(1); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java new file mode 100644 index 0000000000..f5251dc425 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -0,0 +1,176 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +import java.nio.charset.StandardCharsets; + +public class PGInterfaceInboundCommunicationHandler { + String type; + PGInterfaceClient client; + ChannelHandlerContext ctx; + + public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client) { + this.type = type; + this.client = client; + this.ctx = client.getCtx(); + } + + //ich mues ergendwie identifiziere wele client dases esch... oder muesich öberhaupt speichere was fören phase das de client denne esch... + //muesich das wörklech oder esches eidütig vom protokoll här? --> has gfühl chas eidütig metem protokoll handle + + + public String decideCycle(Object oMsg) { + String cycleState = ""; + String msgWithZeroBits = ((String) oMsg); + String wholeMsg = msgWithZeroBits.replace("\u0000", ""); + + + + switch (wholeMsg.substring(0, 1)) { + case "C": + PGInterfaceMessage msg = null; + msg.setHeader(PGInterfaceHeaders.C); + //msg.setMsgBody(); + break; + case "r": + startUpPhase(); + break; + case "P": + extendedQueryPhase(wholeMsg); + break; + case "X": + terminateConnection(); + break; + + } + return cycleState; + } + + public void startUpPhase() { + //authenticationOk + PGInterfaceMessage authenticationOk = new PGInterfaceMessage(PGInterfaceHeaders.R, "0", 8, false); + PGInterfaceServerWriter authenticationOkWriter = new PGInterfaceServerWriter("i", authenticationOk, ctx); + ctx.writeAndFlush(authenticationOkWriter.writeOnByteBuf()); + + //server_version (Parameter Status message) + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version§14", 4, true); + PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter("ss", parameterStatusServerVs, ctx); + ctx.writeAndFlush(parameterStatusServerVsWriter.writeOnByteBuf()); + + //ReadyForQuery + sendReadyForQuery("I"); + } + + public void simpleQueryPhase() { + + } + + public void extendedQueryPhase(String incomingMsg) { + + if (incomingMsg.substring(2,5).equals("SET")) { + //parseComplete + /* + PGInterfaceMessage parseComplete = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, false); + PGInterfaceServerWriter parseCompleteWriter = new PGInterfaceServerWriter("i", parseComplete, ctx); + ctx.writeAndFlush(parseCompleteWriter.writeOnByteBuf()); + + */ + + //ParameterStatus - client_encoding (ParameterStatus message) + String paramu = "SET"; + String paramValu = "UTF8"; + ByteBuf buffer3u = ctx.alloc().buffer(4+paramu.length()+10); + buffer3u.writeByte('1'); + buffer3u.writeInt(4); // size excluding char + //buffer3u.writeBytes(paramu.getBytes(StandardCharsets.UTF_8)); + //buffer3u.writeBytes(paramValu.getBytes(StandardCharsets.UTF_8)); + ctx.writeAndFlush(buffer3u); + + /* + //bindComplete + PGInterfaceMessage bindComplete = new PGInterfaceMessage(PGInterfaceHeaders.TWO, "0", 4, true); + PGInterfaceServerWriter bindCompleteWriter = new PGInterfaceServerWriter("i", bindComplete, ctx); + ctx.writeAndFlush(bindCompleteWriter.writeOnByteBuf()); + + */ + + ByteBuf buffer4u = ctx.alloc().buffer(4+10); + buffer4u.writeByte('2'); + buffer4u.writeInt(4); // size excluding char + ctx.writeAndFlush(buffer4u); + + //commandComplete - SET + PGInterfaceMessage commandCompleteSET = new PGInterfaceMessage(PGInterfaceHeaders.C, "SET", 4, true); + PGInterfaceServerWriter commandCompleteSETWriter = new PGInterfaceServerWriter("s", commandCompleteSET, ctx); + ctx.writeAndFlush(commandCompleteSETWriter.writeOnByteBuf()); + + sendReadyForQuery("I"); + } + else { + //Query does not have ";" at the end!! + String query = extractQuery(incomingMsg); + + } + + + } + + /** + * creates and sends (flushes on ctx) a readyForQuery message. Tag is choosable. + * @param msgBody give the Tag - current transaction status indicator (possible vals: I (idle, not in transaction block), + * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) + */ + public void sendReadyForQuery(String msgBody) { + PGInterfaceMessage readyForQuery = new PGInterfaceMessage(PGInterfaceHeaders.Z, msgBody, 5, false); + PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter("c", readyForQuery, ctx); + ctx.writeAndFlush(readyForQueryWriter.writeOnByteBuf()); + } + + + public String extractQuery(String incomingMsg) { + String query = ""; + //cut header + query = incomingMsg.substring(2, incomingMsg.length()-1); + + //find end of query --> normally it ends with combination of BDPES (are headers, with some weird other bits in between) + //B starts immediatelly after query --> find position of correct B and end of query is found + byte[] byteSequence = {66, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 6, 80, 0, 69, 0, 0, 0, 9, 0, 0, 0, 0, 0, 83, 0, 0, 0, 4}; + String msgWithZeroBits = new String(byteSequence, StandardCharsets.UTF_8); + String endSequence = msgWithZeroBits.replace("\u0000", ""); + + int idx = incomingMsg.indexOf(endSequence); + if (idx != -1) { + query = query.substring(0, idx-2); + } + else { + //TODO something went wrong!! + int lol = 2; + } + + return query; + } + + + public void terminateConnection() { + ctx.close(); + } + + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index abf10449bd..7310ae43ca 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -16,25 +16,66 @@ package org.polypheny.db.postgresql; +//message sent by client and server (connection-level) public class PGInterfaceMessage { private PGInterfaceHeaders header; private String msgBody; private int length; //default is 4, if a different length is mentioned in protocol, this is given - private int sizeMsgBody; //how many subparts are in the message. seperated by delimiter - private final char delimiter = '§'; + private boolean defaultLength; + private final char delimiter = '§'; //for the subparts - public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, int sizeMsgBody) { + public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength) { this.header = header; this.msgBody = msgBody; this.length = length; - this.sizeMsgBody = sizeMsgBody; + this.defaultLength = defaultLength; } public PGInterfaceHeaders getHeader() { return this.header; } + public char getHeaderChar() { + + //if header is a single character + if (header != PGInterfaceHeaders.ONE && header != PGInterfaceHeaders.TWO && header != PGInterfaceHeaders.THREE) { + String headerString = header.toString(); + return headerString.charAt(0); + } + //if header is a number + //TODO: make a nicer version of this... if you cast headerInt to char directly it returns '\u0001' and not '1' + else { + int headerInt = getHeaderInt(); + if (headerInt == 1) { + return '1'; + } + else if (headerInt == 2) { + return '2'; + } + else if (headerInt == 3) { + return '3'; + } + } + //TODO: if returns 0, something went wrong + return 0; + } + + public int getHeaderInt() { + String headerString = header.toString(); + if(headerString.equals("ONE")) { + return 1; + } + else if(headerString.equals("TWO")) { + return 2; + } + else if (headerString.equals("THREE")) { + return 3; + } + //TODO: if returns 0, something went wrong + return 0; + } + public void setHeader(PGInterfaceHeaders header) { this.header = header; } @@ -47,6 +88,14 @@ public void setLength(int length) { this.length = length; } + public void setDefaultLength(boolean val) { + this.defaultLength = val; + } + + public boolean isDefaultLength() { + return this.defaultLength; + } + public String getMsgBody() { return msgBody; } @@ -64,7 +113,7 @@ public void setMsgBody(String msgBody) { */ public String[] getMsgPart(int[] part) { String subStrings[] = msgBody.split("§"); - String result[] = new String[0]; + String result[] = new String[part.length]; for (int i=0; i<(part.length); i++) { result[i] = subStrings[i]; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java new file mode 100644 index 0000000000..a5711878f8 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -0,0 +1,129 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.channel.ChannelHandlerContext; + +public class PGInterfaceQueryHandler { + String query; + ChannelHandlerContext ctx; + + public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx) { + this.query = query; + this.ctx = ctx; + } + + public void sendQueryToPolypheny() { + String type = ""; //query type according to answer tags + //get result from polypheny + + //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) + + //handle result --> depending on query type, prepare answer message accordingly here (flush it) + switch (type) { + case "INSERT": + //INSERT oid rows (oid=0, rows = #rows inserted) + //1....2....n....C....INSERT 0 1.Z....I + break; + + case "SELECT" : + //SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) + //1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I + //1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I + break; + + case "DELETE" : + //DELETE rows (rows = #rows deleted) + break; + + case "MOVE": + //MOVE rows (rows = #rows the cursor's position has been changed by (??)) + break; + + case "FETCH": + //FETCH rows (rows = #rows that have been retrieved from cursor) + break; + + case "COPY": + //COPY rows (rows = #rows copied --> only on PSQL 8.2 and later) + break; + + } + } + + + //Example of server answer to simple select query (from real server) + /* + 1....2....T......lolid...@...............D..........1D..........2D..........3D..........3D..........3D..........3C... +SELECT 6.Z....I + +(result: 1,2,3,3,3,3) +1: ParseComplete indicator +2: BindComplete indicator +T: RowDescription - specifies the number of fields in a row (can be 0) - then for each field: + field name (string), lolid + ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 + attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 + ObjectID of fields data type (Int32), 1 + data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 + type modifier (meaning of modifier is type-specific) (see pg_attribute.atttypmod) (Int32), 4 + Format code used for the field (zero(text) or one(binary)) --> if rowDescription is returned from statement variant of DESCRIBE: format code not yet known (always zero) (Int16) + +D: DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: + length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), + value of the col (in format indicated by associated format code) + +C: CommandComplete - msgBody is commandTag (which sql command was completed) + SET (not in list on website, but "observed in the wild"), + INSERT oid rows (oid=0, rows = #rows inserted), + SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands), + UPDATE rows (rows = #rows updated), + DELETE rows (rows = #rows deleted), + MOVE rows (rows = #rows the cursor's position has been changed by (??)), + FETCH rows (rows = #rows that have been retrieved from cursor), + COPY rows (rows = #rows copied --> only on PSQL 8.2 and later) + +Z: Ready for query (tags) + I: idle + + +1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I +1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I +differences from wireshark Data.data (diffs at right position) +ff's format code? + + +from website: +atttypmod int4 +atttypmod records type-specific data supplied at table creation time (for example, the maximum length of a varchar column). +It is passed to type-specific input functions and length coercion functions. The value will generally be -1 for types that do not need atttypmod. + +typlen int2 +For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative. +-1 indicates a “varlena” type (one that has a length word), -2 indicates a null-terminated C string. + +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +insert: + +P...).INSERT INTO lol(LolId) VALUES (4)...B............D....P.E... .....S.... +1....2....n....C....INSERT 0 1.Z....I +X.... + +n: noData indicator +C: CommandComplete + */ +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 1669c55aad55adff07057c3cd6af52918d72bd8b..c828421d620b6601b6bb2b4c5763d7548b28564e 100644 GIT binary patch literal 5247 zcmb7I{chXH5$B=B0X6Ow3Jmm*sYE7iCq`2T?wu{$jT*=DNpjM=qA*tEO4>8Et1OpR zbj7_*fxbukV*L$2B+B0*AWGuS&dhJVm*I;IdO>Y7TUa%oINIIb`SaH9_UDvYl7?rU_Q`qwWD5$HC@*y))0C|IoGA;i!v%>M z6pF+UY9?Y%#*!FYi8W_f;ki{#>2ZrvGjelbC2JY0)LAvm+?u^g90b&L0$5CFY8>{d z({IqxVZYOFF_TZ7!MpC|fIc1edWYwO&PkuTJ!*H)k2`}-_ZG1p~dfz!eZjpqw z;1~I2W*Gt0RBTBZ=Vt3mHuut3G{QRnPiHbxBNYLf9%o`KX>4w!)j&iuX{Rb>kET#C zW|a~(RZh74(JBsV{s}iWVCQRQ1WO0ADwu+Jh(D==<t z?z#h|4|Jop2KXkFrsu;0}t7Ly;R7}u< zt=5wwCcosgZaRwGmlk!0TncEKj+-S<<`jk}?RVX+nKjNtCJBNdPX|ebH&arsm513V z$a-%&gL`qesT?BfIoCKon1f^BW}!q%C0J zhN=`pnMM<=YP@(4r|bch44Mq6MiPcw&%Fo$6v3={#e429rdui$qOO)#7y^Q&3G_z} zAJArRvu=c3@oKTrYpmAFd?|M#bFjI}kpQI;`HzRlEWg+ujHTl}DJ-xacfsZ0^y*Es zwcVnfng_zL*a$8G!jt#<(5^+zJC>ay&N=Z9sIgsBF%01~S}kth)gE4WO!ac_le*Wv z%`#KTP+k2*$;F+{L#*Ui-XMSDRj-f>!&VACBlJ_J9ArcC2Mw zr5~ly#40tEPe*56CR;AA%}5jfP9bY@&X)P+H(|}Gak4COezVCwx-!t+pG!){5b6Zs7VrmPLDv*v7$uAIZNAr$|;s_L!Cl7lotyph9Z^a-y*TDq>fCC&gr2+yz!2OlYO^Hq}S

jJ_XUjJmkL(DBo#OEt4 zAK~*IKKXTm`ycq%H+|fGzs~4SIiqq)=WM>xa6Q;;UK9go|Hm`>+woDGj;%s~Y=Xt} zxi`HIP6)jLbEq$qB_?wJRTKQ^i1_{;-}8%(3E%WBU64m7{5#j5 zzUk-BZ$bDYAe^1F2bA-s(_Z%ji((EBF<$5EQN_1%FPr#bwrlv0LHg~5w=}X>8hM#2 zVaW60;?&q5Gievg=l7(L{rt5l^fOYZgV5f4eu=T4pO-Qb*yaj7oiP>5`!Z&UH*e0X z;9HyDmIbG*H(O=dU#1VOYSKd`shDbM#5scAq<)F!sWJCKJsC*JB}e}ijPCZXO2L}6B8I9gT??Tj z9Go%Myq60US+PX9?#I3R-MF`1lTnD>t9$1CUC)&3?3kUpW2?|o@p(~4KM0Mneu^RE zR7B3$1rK?>3^T`6e)#*56dK`#M@(Ly`!MFv3}?&(f($vv=^oBWB@4u3rVdiPp}_g= zheq=s+yAT~;H{~QtaPvj7z`#nwx5|uBt0Bk%ruBHYoQS&YxEH2S=+v5fKuLL%S%x; zqKCY>SEE@u^S7cbJbchD-f*EiwME7+-5xt^1Ff0oFPtKQ_Pl=L&L0&=Vbqc6dSLNp zpbkC^2PQWAL}^Jk#^S(_Nm=sCx}nl>hNPNj7IXBCnd02Ttr7gD2Y(vI*HLpY8*8t()Ei5mPy4{rhR#wb}dmXXUQ%!w=Ye%pYZ F{tq_&D2f08 delta 1793 zcmb7E&ubGw6sFb^4d^DO)>YbxTxz|PG3zV~C^`+n&kXWmr?mmI<@ z+$4-xv`Lx3mwUf!q$XV6UP#)_O_vLFhukHYQGqWIK`c(1S4nMy3MmGsXQC#aupL}; zSUGNTJ#GuS+!j=yEKUC9y1;~fTE0o?qaAa#pN-fWhJ3qwMLtiC&39PguII-v zY$nisw20!#;TB~k#UQu{I>mogdoB(14%x8J89cMe`?sVx9cv?#wzc?DL> zcG<*&O2aU4E|2p_zd)-tVMuLea(L4+tz2$)DwmB!Q5M{07TP3G-W$YGl(~6)8i)+z z>cvWVwRB^(RDo44tY7Kje3X2xCC+y-`F|h`qYBl$b-UxK3VwW-^5@X8$*}ryE8y-K z!oRXT617$Dv+UJTr@Hg%E#&=!0|B={3BKb5iwsj&Dwv`59j5=$c@Hj=a z*lrPp?k1Kz(Eznp)d%HT- Date: Thu, 22 Sep 2022 11:08:55 +0200 Subject: [PATCH 05/57] (forgot to add) not working vs of psql interface, pushing because of exception while starting polypheny --- .../polypheny/db/postgresql/PGInterface.java | 6 + ...GInterfaceInboundCommunicationHandler.java | 162 +++++++++--- .../db/postgresql/PGInterfaceMessage.java | 9 +- .../postgresql/PGInterfaceQueryHandler.java | 240 +++++++++++++++++- .../postgresql/PGInterfaceServerWriter.java | 127 ++++++++- 5 files changed, 495 insertions(+), 49 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 24c043f8b2..9d1f74e661 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -61,6 +61,7 @@ public class PGInterface extends QueryInterface { // new QueryInterfaceSettingList( "serialization", false, true, false, ImmutableList.of( "PROTOBUF", "JSON" ) ) // Possible to add more myself ); + public static TransactionManager transactionManager = null; private final int port; @@ -87,8 +88,13 @@ public PGInterface(TransactionManager transactionManager, Authenticator authenti } // Add information page monitoringPage = new MonitoringPage(); + this.transactionManager = transactionManager; } + public static TransactionManager getInstance() { + return transactionManager; + } //getTransactionManager + @Override public void run() { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index f5251dc425..91160be3a9 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; public class PGInterfaceInboundCommunicationHandler { String type; @@ -70,7 +71,7 @@ public void startUpPhase() { ctx.writeAndFlush(authenticationOkWriter.writeOnByteBuf()); //server_version (Parameter Status message) - PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version§14", 4, true); + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter("ss", parameterStatusServerVs, ctx); ctx.writeAndFlush(parameterStatusServerVsWriter.writeOnByteBuf()); @@ -85,36 +86,8 @@ public void simpleQueryPhase() { public void extendedQueryPhase(String incomingMsg) { if (incomingMsg.substring(2,5).equals("SET")) { - //parseComplete - /* - PGInterfaceMessage parseComplete = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, false); - PGInterfaceServerWriter parseCompleteWriter = new PGInterfaceServerWriter("i", parseComplete, ctx); - ctx.writeAndFlush(parseCompleteWriter.writeOnByteBuf()); - - */ - - //ParameterStatus - client_encoding (ParameterStatus message) - String paramu = "SET"; - String paramValu = "UTF8"; - ByteBuf buffer3u = ctx.alloc().buffer(4+paramu.length()+10); - buffer3u.writeByte('1'); - buffer3u.writeInt(4); // size excluding char - //buffer3u.writeBytes(paramu.getBytes(StandardCharsets.UTF_8)); - //buffer3u.writeBytes(paramValu.getBytes(StandardCharsets.UTF_8)); - ctx.writeAndFlush(buffer3u); - - /* - //bindComplete - PGInterfaceMessage bindComplete = new PGInterfaceMessage(PGInterfaceHeaders.TWO, "0", 4, true); - PGInterfaceServerWriter bindCompleteWriter = new PGInterfaceServerWriter("i", bindComplete, ctx); - ctx.writeAndFlush(bindCompleteWriter.writeOnByteBuf()); - - */ - - ByteBuf buffer4u = ctx.alloc().buffer(4+10); - buffer4u.writeByte('2'); - buffer4u.writeInt(4); // size excluding char - ctx.writeAndFlush(buffer4u); + + sendParseBindComplete(); //commandComplete - SET PGInterfaceMessage commandCompleteSET = new PGInterfaceMessage(PGInterfaceHeaders.C, "SET", 4, true); @@ -126,6 +99,8 @@ public void extendedQueryPhase(String incomingMsg) { else { //Query does not have ";" at the end!! String query = extractQuery(incomingMsg); + PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this); + queryHandler.start(); } @@ -151,26 +126,147 @@ public String extractQuery(String incomingMsg) { //find end of query --> normally it ends with combination of BDPES (are headers, with some weird other bits in between) //B starts immediatelly after query --> find position of correct B and end of query is found - byte[] byteSequence = {66, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 6, 80, 0, 69, 0, 0, 0, 9, 0, 0, 0, 0, 0, 83, 0, 0, 0, 4}; + byte[] byteSequence = {66, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 6, 80, 0, 69, 0, 0, 0, 9}; String msgWithZeroBits = new String(byteSequence, StandardCharsets.UTF_8); String endSequence = msgWithZeroBits.replace("\u0000", ""); + String endOfQuery = query.substring(incomingMsg.length()-20); + int idx = incomingMsg.indexOf(endSequence); if (idx != -1) { query = query.substring(0, idx-2); } else { - //TODO something went wrong!! + //TODO(FF) something went wrong!! --> trow exception (in polypheny), send errormessage to client int lol = 2; } return query; } + public void sendParseBindComplete() { + //TODO(FF): This should work with the normal PGInterfaceServerWriter type "i" (called like in the commented out part), + // but it does not --> roundabout solution that works, but try to figure out what went wrong... + + /* + //parseComplete + PGInterfaceMessage parseComplete = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, true); + PGInterfaceServerWriter parseCompleteWriter = new PGInterfaceServerWriter("i", parseComplete, ctx); + ctx.writeAndFlush(parseCompleteWriter.writeOnByteBuf()); + + //bindComplete + PGInterfaceMessage bindComplete = new PGInterfaceMessage(PGInterfaceHeaders.TWO, "0", 4, true); + PGInterfaceServerWriter bindCompleteWriter = new PGInterfaceServerWriter("i", bindComplete, ctx); + ctx.writeAndFlush(bindCompleteWriter.writeOnByteBuf()); + */ + + PGInterfaceMessage mockMessage = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, true); + PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter("i", mockMessage, ctx); + headerWriter.writeIntHeaderOnByteBuf('1'); + headerWriter.writeIntHeaderOnByteBuf('2'); + ctx.writeAndFlush(headerWriter); + + } + + public void sendNoData() { + PGInterfaceMessage noData = new PGInterfaceMessage(PGInterfaceHeaders.n, "0", 4, true); + PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter("i", noData, ctx); + ctx.writeAndFlush(noDataWriter.writeOnByteBuf()); + } + + public void sendCommandCompleteInsert(int rowsInserted) { + //send CommandComplete - insert + PGInterfaceMessage insertCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "INSERT" + PGInterfaceMessage.getDelimiter() + "0" + PGInterfaceMessage.getDelimiter() + String.valueOf(rowsInserted), 4, true); + PGInterfaceServerWriter insertCommandCompleteWriter = new PGInterfaceServerWriter("sss", insertCommandComplete, ctx); + ctx.writeAndFlush(insertCommandCompleteWriter); + + } + + public void sendCommandCompleteCreateTable() { + //send CommandComplete - create table + PGInterfaceMessage createTableCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "CREATE TABLE", 4, true); + PGInterfaceServerWriter createTableCommandCompleteWriter = new PGInterfaceServerWriter("s", createTableCommandComplete, ctx); + ctx.writeAndFlush(createTableCommandCompleteWriter); + } + + //for SELECT and CREATE TABLE AS + public void sendCommandCompleteSelect(ArrayList data) { + int rowsSelected = data.size(); + //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) + PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ String.valueOf(rowsSelected), 4, true); + PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("s", selectCommandComplete, ctx); + ctx.writeAndFlush(selectCommandCompleteWriter); + } + + + public void sendRowDescription(String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode) { + + //bytebuf.writeInt(int value) = 32-bit int + //bytebuf.writeShort(int value) = 16-bit short integer; + String body = ""; + PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); + rowDescriptionWriter.writeRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + ctx.writeAndFlush(rowDescriptionWriter); + } + + + public void sendDataRow(ArrayList data) { + /* + DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: (int16) + length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), (int32) + value of the col (in format indicated by associated format code) (string) + + */ + int noCols = data.size(); //number of rows returned --> belongs to rowDescription (?) + String colVal = ""; + int nbrFollowingColVal = 0; //int16 --> length of String[] --> nbr of column values that follow + int colValLength = 0; //int32 --> length of one String[i] (length of actual string) (n) + String body = ""; //Byte*n* --> the string itself String[i] + + Boolean colValIsNull = false; + PGInterfaceMessage dataRow; + PGInterfaceServerWriter dataRowWriter; + + for (int i = 0; i < noCols; i++) { + //can be 0 and -1 (= NULL col val) + nbrFollowingColVal = data.get(i).length; + + //TODO(FF): handle the case if the column value (of the result) is NULL. Bzw. it already sends the correct reply, but you have to figure out wether the colVal is NULL! + if (colValIsNull) { + //colum value is NULL + //dont send any colVal + colValLength = -1; + } + + else { + for (int j = 0; j < nbrFollowingColVal; j++) { + //if colValLength -1 : nothing sent at all + colVal = data.get(i)[j]; + colValLength = colVal.length(); + + //TODO(FF)!!: fählt no § em body... --> was esch eifacher... en body, oder methode?? + //FIXME(FF): scheckich för jede einzelni string en DataRow??? + body = String.valueOf(nbrFollowingColVal) + PGInterfaceMessage.getDelimiter() + String.valueOf(colValLength)+ PGInterfaceMessage.getDelimiter() + colVal; + //body = String.valueOf(nbrFollowingColVal) + String.valueOf(colValLength) + colVal; + dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, 4, true); + dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); + ctx.writeAndFlush(dataRowWriter); + + + //needs to be at the end + nbrFollowingColVal--; + } + } + } + + + } public void terminateConnection() { ctx.close(); } + } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 7310ae43ca..78737aee79 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -23,7 +23,7 @@ public class PGInterfaceMessage { private String msgBody; private int length; //default is 4, if a different length is mentioned in protocol, this is given private boolean defaultLength; - private final char delimiter = '§'; //for the subparts + private static final char delimiter = '§'; //for the subparts public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength) { this.header = header; @@ -112,7 +112,7 @@ public void setMsgBody(String msgBody) { * @return a string array with each requested part */ public String[] getMsgPart(int[] part) { - String subStrings[] = msgBody.split("§"); + String subStrings[] = msgBody.split(getDelimiter()); String result[] = new String[part.length]; for (int i=0; i<(part.length); i++) { @@ -121,4 +121,9 @@ public String[] getMsgPart(int[] part) { return result; } + public static String getDelimiter() { + String del = String.valueOf(delimiter); + return del; + } + } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index a5711878f8..3e55b7d9b0 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -17,30 +17,211 @@ package org.polypheny.db.postgresql; import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang.ArrayUtils; +import org.polypheny.db.PolyResult; +import org.polypheny.db.algebra.AlgRoot; +import org.polypheny.db.algebra.constant.Kind; +import org.polypheny.db.algebra.type.AlgDataTypeField; +import org.polypheny.db.catalog.Catalog; +import org.polypheny.db.catalog.entity.*; +import org.polypheny.db.catalog.exceptions.*; +import org.polypheny.db.config.RuntimeConfig; +import org.polypheny.db.languages.QueryParameters; +import org.polypheny.db.nodes.Node; +import org.polypheny.db.processing.Processor; +import org.polypheny.db.processing.QueryProcessor; +import org.polypheny.db.transaction.*; +import java.util.ArrayList; +import java.util.List; -public class PGInterfaceQueryHandler { +public class PGInterfaceQueryHandler implements TransactionManager { String query; ChannelHandlerContext ctx; + PGInterfaceInboundCommunicationHandler communicationHandler; + private TransactionManager transactionManager; + int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) + List> rows; - public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx) { + public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler) { this.query = query; this.ctx = ctx; + this.communicationHandler = communicationHandler; + Object obj = new Object(); + this.transactionManager = PGInterface.getInstance(); + } + + public void start() { + sendQueryToPolypheny(); + + //is 2 times inside... delete here or in sendQueryToPolypheny + ArrayList data = null; + sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... } public void sendQueryToPolypheny() { String type = ""; //query type according to answer tags //get result from polypheny + Transaction transaction; + Statement statement = null; + PolyResult result; + ArrayList data = new ArrayList<>(); + + + + try { + //get transaction letze linie + transaction = transactionManager.startTransaction("pa", "APP", false, "Index Manager"); + statement = transaction.createStatement(); + } + catch (UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e) { + throw new RuntimeException( "Error while starting transaction", e ); + } + + + + //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) + //for loop zom dor alli catalogTables doregoh? - nei + Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); + Node sqlNode = sqlProcessor.parse(query); + QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); + if ( sqlNode.isA( Kind.DDL ) ) { + result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); + } else { + AlgRoot algRoot = sqlProcessor.translate( + statement, + sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, + new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds (emmer no???) + + //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) + final QueryProcessor processor = statement.getQueryProcessor(); + result = processor.prepareQuery(algRoot, true); + + } + + //get type information - from crud.java + //Type of ArrayList was DbColumn, but belongs to webUI (so I don't need it...) --> replaced it with string? + ArrayList header = new ArrayList<>(); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? + + //get actual result of query in array - from crud.java + rows = result.getRows(statement, -1); //-1 as size valid?? + data = computeResultData(rows, header, statement.getTransaction()); //computeResultData selber implementieren? --> das esch die aagehnigi ziile + //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) //handle result --> depending on query type, prepare answer message accordingly here (flush it) + sendResultToClient(type, data); + + } + + private ArrayList computeResultData(List> rows, ArrayList header, Transaction transaction) { + //ha es paar sache useglöscht... aber wahrschiinli muesmer de no meh lösche... + ArrayList data = new ArrayList<>(); + /* + for ( List row : rows ) { + String[] temp = new String[row.size()]; + int counter = 0; + for ( Object o : row ) { + if ( o == null ) { + temp[counter] = null; + } else { + switch ( header.get( counter ) ) { + case "TIMESTAMP": + break; + case "DATE": + break; + case "TIME": + break; + case "FILE": + case "IMAGE": + case "SOUND": + case "VIDEO": + break; + //fall through + default: + temp[counter] = o.toString(); + } + if ( header.get( counter ).endsWith( "ARRAY" ) ) { + + } + } + counter++; + } + data.add( temp ); + } + + */ + return data; + } + + + public void sendResultToClient(String type, ArrayList data) { switch (type) { case "INSERT": + //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) //INSERT oid rows (oid=0, rows = #rows inserted) //1....2....n....C....INSERT 0 1.Z....I + + //insert into table with several vals (but only 1 row) + /* + client: + P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B............D....P.E... .....S.... + + server: + 1....2....n....C....INSERT 0 1.Z....I + */ + + + communicationHandler.sendParseBindComplete(); + communicationHandler.sendCommandCompleteInsert(rowsAffected); + communicationHandler.sendReadyForQuery("I"); + break; - case "SELECT" : + case "CREATE TABLE": + //1....2....n....C....CREATE TABLE.Z....I + communicationHandler.sendParseBindComplete(); + communicationHandler.sendCommandCompleteCreateTable(); + communicationHandler.sendReadyForQuery("I"); + + break; + + case "SELECT" : //also CREATE TABLE AS + + if (data.isEmpty()) { + //noData + //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) + communicationHandler.sendParseBindComplete(); + communicationHandler.sendReadyForQuery("I"); + } + + else { + //data + + //rowDescription + String fieldName = ""; //get field name from query? + int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 + int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 + int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified + + int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt + //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types + int typeModifier = 0; //int32 --> meaning of modifier is type specific (pg_attribute.atttypmod) + int formatCode = 0; //int16 --> zero(text) or one(binary) --> if returned from describe, not yet known = 0 + + communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + + communicationHandler.sendDataRow(data); + + + + //rowsAffected = 2; //das fonktioniert met 0 ond 2 --> rein das schecke get kei fähler em frontend + communicationHandler.sendCommandCompleteSelect(data); + communicationHandler.sendParseBindComplete(); + communicationHandler.sendReadyForQuery("I"); + } + + //SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) //1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I //1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I @@ -66,6 +247,41 @@ public void sendQueryToPolypheny() { } + @Override + public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin) { + return null; + } + + @Override + public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) { + return null; + } + + @Override + public Transaction startTransaction(String user, String database, boolean analyze, String origin) { + try { + return transactionManager.startTransaction( "pa", "APP", true, "Test Helper" ); + } catch ( GenericCatalogException | UnknownUserException | UnknownDatabaseException | UnknownSchemaException e ) { + throw new RuntimeException( "Error while starting transaction", e ); + } + } + + @Override + public Transaction startTransaction(String user, String database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) throws UnknownUserException, UnknownDatabaseException, UnknownSchemaException { + return null; + } + + @Override + public void removeTransaction(PolyXid xid) { + + } + + @Override + public boolean isActive(PolyXid xid) { + return false; + } + + //Example of server answer to simple select query (from real server) /* 1....2....T......lolid...@...............D..........1D..........2D..........3D..........3D..........3D..........3C... @@ -76,16 +292,24 @@ public void sendQueryToPolypheny() { 2: BindComplete indicator T: RowDescription - specifies the number of fields in a row (can be 0) - then for each field: field name (string), lolid - ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 + ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 --> kompliziert attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 ObjectID of fields data type (Int32), 1 - data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 + + Specifies the object ID of the parameter data type. Placing a zero here is equivalent to leaving the type unspecified. + --> apparently specified in parse message (at the end, if 0, then unspecified...) + + data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 --> polypheny website, typedokumentation, mit länge + real and double in polypheny s gliiche --> luege was postgres macht, mind. länge aaluege --> postgresqlStore schauen welche grössen wie gemappt + gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) + type modifier (meaning of modifier is type-specific) (see pg_attribute.atttypmod) (Int32), 4 + Format code used for the field (zero(text) or one(binary)) --> if rowDescription is returned from statement variant of DESCRIBE: format code not yet known (always zero) (Int16) -D: DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: - length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), - value of the col (in format indicated by associated format code) +D: DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: (int16) + length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), (int32) + value of the col (in format indicated by associated format code) (string)00 C: CommandComplete - msgBody is commandTag (which sql command was completed) SET (not in list on website, but "observed in the wild"), diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index a0d65f6221..188268bdad 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -77,15 +77,17 @@ public ByteBuf writeOnByteBuf() { body = Integer.parseInt(pgMsg.getMsgBody()); } catch (NumberFormatException e) { e.printStackTrace(); - //TODO: send error-message to client + //TODO(FF): send error-message to client } buffer.writeInt(body); break; - case "ss": //write two strings (tag and message) + writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + + /* buffer.writeByte(pgMsg.getHeaderChar()); if (pgMsg.isDefaultLength()) { buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 1); @@ -93,17 +95,70 @@ public ByteBuf writeOnByteBuf() { else { buffer.writeInt(pgMsg.getLength()); } - int[] idx = new int[]{0,1}; - String[] msgParts = pgMsg.getMsgPart(idx); + int[] twoPartsIdx = new int[]{0,1}; + String[] msgParts = pgMsg.getMsgPart(twoPartsIdx); buffer.writeBytes(msgParts[0].getBytes(StandardCharsets.US_ASCII)); buffer.writeByte(0); buffer.writeBytes(msgParts[1].getBytes(StandardCharsets.US_ASCII)); buffer.writeByte(0); + + */ + break; + + + case "sss": + //write 3 strings, example, tag with three components + writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + /* + buffer.writeByte(pgMsg.getHeaderChar()); + if (pgMsg.isDefaultLength()) { + buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 2); + } + else { + buffer.writeInt(pgMsg.getLength()); + } + int[] threePartsIdx = new int[]{0,1,2}; + String[] threeMsgParts = pgMsg.getMsgPart(threePartsIdx); + buffer.writeBytes(threeMsgParts[0].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + buffer.writeBytes(threeMsgParts[1].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + buffer.writeBytes(threeMsgParts[2].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + + */ break; + case "ssm": + //several strings modified --> ideally only use this in the future... + break; + + case "dr": + //send dataRow + buffer.writeByte(pgMsg.getHeaderChar()); + + int[] idxDataRow = new int[3]; + String[] dataRows = pgMsg.getMsgPart(idxDataRow); + + int nbrFollowingColVal = 0; + int colValLenght = 0; + try { + nbrFollowingColVal = Integer.parseInt(dataRows[0]); + colValLenght = Integer.parseInt(dataRows[1]); + } catch (NumberFormatException e) { + e.printStackTrace(); + //TODO(FF): send error-message to client + } + + //dont check for length, bcs is always the same for dataRow + buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 2); + + buffer.writeShort(nbrFollowingColVal); + buffer.writeByte(0); + buffer.writeInt(colValLenght); + buffer.writeByte(0); + buffer.writeBytes(dataRows[2].getBytes(StandardCharsets.UTF_8)); - case "cc": - //two chars? break; @@ -111,4 +166,64 @@ public ByteBuf writeOnByteBuf() { return buffer; } + public ByteBuf writeSeveralStrings(int nbrStrings) { + ByteBuf buffer = ctx.alloc().buffer(); + + buffer.writeByte(pgMsg.getHeaderChar()); + if (pgMsg.isDefaultLength()) { + buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - (nbrStrings -1)); + } + else { + buffer.writeInt(pgMsg.getLength()); + } + + int[] idx = new int[nbrStrings]; + String[] msgParts = pgMsg.getMsgPart(idx); + + for (int i = 0; i < nbrStrings; i++) { + buffer.writeBytes(msgParts[i].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + } + + return buffer; + } + + public ByteBuf writeIntHeaderOnByteBuf(char header) { + //write a int header... ("i" (for char headers) doesn't work TODO(FF): Figure out a way to do this with case "i" + //since headers with numbers are always indicators, don't I don't check for not standard lengths + ByteBuf buffer = ctx.alloc().buffer(); + + buffer.writeByte(header); + buffer.writeInt(4); // size excluding char + + return buffer; + } + + public ByteBuf writeRowDescription(String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode) { + //I don't check for length, bcs rowDescription is always the same + ByteBuf buffer = ctx.alloc().buffer(); + + //bytebuf.writeInt(int value) = 32-bit int + //bytebuf.writeShort(int value) = 16-bit short integer; + + buffer.writeByte(pgMsg.getHeaderChar()); + buffer.writeInt(pgMsg.getLength() + fieldName.length() + 6); + + buffer.writeBytes(fieldName.getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + buffer.writeInt(objectIDTable); + buffer.writeByte(0); + buffer.writeShort(attributeNoCol); + buffer.writeByte(0); + buffer.writeInt(objectIDCol); + buffer.writeByte(0); + buffer.writeShort(dataTypeSize); + buffer.writeByte(0); + buffer.writeInt(typeModifier); + buffer.writeByte(0); + buffer.writeShort(formatCode); + + return buffer; + } + } From 3b16782ab88685c451470a531751efd1910c98a7 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 22 Sep 2022 13:26:59 +0200 Subject: [PATCH 06/57] now it works again as far as implemented should (still not works as a whole). Exception on startup remains --- .../polypheny/db/postgresql/PGInterface.java | 6 +-- ...GInterfaceInboundCommunicationHandler.java | 12 ++--- .../postgresql/PGInterfaceQueryHandler.java | 41 ++---------------- .../postgresql/PGInterfaceServerHandler.java | Bin 5247 -> 5362 bytes .../postgresql/PGInterfaceServerWriter.java | 4 +- 5 files changed, 14 insertions(+), 49 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 9d1f74e661..3acdba9799 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -91,10 +91,6 @@ public PGInterface(TransactionManager transactionManager, Authenticator authenti this.transactionManager = transactionManager; } - public static TransactionManager getInstance() { - return transactionManager; - } //getTransactionManager - @Override public void run() { @@ -124,7 +120,7 @@ public void initChannel(SocketChannel socketChannel) throws Exception { //channelPipeline.addLast("encoder", new StringEncoder()); //Handler - channelPipeline.addLast("handler", new PGInterfaceServerHandler()); + channelPipeline.addLast("handler", new PGInterfaceServerHandler(transactionManager)); //channelPipeline.addLast("handler2", new ServerHandler2()); //channelPipeline.addLast("handler", new ServerHandler3()); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 91160be3a9..e315f5b6b1 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -18,6 +18,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; +import org.polypheny.db.transaction.TransactionManager; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -26,11 +27,13 @@ public class PGInterfaceInboundCommunicationHandler { String type; PGInterfaceClient client; ChannelHandlerContext ctx; + TransactionManager transactionManager; - public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client) { + public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client, TransactionManager transactionManager) { this.type = type; this.client = client; this.ctx = client.getCtx(); + this.transactionManager = transactionManager; } //ich mues ergendwie identifiziere wele client dases esch... oder muesich öberhaupt speichere was fören phase das de client denne esch... @@ -42,8 +45,6 @@ public String decideCycle(Object oMsg) { String msgWithZeroBits = ((String) oMsg); String wholeMsg = msgWithZeroBits.replace("\u0000", ""); - - switch (wholeMsg.substring(0, 1)) { case "C": PGInterfaceMessage msg = null; @@ -71,7 +72,8 @@ public void startUpPhase() { ctx.writeAndFlush(authenticationOkWriter.writeOnByteBuf()); //server_version (Parameter Status message) - PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version§14", 4, true); + //PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter("ss", parameterStatusServerVs, ctx); ctx.writeAndFlush(parameterStatusServerVsWriter.writeOnByteBuf()); @@ -99,7 +101,7 @@ public void extendedQueryPhase(String incomingMsg) { else { //Query does not have ";" at the end!! String query = extractQuery(incomingMsg); - PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this); + PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this, transactionManager); queryHandler.start(); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 3e55b7d9b0..24cc5caf49 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -34,7 +34,7 @@ import java.util.ArrayList; import java.util.List; -public class PGInterfaceQueryHandler implements TransactionManager { +public class PGInterfaceQueryHandler{ String query; ChannelHandlerContext ctx; PGInterfaceInboundCommunicationHandler communicationHandler; @@ -42,12 +42,12 @@ public class PGInterfaceQueryHandler implements TransactionManager { int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) List> rows; - public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler) { + public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager) { this.query = query; this.ctx = ctx; this.communicationHandler = communicationHandler; Object obj = new Object(); - this.transactionManager = PGInterface.getInstance(); + this.transactionManager = transactionManager; } public void start() { @@ -86,6 +86,7 @@ public void sendQueryToPolypheny() { QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); if ( sqlNode.isA( Kind.DDL ) ) { result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); + // exception: java.lang.RuntimeException: No primary key has been provided! } else { AlgRoot algRoot = sqlProcessor.translate( statement, @@ -247,40 +248,6 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... } - @Override - public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin) { - return null; - } - - @Override - public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) { - return null; - } - - @Override - public Transaction startTransaction(String user, String database, boolean analyze, String origin) { - try { - return transactionManager.startTransaction( "pa", "APP", true, "Test Helper" ); - } catch ( GenericCatalogException | UnknownUserException | UnknownDatabaseException | UnknownSchemaException e ) { - throw new RuntimeException( "Error while starting transaction", e ); - } - } - - @Override - public Transaction startTransaction(String user, String database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) throws UnknownUserException, UnknownDatabaseException, UnknownSchemaException { - return null; - } - - @Override - public void removeTransaction(PolyXid xid) { - - } - - @Override - public boolean isActive(PolyXid xid) { - return false; - } - //Example of server answer to simple select query (from real server) /* diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index c828421d620b6601b6bb2b4c5763d7548b28564e..47ee50a5849bb6da2f3b4dcce1973f50881795ac 100644 GIT binary patch delta 256 zcmeyb@kw*TRHn(-m}<;2a|`l|N)+;o()9}Rb1DlmQu8YHQj+vaiW2jR6O&6a^YipV z5NzMXyu|d>qRI1^LyRzm6_9j6Ra$d#DF8u1X;MyR^5nJ5lJOcu>C;rG25SUqF3HF& gMs^U?Xa!qr_D%K|R@=dtmUP@w7 XiZg^?JlUN&WOE=(3+v{WoSfVMC3`re diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 188268bdad..f70c7a0736 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -85,7 +85,7 @@ public ByteBuf writeOnByteBuf() { case "ss": //write two strings (tag and message) - writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + buffer = writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution (switch case(?))?? /* buffer.writeByte(pgMsg.getHeaderChar()); @@ -108,7 +108,7 @@ public ByteBuf writeOnByteBuf() { case "sss": //write 3 strings, example, tag with three components - writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + buffer = writeSeveralStrings(3); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? /* buffer.writeByte(pgMsg.getHeaderChar()); if (pgMsg.isDefaultLength()) { From 345004f6fe1d81128a6fc1ff95c4f6eceeadc7f4 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 28 Sep 2022 10:56:35 +0200 Subject: [PATCH 07/57] data from Polypheny is handled, and ready to be sent to the client, but not yet sent correctly to the client --- ...GInterfaceInboundCommunicationHandler.java | 18 +- .../postgresql/PGInterfaceQueryHandler.java | 205 +++++++++++++++--- 2 files changed, 185 insertions(+), 38 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index e315f5b6b1..751dfb3411 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -201,14 +201,24 @@ public void sendCommandCompleteSelect(ArrayList data) { } - public void sendRowDescription(String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode) { + + + public void sendRowDescription(int numberOfFields, ArrayList valuesPerCol) { + //String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode //bytebuf.writeInt(int value) = 32-bit int //bytebuf.writeShort(int value) = 16-bit short integer; - String body = ""; + ByteBuf test = ctx.alloc().buffer(); + String body = String.valueOf(numberOfFields); PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); - rowDescriptionWriter.writeRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + + for(Object[] oneCol : valuesPerCol) { + test = rowDescriptionWriter.writeRowDescription(oneCol[0].toString(), (Integer) oneCol[1], (Integer) oneCol[2], (Integer) oneCol[3], (Integer) oneCol[4], (Integer) oneCol[5], (Integer) oneCol[6]); + ctx.writeAndFlush(test); + } + //rowDescriptionWriter.writeRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + //ctx.writeAndFlush(test); ctx.writeAndFlush(rowDescriptionWriter); } @@ -269,6 +279,4 @@ public void terminateConnection() { ctx.close(); } - - } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 24cc5caf49..456704151e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -31,6 +31,8 @@ import org.polypheny.db.processing.Processor; import org.polypheny.db.processing.QueryProcessor; import org.polypheny.db.transaction.*; + +import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.List; @@ -54,8 +56,9 @@ public void start() { sendQueryToPolypheny(); //is 2 times inside... delete here or in sendQueryToPolypheny - ArrayList data = null; - sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... + //ArrayList data = null; //chonnt vo sendQueryToPolypheny zrogg, ond goht etzt es insert ine... aber + //aber ebe, esch dopplet wie onde + //sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... } public void sendQueryToPolypheny() { @@ -65,6 +68,7 @@ public void sendQueryToPolypheny() { Statement statement = null; PolyResult result; ArrayList data = new ArrayList<>(); + ArrayList header = new ArrayList<>(); @@ -91,7 +95,7 @@ public void sendQueryToPolypheny() { AlgRoot algRoot = sqlProcessor.translate( statement, sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, - new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds (emmer no???) + new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds: org.polypheny.db.runtime.PolyphenyDbContextException: From line 1, column 13 to line 1, column 15: Table 'lol' not found //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) final QueryProcessor processor = statement.getQueryProcessor(); @@ -101,32 +105,105 @@ public void sendQueryToPolypheny() { //get type information - from crud.java //Type of ArrayList was DbColumn, but belongs to webUI (so I don't need it...) --> replaced it with string? - ArrayList header = new ArrayList<>(); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? + //ArrayList header = getHeader(result, query); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? + header = getHeader(result); + //statement.executeUpdate("SELECT empid FROM public.emps"); //get actual result of query in array - from crud.java rows = result.getRows(statement, -1); //-1 as size valid?? - data = computeResultData(rows, header, statement.getTransaction()); //computeResultData selber implementieren? --> das esch die aagehnigi ziile + data = computeResultData(rows, header); //, statement.getTransaction() + //type = result.getStatementType().name(); + type = result.getStatementType().toString(); //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) //handle result --> depending on query type, prepare answer message accordingly here (flush it) - sendResultToClient(type, data); + sendResultToClient(type, data, header); + + } + + /** + * gets the information for the header + * @param result the polyresult the additional information is needed + * @return a list with array, where: + * - array[0] = columnName + * - array[1] = columnType + */ + private ArrayList getHeader(PolyResult result) { //(request = query) + ArrayList header = new ArrayList<>(); + for ( AlgDataTypeField metaData : result.getRowType().getFieldList() ) { + String columnName = metaData.getName(); + //final String name = metaData.getName(); + String dataType = metaData.getType().getPolyType().getTypeName(); //INTEGER, VARCHAR --> aber ergendwie ohnis (20) em header?? + int precision = metaData.getType().getPrecision(); //sizeVarChar + boolean nullable = metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1); + //Integer precision = metaData.getType().getPrecision(); + + //For each column: If it should be filtered empty string if it should not be filtered + /* + String filter = ""; + if ( request.filter != null && request.filter.containsKey( columnName ) ) { + filter = request.filter.get( columnName ); + } + */ + + //For each column: If and how it should be sorted + /* + SortState sort; + if ( request.sortState != null && request.sortState.containsKey( columnName ) ) { + sort = request.sortState.get( columnName ); + } else { + sort = new SortState(); + } + */ + + /* + DbColumn dbCol = new DbColumn( + metaData.getName(), + metaData.getType().getPolyType().getTypeName(), + metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1), + metaData.getType().getPrecision(), + sort, + filter ); + */ + + //bruuch ich ned wörklech? + /* + // Get column default values + if ( catalogTable != null ) { + try { + if ( catalog.checkIfExistsColumn( catalogTable.id, columnName ) ) { + CatalogColumn catalogColumn = catalog.getColumn( catalogTable.id, columnName ); + if ( catalogColumn.defaultValue != null ) { + dbCol.defaultValue = catalogColumn.defaultValue.value; + } + } + } catch ( UnknownColumnException e ) { + log.error( "Caught exception", e ); + } + } + */ + //header.add( dbCol ); + header.add(new String[]{columnName, dataType, String.valueOf(precision)}); + } + return header; } - private ArrayList computeResultData(List> rows, ArrayList header, Transaction transaction) { + private ArrayList computeResultData(List> rows, ArrayList header) { + //TODO(FF): bruuch ich de header do öberhaupt? (aso em momänt ned... ) --> hanich sache wonich de chönnt/müesst bruuche? //ha es paar sache useglöscht... aber wahrschiinli muesmer de no meh lösche... ArrayList data = new ArrayList<>(); - /* + for ( List row : rows ) { - String[] temp = new String[row.size()]; + String[] temp = new String[row.size()]; //temp esch au 100 --> vo resultat sälber... int counter = 0; for ( Object o : row ) { if ( o == null ) { temp[counter] = null; } else { - switch ( header.get( counter ) ) { + switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry case "TIMESTAMP": break; case "DATE": @@ -140,23 +217,23 @@ private ArrayList computeResultData(List> rows, ArrayList break; //fall through default: - temp[counter] = o.toString(); + temp[counter] = o.toString(); //em momänt werd do no 100 aaghänkt?? --> s 1. resultat vo rows } - if ( header.get( counter ).endsWith( "ARRAY" ) ) { + if ( header.get( counter )[0].endsWith( "ARRAY" ) ) { } } - counter++; + counter++; //was macht gnau de counter? (esch etzt 1, chonnt add), rows size = 4 } data.add( temp ); } - */ + return data; } - public void sendResultToClient(String type, ArrayList data) { + public void sendResultToClient(String type, ArrayList data, ArrayList header) { switch (type) { case "INSERT": //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) @@ -180,6 +257,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "CREATE TABLE": + //TODO(FF) do things in polypheny (?) //1....2....n....C....CREATE TABLE.Z....I communicationHandler.sendParseBindComplete(); communicationHandler.sendCommandCompleteCreateTable(); @@ -188,8 +266,23 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "SELECT" : //also CREATE TABLE AS - - if (data.isEmpty()) { + int lol = 4; + ArrayList valuesPerCol = new ArrayList(); + + String fieldName = ""; //get field name from query? momentan no de einzig val em header o + int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 o + int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 o + int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified o + int formatCode = 0; //int16 --> zero(text-inhalt (values)) or one(integer) --> if returned from describe, not yet known = 0 o. + int typeModifier = -1; //The value will generally be -1 for types that do not need atttypmod. --> type specific data (supplied at table creation time o + + int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt + //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types + //For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative + // o. + + + if (lol == 3) { //data.isEmpty() //noData //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) communicationHandler.sendParseBindComplete(); @@ -198,24 +291,64 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... else { //data - - //rowDescription - String fieldName = ""; //get field name from query? - int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 - int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 - int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified - - int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt - //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types - int typeModifier = 0; //int32 --> meaning of modifier is type specific (pg_attribute.atttypmod) - int formatCode = 0; //int16 --> zero(text) or one(binary) --> if returned from describe, not yet known = 0 - - communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); - + //for loop mache för jedi reihe? --> nocheluege wies gmacht werd em ächte psql met mehrere cols & reihe + int numberOfFields = header.size(); + + for (String[] head : header) { + + fieldName = head[0]; + + //TODO(FF): Implement the rest of the cases + switch (head[1]) { + case "BIGINT": + case "DOUBLE": + dataTypeSize = 8; //8 bytes signed + formatCode = 1; //TODO(FF): esch das rechtig? wel es heisst e de doc darstellig vo Integer... + break; + case "BOOLEAN": + dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? + break; + case "DATE": + break; + case "DECIMAL": + break; + case "REAL": + case "INTEGER": + dataTypeSize = 4; + formatCode = 1; + break; + case "VARCHAR": + dataTypeSize = Integer.parseInt(head[2]); + formatCode = 0; + break; + case "SMALLINT": + dataTypeSize = 2; + formatCode = 1; + break; + case "TINYINT": + dataTypeSize = 1; + formatCode = 1; + break; + case "TIMESTAMP": + break; + case "TIME": + break; + case "FILE": + case "IMAGE": + case "SOUND": + case "VIDEO": + break; + } + //rowDescription + //communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + Object col[] = {fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode}; + valuesPerCol.add(col); + } + communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); + //sendData communicationHandler.sendDataRow(data); - //rowsAffected = 2; //das fonktioniert met 0 ond 2 --> rein das schecke get kei fähler em frontend communicationHandler.sendCommandCompleteSelect(data); communicationHandler.sendParseBindComplete(); @@ -257,7 +390,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... (result: 1,2,3,3,3,3) 1: ParseComplete indicator 2: BindComplete indicator -T: RowDescription - specifies the number of fields in a row (can be 0) - then for each field: +T: RowDescription - specifies the number of fields in a row (can be 0) (as message content!!) - then for each field: field name (string), lolid ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 --> kompliziert attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 @@ -307,6 +440,10 @@ COPY rows (rows = #rows copied --> only on PSQL 8.2 and later) For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative. -1 indicates a “varlena” type (one that has a length word), -2 indicates a null-terminated C string. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +1....2....T...S..albumid...@...............title...@...............artistid...@...............D..........1....Hello....1D..........2....Hello....2D..........3....lol....3C...SELECT 3.Z....I +1....2....T...S..albumid...@...............title...@...............artistid...@...............D..........1....Hello....1D..........2....Hello....2D..........3....lol....3C...SELECT 3.Z....I + --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- insert: @@ -316,5 +453,7 @@ COPY rows (rows = #rows copied --> only on PSQL 8.2 and later) n: noData indicator C: CommandComplete + + */ } From 4f42c132c81176f6d4e5de70a66ad1c37b11ff9b Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 29 Sep 2022 17:45:36 +0200 Subject: [PATCH 08/57] answer should now be sent correctly (it is not, but want to commit before debugging) --- ...GInterfaceInboundCommunicationHandler.java | 47 +++++++++---------- .../postgresql/PGInterfaceQueryHandler.java | 23 ++++----- .../postgresql/PGInterfaceServerWriter.java | 39 ++++++++------- 3 files changed, 51 insertions(+), 58 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 751dfb3411..ee0adeca79 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -171,6 +171,7 @@ public void sendParseBindComplete() { } public void sendNoData() { + //TODO(FF) wenn gnau esch das öberhaupt nötig? Wenn de client kei date scheckt --> aber wenn esch das es problem? PGInterfaceMessage noData = new PGInterfaceMessage(PGInterfaceHeaders.n, "0", 4, true); PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter("i", noData, ctx); ctx.writeAndFlush(noDataWriter.writeOnByteBuf()); @@ -192,8 +193,7 @@ public void sendCommandCompleteCreateTable() { } //for SELECT and CREATE TABLE AS - public void sendCommandCompleteSelect(ArrayList data) { - int rowsSelected = data.size(); + public void sendCommandCompleteSelect(int rowsSelected) { //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ String.valueOf(rowsSelected), 4, true); PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("s", selectCommandComplete, ctx); @@ -232,44 +232,39 @@ value of the col (in format indicated by associated format code) (string) */ int noCols = data.size(); //number of rows returned --> belongs to rowDescription (?) String colVal = ""; - int nbrFollowingColVal = 0; //int16 --> length of String[] --> nbr of column values that follow + int nbrFollowingColVal = data.get(0).length; //int16 --> length of String[] --> nbr of column values that follow int colValLength = 0; //int32 --> length of one String[i] (length of actual string) (n) String body = ""; //Byte*n* --> the string itself String[i] - Boolean colValIsNull = false; PGInterfaceMessage dataRow; PGInterfaceServerWriter dataRowWriter; for (int i = 0; i < noCols; i++) { //can be 0 and -1 (= NULL col val) - nbrFollowingColVal = data.get(i).length; - //TODO(FF): handle the case if the column value (of the result) is NULL. Bzw. it already sends the correct reply, but you have to figure out wether the colVal is NULL! - if (colValIsNull) { - //colum value is NULL - //dont send any colVal - colValLength = -1; - } - - else { - for (int j = 0; j < nbrFollowingColVal; j++) { - //if colValLength -1 : nothing sent at all - colVal = data.get(i)[j]; - colValLength = colVal.length(); + for (int j = 0; j < nbrFollowingColVal; j++) { - //TODO(FF)!!: fählt no § em body... --> was esch eifacher... en body, oder methode?? - //FIXME(FF): scheckich för jede einzelni string en DataRow??? - body = String.valueOf(nbrFollowingColVal) + PGInterfaceMessage.getDelimiter() + String.valueOf(colValLength)+ PGInterfaceMessage.getDelimiter() + colVal; - //body = String.valueOf(nbrFollowingColVal) + String.valueOf(colValLength) + colVal; - dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, 4, true); - dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); - ctx.writeAndFlush(dataRowWriter); + //if colValLength -1 : nothing sent at all + colVal = data.get(i)[j]; + //TODO(FF): How is null safed in polypheny exactly?? is it correctly checked? + if (colVal == "NULL") { + colValLength = -1; + //scheck kei body + break; + } - //needs to be at the end - nbrFollowingColVal--; + else { + colValLength += colVal.length(); + body += colVal.length() + PGInterfaceMessage.getDelimiter() + colVal + PGInterfaceMessage.getDelimiter(); //TODO(FF): + PGInterfaceMessage.getDelimiter()?? + //body += colVal + PGInterfaceMessage.getDelimiter(); //TODO(FF): + PGInterfaceMessage.getDelimiter()?? } } + //TODO(FF): do mues ergendöppis falsch laufe... wels eif gar nüt usescheckt... (doer denn halt bem server writer) + dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, colValLength, false); + dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); + ctx.writeAndFlush(dataRowWriter); + body = ""; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 456704151e..8ebf1bbad1 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -54,11 +54,6 @@ public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInter public void start() { sendQueryToPolypheny(); - - //is 2 times inside... delete here or in sendQueryToPolypheny - //ArrayList data = null; //chonnt vo sendQueryToPolypheny zrogg, ond goht etzt es insert ine... aber - //aber ebe, esch dopplet wie onde - //sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... } public void sendQueryToPolypheny() { @@ -86,16 +81,17 @@ public void sendQueryToPolypheny() { //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) //for loop zom dor alli catalogTables doregoh? - nei Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); - Node sqlNode = sqlProcessor.parse(query); + Node sqlNode = sqlProcessor.parse(query); //go gehts fähler: (see diary) QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); if ( sqlNode.isA( Kind.DDL ) ) { result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); + //TODO(FF): ene try catch block... || evtl no committe (söscht werds ned aazeigt em ui (aso allgemein, wie werds denn aazeigt em ui?) // exception: java.lang.RuntimeException: No primary key has been provided! } else { AlgRoot algRoot = sqlProcessor.translate( statement, sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, - new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds: org.polypheny.db.runtime.PolyphenyDbContextException: From line 1, column 13 to line 1, column 15: Table 'lol' not found + new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) final QueryProcessor processor = statement.getQueryProcessor(); @@ -203,7 +199,7 @@ private ArrayList computeResultData(List> rows, ArrayList if ( o == null ) { temp[counter] = null; } else { - switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry + switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry (only handling "standard" returns case "TIMESTAMP": break; case "DATE": @@ -217,7 +213,7 @@ private ArrayList computeResultData(List> rows, ArrayList break; //fall through default: - temp[counter] = o.toString(); //em momänt werd do no 100 aaghänkt?? --> s 1. resultat vo rows + temp[counter] = o.toString(); } if ( header.get( counter )[0].endsWith( "ARRAY" ) ) { @@ -282,7 +278,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... // o. - if (lol == 3) { //data.isEmpty() + if (lol == 3) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... //noData //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) communicationHandler.sendParseBindComplete(); @@ -318,7 +314,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... formatCode = 1; break; case "VARCHAR": - dataTypeSize = Integer.parseInt(head[2]); + dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize formatCode = 0; break; case "SMALLINT": @@ -348,9 +344,8 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... //sendData communicationHandler.sendDataRow(data); - - //rowsAffected = 2; //das fonktioniert met 0 ond 2 --> rein das schecke get kei fähler em frontend - communicationHandler.sendCommandCompleteSelect(data); + rowsAffected = data.size(); + communicationHandler.sendCommandCompleteSelect(rowsAffected); communicationHandler.sendParseBindComplete(); communicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index f70c7a0736..d39fffb20f 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -137,31 +137,34 @@ public ByteBuf writeOnByteBuf() { //send dataRow buffer.writeByte(pgMsg.getHeaderChar()); - int[] idxDataRow = new int[3]; - String[] dataRows = pgMsg.getMsgPart(idxDataRow); + int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("g","").length())/2; - int nbrFollowingColVal = 0; - int colValLenght = 0; - try { - nbrFollowingColVal = Integer.parseInt(dataRows[0]); - colValLenght = Integer.parseInt(dataRows[1]); - } catch (NumberFormatException e) { - e.printStackTrace(); - //TODO(FF): send error-message to client + //should generally be not the default length, but also works with default length & length = 4 + if (pgMsg.isDefaultLength()) { + //data row does not include msg-length bytes in msg length + buffer.writeInt(pgMsg.getLength()- 4 - (nbrCol*2)); + } + else { + buffer.writeInt(pgMsg.getLength()); } - //dont check for length, bcs is always the same for dataRow - buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 2); + buffer.writeShort(nbrCol); - buffer.writeShort(nbrFollowingColVal); - buffer.writeByte(0); - buffer.writeInt(colValLenght); - buffer.writeByte(0); - buffer.writeBytes(dataRows[2].getBytes(StandardCharsets.UTF_8)); + //cut the last § (it is at the end) from the msgBody and set it as the new msgBody + String temp = pgMsg.getMsgBody().substring(0, pgMsg.getMsgBody().length() - 1); + pgMsg.setMsgBody(temp); - break; + int[] idx = new int[(nbrCol*2)]; + String[] msgParts = pgMsg.getMsgPart(idx); + for (int i = 0; i < (nbrCol*2); i++) { + buffer.writeInt(Integer.parseInt(msgParts[i])); + buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + i++; + } + break; } return buffer; } From bfe75650fb37692893d31fa9263f14a7d91d9af7 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 29 Sep 2022 18:08:24 +0200 Subject: [PATCH 09/57] it now sends the message correctly(?), but doesnt close the connection... --- .../PGInterfaceInboundCommunicationHandler.java | 8 +++----- .../polypheny/db/postgresql/PGInterfaceServerWriter.java | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index ee0adeca79..ca7a2b6322 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -256,14 +256,12 @@ value of the col (in format indicated by associated format code) (string) else { colValLength += colVal.length(); - body += colVal.length() + PGInterfaceMessage.getDelimiter() + colVal + PGInterfaceMessage.getDelimiter(); //TODO(FF): + PGInterfaceMessage.getDelimiter()?? - //body += colVal + PGInterfaceMessage.getDelimiter(); //TODO(FF): + PGInterfaceMessage.getDelimiter()?? + body += colVal.length() + PGInterfaceMessage.getDelimiter() + colVal + PGInterfaceMessage.getDelimiter(); } } - //TODO(FF): do mues ergendöppis falsch laufe... wels eif gar nüt usescheckt... (doer denn halt bem server writer) dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, colValLength, false); - dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); - ctx.writeAndFlush(dataRowWriter); + dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); //TODO(FF): Das werd nie uufgrüeft?? werom au emmer + ctx.writeAndFlush(dataRowWriter.writeOnByteBuf()); body = ""; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index d39fffb20f..cfe4d5782e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -137,7 +137,7 @@ public ByteBuf writeOnByteBuf() { //send dataRow buffer.writeByte(pgMsg.getHeaderChar()); - int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("g","").length())/2; + int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("§","").length())/2; //should generally be not the default length, but also works with default length & length = 4 if (pgMsg.isDefaultLength()) { From ce9c4c8db53e98bfbafae64b6da45314a0ddc87a Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 5 Oct 2022 08:55:49 +0200 Subject: [PATCH 10/57] some code cleanup and fixes, but the client still doesn't accept the select response --- .../org/polypheny/db/postgresql/Decoder.java | 73 ------------------- .../db/postgresql/PGInterfaceClient.java | 43 ----------- .../PGInterfaceHeaderPrepender.java | 38 ---------- .../db/postgresql/PGInterfaceServer.java | 20 ----- .../postgresql/PGInterfaceServerReader.java | 30 -------- 5 files changed, 204 deletions(-) delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java deleted file mode 100644 index e841c88663..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.polypheny.db.postgresql; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.polypheny.db.StatusService; - -import java.util.List; - -public class Decoder extends LengthFieldBasedFrameDecoder { - - private static final int HEADER_SIZE = 1; - private byte type; - private int length; - private String msgBody; - private ChannelHandlerContext ctx; - private ByteBuf in; - private List out; - - - public Decoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) throws Exception { - super(maxFrameLength, lengthFieldOffset, lengthFieldLength, - lengthAdjustment, initialBytesToStrip); - Object decoded = decode(ctx, in); - ctx.write(decoded); - } - - - /* - @Override - protected void decode (ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - this.ctx = ctx; - this.in = in; - Object decoded = decode(ctx, in); - if (decoded != null) { - out.add(decoded); - } - - } - - @Override - protected Object decode (ChannelHandlerContext ctx, ByteBuf in) throws Exception { - if (in == null) { - return null; - } - if (in.readableBytes() < HEADER_SIZE) { - throw new Exception("Only Header"); - } - - - type = in.readByte(); - length = in.readByte(); - - if(in.readableBytes() < length) { - //throw new Exception("The message is too short"); - } - - ByteBuf buf = in.readBytes(length); - byte[] b = new byte[buf.readableBytes()]; - buf.readBytes(b); - - msgBody = new String(b, "UTF-8"); - Message msg = new Message(type, length, msgBody); - - //StatusService.printInfo(String.format("decoded message:" + msgBody)); - - return msg; - - - } - - */ -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java deleted file mode 100644 index abe97739a5..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -import io.netty.channel.ChannelHandlerContext; - -import java.net.InetSocketAddress; - -public class PGInterfaceClient { - public static ChannelHandlerContext ctx = null; - public String state; - - public PGInterfaceClient (ChannelHandlerContext ctx) { - this.ctx = ctx; - //int port = ((InetSocketAddress)ctx.channel().remoteAddress()).getPort(); - } - - public static ChannelHandlerContext getCtx() { - return ctx; - } - - public void setState(String state) { - this.state = state; - } - - public String getState() { - return state; - } -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java deleted file mode 100644 index a0ce4b5b25..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; - -import java.nio.charset.StandardCharsets; - -public class PGInterfaceHeaderPrepender extends MessageToByteEncoder { - String header = "R"; //Authentication request header - //public HeaderPrepender() { } - - @Override - protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { - ByteBuf headerBuf = Unpooled.copiedBuffer(header.getBytes(StandardCharsets.UTF_8)); - out.writeBytes(headerBuf); - //out.writeBytes(msg); - } - - -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java deleted file mode 100644 index 9f0dfd646e..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -public class PGInterfaceServer { -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java deleted file mode 100644 index 5aabc4937f..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -public class PGInterfaceServerReader { - - public PGInterfaceServerReader(String wholeMsg, PGInterfaceServer server) { - - switch (wholeMsg.substring(0, 1)) { - case "C": - PGInterfaceMessage msg = null; - msg.setHeader(PGInterfaceHeaders.C); - //msg.setMsgBody(); - } - } -} From 975fef089effd381fea38cde3f8cb19efd9df57a Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 5 Oct 2022 08:56:58 +0200 Subject: [PATCH 11/57] forgot to add in the commit before (missed the deleted files) --- .../polypheny/db/postgresql/PGInterface.java | 15 +--- ...GInterfaceInboundCommunicationHandler.java | 61 +++++++++------- .../postgresql/PGInterfaceQueryHandler.java | 3 +- .../postgresql/PGInterfaceServerHandler.java | Bin 5362 -> 4324 bytes .../postgresql/PGInterfaceServerWriter.java | 66 +++++++++++++----- 5 files changed, 87 insertions(+), 58 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 3acdba9799..31c907ea3e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -94,7 +94,6 @@ public PGInterface(TransactionManager transactionManager, Authenticator authenti @Override public void run() { - //ToDo: Instantiate Server (open port...) try { ServerBootstrap serverBootstrap = new ServerBootstrap(); @@ -106,23 +105,11 @@ public void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline channelPipeline = socketChannel.pipeline(); //Inbound - //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, Integer.MAX_VALUE, 1, 4, -4, 0, true)); - //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 1, 4, -4, 0)); - //channelPipeline.addLast("DecoderText", new Decoder(Integer.MAX_VALUE, 1, 4, -4, 0)); - //channelPipeline.addLast("headerdecoder", new StringDecoder()); channelPipeline.addLast("decoder", new StringDecoder()); - - //Outbound - // only accepts bytebuf - //channelPipeline.addLast("frameEncoder", new LengthFieldPrepender(4, true)); - //channelPipeline.addLast("headerPrepender", new HeaderPrepender()); - //channelPipeline.addLast("encoder", new StringEncoder()); - //Handler channelPipeline.addLast("handler", new PGInterfaceServerHandler(transactionManager)); - //channelPipeline.addLast("handler2", new ServerHandler2()); - //channelPipeline.addLast("handler", new ServerHandler3()); + } }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index ca7a2b6322..233098426e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -23,30 +23,33 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; +/** + * Manages all incoming communication, not using the netty framework + */ public class PGInterfaceInboundCommunicationHandler { String type; - PGInterfaceClient client; ChannelHandlerContext ctx; TransactionManager transactionManager; - public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client, TransactionManager transactionManager) { + public PGInterfaceInboundCommunicationHandler (String type, ChannelHandlerContext ctx, TransactionManager transactionManager) { this.type = type; - this.client = client; - this.ctx = client.getCtx(); + this.ctx = ctx; this.transactionManager = transactionManager; } - //ich mues ergendwie identifiziere wele client dases esch... oder muesich öberhaupt speichere was fören phase das de client denne esch... - //muesich das wörklech oder esches eidütig vom protokoll här? --> has gfühl chas eidütig metem protokoll handle - - public String decideCycle(Object oMsg) { - String cycleState = ""; + /** + * Decides in what cycle from postgres the client is (startup-phase, query-phase, etc.) + * @param oMsg the incoming message from the client (unchanged) + * @return + */ + public void decideCycle(Object oMsg) { String msgWithZeroBits = ((String) oMsg); String wholeMsg = msgWithZeroBits.replace("\u0000", ""); + //TODO(FF): simple query phase is not implemented switch (wholeMsg.substring(0, 1)) { - case "C": + case "C": //TODO(FF):was gnau passiert do?? PGInterfaceMessage msg = null; msg.setHeader(PGInterfaceHeaders.C); //msg.setMsgBody(); @@ -62,7 +65,6 @@ public String decideCycle(Object oMsg) { break; } - return cycleState; } public void startUpPhase() { @@ -121,6 +123,11 @@ public void sendReadyForQuery(String msgBody) { } + /** + * prepares the incoming message from the client, so it can be used in the context of polypheny + * @param incomingMsg unchanged incoming message from the client + * @return "normally" readable and usable query string + */ public String extractQuery(String incomingMsg) { String query = ""; //cut header @@ -162,11 +169,14 @@ public void sendParseBindComplete() { ctx.writeAndFlush(bindCompleteWriter.writeOnByteBuf()); */ + ByteBuf buffer = ctx.alloc().buffer(); PGInterfaceMessage mockMessage = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, true); PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter("i", mockMessage, ctx); - headerWriter.writeIntHeaderOnByteBuf('1'); - headerWriter.writeIntHeaderOnByteBuf('2'); - ctx.writeAndFlush(headerWriter); + buffer = headerWriter.writeIntHeaderOnByteBuf('1'); + //ctx.writeAndFlush(buffer); + buffer.writeBytes(headerWriter.writeIntHeaderOnByteBuf('2')); + //buffer = headerWriter.writeIntHeaderOnByteBuf('2'); + ctx.writeAndFlush(buffer); } @@ -181,7 +191,7 @@ public void sendCommandCompleteInsert(int rowsInserted) { //send CommandComplete - insert PGInterfaceMessage insertCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "INSERT" + PGInterfaceMessage.getDelimiter() + "0" + PGInterfaceMessage.getDelimiter() + String.valueOf(rowsInserted), 4, true); PGInterfaceServerWriter insertCommandCompleteWriter = new PGInterfaceServerWriter("sss", insertCommandComplete, ctx); - ctx.writeAndFlush(insertCommandCompleteWriter); + ctx.writeAndFlush(insertCommandCompleteWriter.writeOnByteBuf()); } @@ -189,37 +199,34 @@ public void sendCommandCompleteCreateTable() { //send CommandComplete - create table PGInterfaceMessage createTableCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "CREATE TABLE", 4, true); PGInterfaceServerWriter createTableCommandCompleteWriter = new PGInterfaceServerWriter("s", createTableCommandComplete, ctx); - ctx.writeAndFlush(createTableCommandCompleteWriter); + ctx.writeAndFlush(createTableCommandCompleteWriter.writeOnByteBuf()); } //for SELECT and CREATE TABLE AS public void sendCommandCompleteSelect(int rowsSelected) { //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ String.valueOf(rowsSelected), 4, true); - PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("s", selectCommandComplete, ctx); - ctx.writeAndFlush(selectCommandCompleteWriter); + String body = "SELECT"+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? + PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected), 4, true); + PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("ss", selectCommandComplete, ctx); + ctx.writeAndFlush(selectCommandCompleteWriter.writeOnByteBuf()); } - public void sendRowDescription(int numberOfFields, ArrayList valuesPerCol) { //String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode //bytebuf.writeInt(int value) = 32-bit int //bytebuf.writeShort(int value) = 16-bit short integer; - ByteBuf test = ctx.alloc().buffer(); + //ByteBuf test = ctx.alloc().buffer(); String body = String.valueOf(numberOfFields); - PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); + PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); + ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); - for(Object[] oneCol : valuesPerCol) { - test = rowDescriptionWriter.writeRowDescription(oneCol[0].toString(), (Integer) oneCol[1], (Integer) oneCol[2], (Integer) oneCol[3], (Integer) oneCol[4], (Integer) oneCol[5], (Integer) oneCol[6]); - ctx.writeAndFlush(test); - } //rowDescriptionWriter.writeRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); //ctx.writeAndFlush(test); - ctx.writeAndFlush(rowDescriptionWriter); + //ctx.writeAndFlush(rowDescriptionWriter); //TODO(FF): glaube das bruucht mer ned?? } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 8ebf1bbad1..3a24d3c82d 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -340,13 +340,14 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... Object col[] = {fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode}; valuesPerCol.add(col); } + communicationHandler.sendParseBindComplete(); communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); //sendData communicationHandler.sendDataRow(data); rowsAffected = data.size(); communicationHandler.sendCommandCompleteSelect(rowsAffected); - communicationHandler.sendParseBindComplete(); + communicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 47ee50a5849bb6da2f3b4dcce1973f50881795ac..5b424138642a8c311dde2379207bdcdd8bc12cf5 100644 GIT binary patch delta 117 zcmeyQ`9yJp7qh>G)I54Cvy_xWG+^p$x&R~lVdrHnM*2k OCL6K{Z+^+i$qfKJC?=Tz delta 1075 zcma)5&2AGh5Ekl>L@1|9oH$G)qwrrUk}S6=+7?uc^C)u%Al&<^qOanoK8KC%DCpIB<*)Tu z#kn(5jX)|m1U5eeKzY4ZoyYn9stbr&!X>GbTEPlcFYBC!Zm-#LkwykmjAAq-aCflV z$gh+yg6%=s-`ZyL<8hu)`dc;8I>R^=dLl8VpX6JWQGUF;Q*^o=c(mjQ=XH5#(H+km zGUDt&(6~|2j?vm^gv8SBwi{8LOXZ*mcAJn#^Sa2~O5Xi{>Z^)L;De%e!lPPw<@p}> zfb)kHOlZiPXqcf#x9pEzL^O$nbh85(pv#T2H`Ai>@sP~a2@HJ+FfAN98&FW%YPLW` z3WQdLi=+x`5sMDIkiQ+CohrwCh(y#Su*aLj>VpKaG~d2l6wd367b6c=q(;gi)(Tq^VQ;EL03QWd?EE9Pp(ICC{ cqoY>SMa5CR-k5IQaCgcN>)Y4gH*Vkg4FDZ4Gynhq diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index cfe4d5782e..7df2e25ba9 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; public class PGInterfaceServerWriter { String type; @@ -202,30 +203,63 @@ public ByteBuf writeIntHeaderOnByteBuf(char header) { return buffer; } - public ByteBuf writeRowDescription(String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode) { + public ByteBuf writeRowDescription(ArrayList valuesPerCol) { //I don't check for length, bcs rowDescription is always the same ByteBuf buffer = ctx.alloc().buffer(); + //ByteBuf bufferTemp = ctx.alloc().buffer(); + String fieldName; + int objectIDTable; + int attributeNoCol; + int objectIDCol; + int dataTypeSize; + int typeModifier; + int formatCode; //bytebuf.writeInt(int value) = 32-bit int //bytebuf.writeShort(int value) = 16-bit short integer; + int messageLength = 0; buffer.writeByte(pgMsg.getHeaderChar()); - buffer.writeInt(pgMsg.getLength() + fieldName.length() + 6); - - buffer.writeBytes(fieldName.getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); - buffer.writeInt(objectIDTable); - buffer.writeByte(0); - buffer.writeShort(attributeNoCol); - buffer.writeByte(0); - buffer.writeInt(objectIDCol); - buffer.writeByte(0); - buffer.writeShort(dataTypeSize); - buffer.writeByte(0); - buffer.writeInt(typeModifier); - buffer.writeByte(0); - buffer.writeShort(formatCode); + for (int i = 0; i be comission + + ctx.writeAndFlush(bufferTemp); //die erste 3x gohts ohni fähler + } + + //return buffer.writeBytes(bufferTemp); return buffer; } From 0171b9be03d8460674fa73e2509798a08053b3c7 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 5 Oct 2022 15:39:03 +0200 Subject: [PATCH 12/57] rowDescription is now sent correctly... although I don't know why... The origin of the number 8 eludes me as of yet... --- .../PGInterfaceInboundCommunicationHandler.java | 6 +----- .../db/postgresql/PGInterfaceQueryHandler.java | 6 ++++-- .../db/postgresql/PGInterfaceServerWriter.java | 16 ++++++---------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 233098426e..1a7fab4a47 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -223,10 +223,6 @@ public void sendRowDescription(int numberOfFields, ArrayList valuesPer PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); - - //rowDescriptionWriter.writeRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); - //ctx.writeAndFlush(test); - //ctx.writeAndFlush(rowDescriptionWriter); //TODO(FF): glaube das bruucht mer ned?? } @@ -265,7 +261,7 @@ value of the col (in format indicated by associated format code) (string) colValLength += colVal.length(); body += colVal.length() + PGInterfaceMessage.getDelimiter() + colVal + PGInterfaceMessage.getDelimiter(); } - } + } //do gets glaubs ergendwo neu en fähler? dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, colValLength, false); dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); //TODO(FF): Das werd nie uufgrüeft?? werom au emmer ctx.writeAndFlush(dataRowWriter.writeOnByteBuf()); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 3a24d3c82d..1df1f431cb 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -314,8 +314,10 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... formatCode = 1; break; case "VARCHAR": - dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize - formatCode = 0; + //dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize + //formatCode = 0; + dataTypeSize = 4; + formatCode = 1; break; case "SMALLINT": dataTypeSize = 2; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 7df2e25ba9..741d0b8302 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -215,20 +215,16 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { int typeModifier; int formatCode; - //bytebuf.writeInt(int value) = 32-bit int - //bytebuf.writeShort(int value) = 16-bit short integer; - int messageLength = 0; buffer.writeByte(pgMsg.getHeaderChar()); for (int i = 0; i( oder au ned? werom 8????? for(Object[] oneCol : valuesPerCol) { ByteBuf bufferTemp = ctx.alloc().buffer(); @@ -248,15 +244,15 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { bufferTemp.writeByte(0); bufferTemp.writeShort(attributeNoCol); bufferTemp.writeByte(0); - bufferTemp.writeInt(objectIDCol); + bufferTemp.writeInt(objectIDCol); //objectId of datatype? bufferTemp.writeByte(0); bufferTemp.writeShort(dataTypeSize); bufferTemp.writeByte(0); bufferTemp.writeInt(typeModifier); bufferTemp.writeByte(0); - bufferTemp.writeShort(formatCode); //aber bem 4. esch denn do dezwösche en fähöer cho, vorem nöchste flushl... werom au emmer??? --> be comission + bufferTemp.writeShort(formatCode); //aber bem 4. esch denn do dezwösche en fähler cho, vorem nöchste flushl... werom au emmer??? --> be comission - ctx.writeAndFlush(bufferTemp); //die erste 3x gohts ohni fähler + buffer.writeBytes(bufferTemp); //die erste 3x gohts ohni fähler } //return buffer.writeBytes(bufferTemp); From 9cabb44250d41b07383b73ffcaab765f9f4cb10f Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 15:00:25 +0200 Subject: [PATCH 13/57] client doesn't respond --- ...GInterfaceInboundCommunicationHandler.java | 2 +- .../postgresql/PGInterfaceQueryHandler.java | 13 +++-- .../postgresql/PGInterfaceServerWriter.java | 50 +++++++++++++++---- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 1a7fab4a47..f8a8850e12 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -263,7 +263,7 @@ value of the col (in format indicated by associated format code) (string) } } //do gets glaubs ergendwo neu en fähler? dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, colValLength, false); - dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); //TODO(FF): Das werd nie uufgrüeft?? werom au emmer + dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); ctx.writeAndFlush(dataRowWriter.writeOnByteBuf()); body = ""; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 1df1f431cb..2259709231 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -310,14 +310,17 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "REAL": case "INTEGER": + objectIDCol = 32; dataTypeSize = 4; - formatCode = 1; + formatCode = 1; //Test with 0, normally 1 (?) break; case "VARCHAR": - //dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize - //formatCode = 0; - dataTypeSize = 4; - formatCode = 1; + objectIDCol = 1043; + typeModifier = Integer.parseInt(head[2]); + dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize + formatCode = 0; + //dataTypeSize = 4; + //formatCode = 1; break; case "SMALLINT": dataTypeSize = 2; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 741d0b8302..eedd31457a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -136,20 +137,36 @@ public ByteBuf writeOnByteBuf() { case "dr": //send dataRow - buffer.writeByte(pgMsg.getHeaderChar()); + String test = ""; + ByteBuf buffer7 = ctx.alloc().buffer(); + buffer7.writeByte(pgMsg.getHeaderChar()); + ctx.writeAndFlush(buffer7); + test += pgMsg.getHeaderChar() + " | "; + + ByteBuf buffer1 = ctx.alloc().buffer(); + ByteBuf buffer2 = ctx.alloc().buffer(); + ByteBuf buffer3 = ctx.alloc().buffer(); int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("§","").length())/2; //should generally be not the default length, but also works with default length & length = 4 if (pgMsg.isDefaultLength()) { //data row does not include msg-length bytes in msg length - buffer.writeInt(pgMsg.getLength()- 4 - (nbrCol*2)); + buffer1.writeInt(pgMsg.getLength() - (nbrCol*2)); + ctx.writeAndFlush(buffer1); + int lol = (pgMsg.getLength() - (nbrCol*2)); + test += lol + " | "; } else { - buffer.writeInt(pgMsg.getLength()); + //bcs it is including self + buffer2.writeInt(pgMsg.getLength() + 4); + ctx.writeAndFlush(buffer2); + test += pgMsg.getLength() + " | "; } - buffer.writeShort(nbrCol); + buffer3.writeShort(nbrCol); //mues das evtl au 8 sii??? + ctx.writeAndFlush(buffer3); + test += nbrCol + " | "; //cut the last § (it is at the end) from the msgBody and set it as the new msgBody String temp = pgMsg.getMsgBody().substring(0, pgMsg.getMsgBody().length() - 1); @@ -158,13 +175,24 @@ public ByteBuf writeOnByteBuf() { int[] idx = new int[(nbrCol*2)]; String[] msgParts = pgMsg.getMsgPart(idx); - for (int i = 0; i < (nbrCol*2); i++) { - buffer.writeInt(Integer.parseInt(msgParts[i])); - buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); + for (int i = 0; i < ((nbrCol*2)- 1); i++) { //i<=10? hätt etzt gseit nei + ByteBuf buffer4 = ctx.alloc().buffer(); + ByteBuf buffer5 = ctx.alloc().buffer(); + ByteBuf buffer6 = ctx.alloc().buffer(); + buffer4.writeInt(Integer.parseInt(msgParts[i])); //onde: müesst 10 schecke... + ctx.writeAndFlush(buffer4); //2. durchgang, hier fehler chönnts + //buffer5.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? + buffer5.writeInt(Integer.parseInt(msgParts[i+1])); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? + ctx.writeAndFlush(buffer5); + //buffer6.writeBytes(msgParts[i+2].getBytes(StandardCharsets.UTF_8)); + buffer6.writeByte(0); + //ctx.writeAndFlush(buffer6); + + test += msgParts[i] + " | " + msgParts[i+1] + " | "; + i++; } - + int x = 2; break; } return buffer; @@ -224,7 +252,7 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { buffer.writeInt(pgMsg.getLength() + messageLength); //buffer.writeShort(Integer.parseInt(pgMsg.getMsgBody())); - buffer.writeShort(8); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? + buffer.writeShort(1); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? for(Object[] oneCol : valuesPerCol) { ByteBuf bufferTemp = ctx.alloc().buffer(); @@ -256,6 +284,8 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { } //return buffer.writeBytes(bufferTemp); + //String bla = new String(buffer.array(), Charset.defaultCharset()); + String bla = buffer.toString(Charset.defaultCharset()); return buffer; } From bf222591582d5b653eb1a8b343d7abc2ae8007c6 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 15:51:05 +0200 Subject: [PATCH 14/57] hardcoded, client doesn't respond for real --- ...GInterfaceInboundCommunicationHandler.java | 5 ++-- .../postgresql/PGInterfaceServerWriter.java | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index f8a8850e12..6ad991c950 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -221,8 +221,9 @@ public void sendRowDescription(int numberOfFields, ArrayList valuesPer //ByteBuf test = ctx.alloc().buffer(); String body = String.valueOf(numberOfFields); PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription - PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); - ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("test",rowDescription, ctx); + //ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); + ctx.writeAndFlush(rowDescriptionWriter.writeOnByteBuf()); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index eedd31457a..5377fdde33 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -139,7 +139,8 @@ public ByteBuf writeOnByteBuf() { //send dataRow String test = ""; ByteBuf buffer7 = ctx.alloc().buffer(); - buffer7.writeByte(pgMsg.getHeaderChar()); + //buffer7.writeByte(pgMsg.getHeaderChar()); + buffer7.writeByte('X'); ctx.writeAndFlush(buffer7); test += pgMsg.getHeaderChar() + " | "; @@ -194,6 +195,28 @@ public ByteBuf writeOnByteBuf() { } int x = 2; break; + + case "test": + //T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff + buffer.writeByte(pgMsg.getHeaderChar()); + buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); + //buffer.writeInt(24 + "empid".length()); + buffer.writeShort(1); + buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); + buffer.writeInt(0); + buffer.writeShort(0); + buffer.writeInt(0); + buffer.writeShort(40); + buffer.writeInt(2); + buffer.writeInt(0); + buffer.writeShort(1); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(17); + buffer.writeInt(0); + buffer.writeInt(4); + break; } return buffer; } From 2bdcd903bee5032794a2118abb13058625a838f3 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 16:44:18 +0200 Subject: [PATCH 15/57] new hardcoded things --- ...GInterfaceInboundCommunicationHandler.java | 29 ++++++++++++++++++- .../postgresql/PGInterfaceQueryHandler.java | 8 ++++- .../postgresql/PGInterfaceServerWriter.java | 11 +++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 6ad991c950..62407ecac3 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext; import org.polypheny.db.transaction.TransactionManager; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -208,7 +209,9 @@ public void sendCommandCompleteSelect(int rowsSelected) { String body = "SELECT"+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected), 4, true); PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("ss", selectCommandComplete, ctx); - ctx.writeAndFlush(selectCommandCompleteWriter.writeOnByteBuf()); + ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); + String lol = buf.toString(Charset.defaultCharset()); + ctx.writeAndFlush(buf); } @@ -266,6 +269,9 @@ value of the col (in format indicated by associated format code) (string) dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, colValLength, false); dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); ctx.writeAndFlush(dataRowWriter.writeOnByteBuf()); + ByteBuf buff = ctx.alloc().buffer(); + //C...SELECT 6 + buff.writeBytes("C000SELECT 6".getBytes(StandardCharsets.UTF_8)); body = ""; } @@ -276,4 +282,25 @@ public void terminateConnection() { ctx.close(); } + public void sendDataRow2(ArrayList data) { + ByteBuf buf = ctx.alloc().buffer(); + // 44 00 00 00 0b 00 01 00 00 00 01 31 + //buf.writeBytes("440000b01000131".getBytes()); + buf.writeInt(44); + buf.writeInt(0); + buf.writeInt(0); + buf.writeInt(0); + buf.writeInt(0); // + buf.writeInt(0); + buf.writeInt(1); + buf.writeInt(0); + buf.writeInt(0); + buf.writeInt(0); + buf.writeInt(1); + buf.writeInt(31); + String lol = buf.toString(Charset.defaultCharset()); + ctx.writeAndFlush(buf); + + + } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 2259709231..711d912d92 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -348,12 +348,18 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... communicationHandler.sendParseBindComplete(); communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); //sendData - communicationHandler.sendDataRow(data); + //communicationHandler.sendDataRow(data); + communicationHandler.sendDataRow2(data); rowsAffected = data.size(); communicationHandler.sendCommandCompleteSelect(rowsAffected); communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 5377fdde33..cfde94bd33 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -139,8 +139,8 @@ public ByteBuf writeOnByteBuf() { //send dataRow String test = ""; ByteBuf buffer7 = ctx.alloc().buffer(); - //buffer7.writeByte(pgMsg.getHeaderChar()); - buffer7.writeByte('X'); + buffer7.writeByte(pgMsg.getHeaderChar()); + //buffer7.writeByte('X'); ctx.writeAndFlush(buffer7); test += pgMsg.getHeaderChar() + " | "; @@ -199,7 +199,12 @@ public ByteBuf writeOnByteBuf() { case "test": //T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff buffer.writeByte(pgMsg.getHeaderChar()); - buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); + //buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); //buffer.writeInt(24 + "empid".length()); buffer.writeShort(1); buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); From 57015af09e9c85b1fdde7b8c954167e4aaf47ac5 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 17:44:37 +0200 Subject: [PATCH 16/57] not implemented yet, but byte analysis from wireshark --- .../db/postgresql/PGInterfaceQueryHandler.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 711d912d92..d3abf58bd8 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -387,6 +387,18 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... } } + //(SELECT empid FROM public.emps LIMIT 1) in postgres + /* +1....2....T......empid...@...............D..........100C....SELECT 1.Z....I + +1... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I +1... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 + +empid = 65 6d 70 69 64 +SELECT 1 = 53 45 4c 45 43 54 20 31 +(select_abst._1) + */ + //Example of server answer to simple select query (from real server) From 11683d5e5e8e58922285aa4d1163ab058d6cb1ed Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Sat, 8 Oct 2022 19:44:09 +0200 Subject: [PATCH 17/57] crude hardcoded version of response to query. Doesn't work yet, far too many 0 now show up in wireshark --- ...GInterfaceInboundCommunicationHandler.java | 7 +- .../postgresql/PGInterfaceQueryHandler.java | 64 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 62407ecac3..4a3f94a1d4 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -206,9 +206,10 @@ public void sendCommandCompleteCreateTable() { //for SELECT and CREATE TABLE AS public void sendCommandCompleteSelect(int rowsSelected) { //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - String body = "SELECT"+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? - PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected), 4, true); - PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("ss", selectCommandComplete, ctx); + String body = "SELECT "+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? + //"SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected) + PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, body, 4, true); + PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("s", selectCommandComplete, ctx); ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); String lol = buf.toString(Charset.defaultCharset()); ctx.writeAndFlush(buf); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index d3abf58bd8..9637c3636b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -16,6 +16,7 @@ package org.polypheny.db.postgresql; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import org.apache.commons.lang.ArrayUtils; import org.polypheny.db.PolyResult; @@ -32,6 +33,8 @@ import org.polypheny.db.processing.QueryProcessor; import org.polypheny.db.transaction.*; +import javax.swing.plaf.basic.BasicButtonUI; +import java.nio.charset.StandardCharsets; import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.List; @@ -53,9 +56,68 @@ public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInter } public void start() { - sendQueryToPolypheny(); + hardcodeResponse(); + //sendQueryToPolypheny(); } + private void hardcodeResponse() { + ByteBuf buffer = ctx.alloc().buffer(); + /* + 1....2....T......empid...@...............D..........100C....SELECT 1.Z....I + + 1... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I + 1... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 + T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 + */ + int[] nbrs = {1,0,0,0,4}; + //2 + int[] nbrs2 = {0,0,0,4}; + //T + //int[] nbrs3 = {0,0,0,1e,0,1}; + int[] nbrs3 = {0,0,0,0,0,1}; + //empid + //int[] nbrs4 = {0,0,0,40,0c,0,1,0,0,0,17,0,4,ff,ff,ff,ff,0,0}; + int[] nbrs4 = {0,0,0,40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; + //D + //int[] nbrs5 = {0,0,0,0d,0,1,0,0,0,3}; + int[] nbrs5 = {0,0,0,0,0,1,0,0,0,3}; + //100C + //int[] nbrs6 = {0,0,0,0d}; + int[] nbrs6 = {0,0,0,0}; + //SELECT 1 + int[] nbrs7 = {0}; + //Z + int[] nbrs8 = {0,0,0,5}; + //I + buffer = writeIntArray(nbrs, buffer); + buffer.writeInt(2); + buffer = writeIntArray(nbrs2, buffer); + buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs3, buffer); + buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs4, buffer); + buffer.writeBytes("D".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs5, buffer); + buffer.writeBytes("100C".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs6, buffer); + buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs7, buffer); + buffer.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs8, buffer); + buffer.writeBytes("I".getBytes(StandardCharsets.UTF_8)); + + ctx.writeAndFlush(buffer); + + } + + private ByteBuf writeIntArray(int[] nbrs, ByteBuf buffer) { + for (int i=0; i< nbrs.length; i++) { + buffer.writeInt(nbrs[i]); + } + return buffer; + } + + public void sendQueryToPolypheny() { String type = ""; //query type according to answer tags //get result from polypheny From 47d927e2f77d00a30aefdac9bb1ba3cccee2faac Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Mon, 10 Oct 2022 15:51:05 +0200 Subject: [PATCH 18/57] now hardcoded is exactly the same as the original in wireshark, and in client comes the error: 'Dieses ResultSet ist geschlossen' --- .../postgresql/PGInterfaceQueryHandler.java | 80 +++++++++++++++---- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 9637c3636b..86cd388b45 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -57,27 +57,51 @@ public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInter public void start() { hardcodeResponse(); + //hardcodeResponse2(); //sendQueryToPolypheny(); } + private void hardcodeResponse2() { + ByteBuf buffer = ctx.alloc().buffer(); + int[] nbr = {1, 2}; + buffer = writeIntArray(nbr, buffer); + buffer.writeByte('T'); + buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); + buffer.writeByte('@'); + buffer.writeByte('D'); + buffer.writeBytes("100".getBytes(StandardCharsets.UTF_8)); + buffer.writeByte('C'); + buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); + buffer.writeByte('Z'); + buffer.writeByte('I'); + ctx.writeAndFlush(buffer); + + } + private void hardcodeResponse() { ByteBuf buffer = ctx.alloc().buffer(); + ByteBuf buffer2 = ctx.alloc().buffer(); /* 1....2....T......empid...@...............D..........100C....SELECT 1.Z....I - 1... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I - 1... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 + 1 ... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I + 31 ... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 */ - int[] nbrs = {1,0,0,0,4}; + //ParseComplete + //int[] nbrs = {1,0,0,0,4}; + int[] nbrs = {4}; + //BindComplete //2 - int[] nbrs2 = {0,0,0,4}; + //int[] nbrs2 = {0,0,0,4}; + int[] nbrs2 = {4}; + //RowDescription //T - //int[] nbrs3 = {0,0,0,1e,0,1}; - int[] nbrs3 = {0,0,0,0,0,1}; + //int[] nbrs3 = {0,0,0,1e,0,1}; --> 1e ist short länge?? etzt schtemmt nome no d reihefolg ned... + int[] nbrs3 = {1}; //empid //int[] nbrs4 = {0,0,0,40,0c,0,1,0,0,0,17,0,4,ff,ff,ff,ff,0,0}; - int[] nbrs4 = {0,0,0,40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; + int[] nbrs4 = {40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; //D //int[] nbrs5 = {0,0,0,0d,0,1,0,0,0,3}; int[] nbrs5 = {0,0,0,0,0,1,0,0,0,3}; @@ -89,21 +113,49 @@ private void hardcodeResponse() { //Z int[] nbrs8 = {0,0,0,5}; //I + buffer.writeByte('1'); buffer = writeIntArray(nbrs, buffer); - buffer.writeInt(2); + //buffer.writeInt(2); + buffer.writeByte('2'); buffer = writeIntArray(nbrs2, buffer); buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs3, buffer); + buffer.writeShort(0); + buffer.writeShort(24+"empid".length() +1); //1e + buffer.writeShort(1); + //buffer = writeIntArray(nbrs3, buffer); buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs4, buffer); + buffer.writeInt(64); //@ + //buffer.writeByte(64); + //buffer.writeShort(12); //1 abst. zvel zwösche 40 ond 0c + buffer.writeByte(12); //0c + buffer.writeShort(1); + buffer.writeShort(0); + buffer.writeShort(23); //17 + buffer.writeShort(4); + //ctx.writeAndFlush(buffer); + //buffer = writeIntArray(nbrs4, buffer); + buffer.writeShort(2147483647); //ff + buffer.writeShort(2147483647); + buffer.writeByte(0); + buffer.writeByte(0); buffer.writeBytes("D".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs5, buffer); + buffer.writeShort(0); + buffer.writeShort(13); //0d + buffer.writeShort(1); + buffer.writeShort(0); + buffer.writeShort(3); + //buffer = writeIntArray(nbrs5, buffer); buffer.writeBytes("100C".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs6, buffer); + buffer.writeShort(0); + buffer.writeShort(13); + //buffer2 = writeIntArray(nbrs6, buffer2); buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs7, buffer); + //buffer2 = writeIntArray(nbrs7, buffer2); + buffer.writeByte(0); buffer.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs8, buffer); + //buffer2 = writeIntArray(nbrs8, buffer2); + buffer.writeShort(0); + buffer.writeShort(5); buffer.writeBytes("I".getBytes(StandardCharsets.UTF_8)); ctx.writeAndFlush(buffer); From 040e304c0bdf34c439752157f18b8e1bf013ec5d Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Tue, 9 Aug 2022 16:32:18 +0200 Subject: [PATCH 19/57] initial changes that allow the creation of a new interface (psql) --- .../db/postgresql/PostgresqlInterface.java | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java new file mode 100644 index 0000000000..d29bb11f81 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java @@ -0,0 +1,166 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + + +import com.google.common.collect.ImmutableList; +import lombok.extern.slf4j.Slf4j; +import org.polypheny.db.catalog.Catalog.QueryLanguage; +import org.polypheny.db.iface.Authenticator; +import org.polypheny.db.iface.QueryInterface; +import org.polypheny.db.information.InformationGroup; +import org.polypheny.db.information.InformationManager; +import org.polypheny.db.information.InformationPage; +import org.polypheny.db.information.InformationTable; +import org.polypheny.db.transaction.TransactionManager; +import org.polypheny.db.util.Util; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + + + +@Slf4j +public class PostgresqlInterface extends QueryInterface { + + @SuppressWarnings("WeakerAccess") + public static final String INTERFACE_NAME = "Postgresql Interface"; + @SuppressWarnings("WeakerAccess") + //TODO: Text abändern + public static final String INTERFACE_DESCRIPTION = "HTTP-based query interface, which supports all available languages via specific routes."; + @SuppressWarnings("WeakerAccess") + public static final List AVAILABLE_SETTINGS = ImmutableList.of( + new QueryInterfaceSettingInteger( "port", false, true, false, 13137 ) + //new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ) + //kann mehr selber hinzufügen + ); + + + private final int port; + private final String uniqueName; + + // Counters + private final Map statementCounters = new HashMap<>(); + + private final MonitoringPage monitoringPage; + + + public PostgresqlInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { + super( transactionManager, authenticator, ifaceId, uniqueName, settings, true, true ); + this.uniqueName = uniqueName; + this.port = Integer.parseInt( settings.get( "port" ) ); + if ( !Util.checkIfPortIsAvailable( port ) ) { + // Port is already in use + throw new RuntimeException( "Unable to start " + INTERFACE_NAME + " on port " + port + "! The port is already in use." ); + } + // Add information page + monitoringPage = new MonitoringPage(); + } + + + @Override + public void run() { + //ToDo: Instantiate Server (open port...) + + } + + + + @Override + public List getAvailableSettings() { + return AVAILABLE_SETTINGS; + } + + + @Override + public void shutdown() { + //todo: end things from run() + } + + + @Override + public String getInterfaceType() { + return INTERFACE_NAME; + } + + + @Override + protected void reloadSettings( List updatedSettings ) { + //Todo: if settings are mutable, change it here (can make them mutable) + } + + + private class MonitoringPage { + //TodO: vergliiche met anderne interfaces (zeigt infos em ui aah) + + private final InformationPage informationPage; + private final InformationGroup informationGroupRequests; + private final InformationTable statementsTable; + + + public MonitoringPage() { + InformationManager im = InformationManager.getInstance(); + + informationPage = new InformationPage( uniqueName, INTERFACE_NAME ).fullWidth().setLabel( "Interfaces" ); + informationGroupRequests = new InformationGroup( informationPage, "Requests" ); + + im.addPage( informationPage ); + im.addGroup( informationGroupRequests ); + + statementsTable = new InformationTable( + informationGroupRequests, + Arrays.asList( "Language", "Percent", "Absolute" ) + ); + statementsTable.setOrder( 2 ); + im.registerInformation( statementsTable ); + + informationGroupRequests.setRefreshFunction( this::update ); + } + + + //reload button + public void update() { + double total = 0; + for ( AtomicLong counter : statementCounters.values() ) { + total += counter.get(); + } + + DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(); + symbols.setDecimalSeparator( '.' ); + DecimalFormat df = new DecimalFormat( "0.0", symbols ); + statementsTable.reset(); + for ( Map.Entry entry : statementCounters.entrySet() ) { + statementsTable.addRow( entry.getKey().name(), df.format( total == 0 ? 0 : (entry.getValue().longValue() / total) * 100 ) + " %", entry.getValue().longValue() ); + } + } + + + public void remove() { + InformationManager im = InformationManager.getInstance(); + im.removeInformation( statementsTable ); + im.removeGroup( informationGroupRequests ); + im.removePage( informationPage ); + } + + } + +} From ddcb48568dfc7b2b0fbbec3507fb50c1d1736697 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Tue, 16 Aug 2022 13:08:56 +0200 Subject: [PATCH 20/57] 1.)deletes a HttpRestServer interface correctly -- 2.) It is now possible to receive a message from a psql client. But it does not send a correct reply to the client, neither does it anything with the message. --- .../org/polypheny/db/postgresql/Decoder.java | 73 +++++++++++++++++++ .../org/polypheny/db/postgresql/Encoder.java | 20 +++++ .../org/polypheny/db/postgresql/Message.java | 60 +++++++++++++++ .../db/postgresql/PostgresqlInterface.java | 73 +++++++++++++++++-- .../db/postgresql/ServerHandler.java | 60 +++++++++++++++ 5 files changed, 281 insertions(+), 5 deletions(-) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java new file mode 100644 index 0000000000..e841c88663 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java @@ -0,0 +1,73 @@ +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import org.polypheny.db.StatusService; + +import java.util.List; + +public class Decoder extends LengthFieldBasedFrameDecoder { + + private static final int HEADER_SIZE = 1; + private byte type; + private int length; + private String msgBody; + private ChannelHandlerContext ctx; + private ByteBuf in; + private List out; + + + public Decoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) throws Exception { + super(maxFrameLength, lengthFieldOffset, lengthFieldLength, + lengthAdjustment, initialBytesToStrip); + Object decoded = decode(ctx, in); + ctx.write(decoded); + } + + + /* + @Override + protected void decode (ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + this.ctx = ctx; + this.in = in; + Object decoded = decode(ctx, in); + if (decoded != null) { + out.add(decoded); + } + + } + + @Override + protected Object decode (ChannelHandlerContext ctx, ByteBuf in) throws Exception { + if (in == null) { + return null; + } + if (in.readableBytes() < HEADER_SIZE) { + throw new Exception("Only Header"); + } + + + type = in.readByte(); + length = in.readByte(); + + if(in.readableBytes() < length) { + //throw new Exception("The message is too short"); + } + + ByteBuf buf = in.readBytes(length); + byte[] b = new byte[buf.readableBytes()]; + buf.readBytes(b); + + msgBody = new String(b, "UTF-8"); + Message msg = new Message(type, length, msgBody); + + //StatusService.printInfo(String.format("decoded message:" + msgBody)); + + return msg; + + + } + + */ +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java new file mode 100644 index 0000000000..793b29037c --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java @@ -0,0 +1,20 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class Encoder { +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java new file mode 100644 index 0000000000..556097eb25 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class Message { + + //Message type + private byte type; + + //Message length + private int length; + + //Message body + private String msgBody; + + public Message(byte type, int length, String msgBody) { + this.type = type; + this.length = length; + this.msgBody = msgBody; + } + + public byte getType() { + return type; + } + + public void setType(byte type) { + this.type = type; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public String getMsgBody() { + return msgBody; + } + + public void setMsgBody(String msgBody) { + this.msgBody = msgBody; + } + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java index d29bb11f81..1a596c27f8 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java @@ -18,7 +18,18 @@ import com.google.common.collect.ImmutableList; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.handler.codec.LengthFieldPrepender; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; import lombok.extern.slf4j.Slf4j; +import org.polypheny.db.StatusService; import org.polypheny.db.catalog.Catalog.QueryLanguage; import org.polypheny.db.iface.Authenticator; import org.polypheny.db.iface.QueryInterface; @@ -29,6 +40,7 @@ import org.polypheny.db.transaction.TransactionManager; import org.polypheny.db.util.Util; +import java.nio.ByteOrder; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Arrays; @@ -45,13 +57,14 @@ public class PostgresqlInterface extends QueryInterface { @SuppressWarnings("WeakerAccess") public static final String INTERFACE_NAME = "Postgresql Interface"; @SuppressWarnings("WeakerAccess") - //TODO: Text abändern - public static final String INTERFACE_DESCRIPTION = "HTTP-based query interface, which supports all available languages via specific routes."; + // TODO: Update description text + public static final String INTERFACE_DESCRIPTION = "PostgreSQL-based query interface - in development"; @SuppressWarnings("WeakerAccess") public static final List AVAILABLE_SETTINGS = ImmutableList.of( - new QueryInterfaceSettingInteger( "port", false, true, false, 13137 ) - //new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ) - //kann mehr selber hinzufügen + new QueryInterfaceSettingInteger( "port", false, true, false, 5432 ) + // new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ), + // new QueryInterfaceSettingList( "serialization", false, true, false, ImmutableList.of( "PROTOBUF", "JSON" ) ) + // Possible to add more myself ); @@ -63,6 +76,11 @@ public class PostgresqlInterface extends QueryInterface { private final MonitoringPage monitoringPage; + // Server things + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); + + public PostgresqlInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { super( transactionManager, authenticator, ifaceId, uniqueName, settings, true, true ); @@ -81,6 +99,47 @@ public PostgresqlInterface(TransactionManager transactionManager, Authenticator public void run() { //ToDo: Instantiate Server (open port...) + try { + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel socketChannel) throws Exception { + ChannelPipeline channelPipeline = socketChannel.pipeline(); + + //Inbound + //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, Integer.MAX_VALUE, 1, 4, -4, 0, true)); + //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 1, 4, -4, 0)); + //channelPipeline.addLast("DecoderText", new Decoder(Integer.MAX_VALUE, 1, 4, -4, 0)); + //channelPipeline.addLast("headerdecoder", new StringDecoder()); + channelPipeline.addLast("decoder", new StringDecoder()); + + + //Outbound + channelPipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); + channelPipeline.addLast("encoder", new StringEncoder()); + + //Handler + channelPipeline.addLast("handler", new ServerHandler()); + + } + }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); + + // Start accepting incoming connections + ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); + + // Waits until server socket is closed --> introduces bugs --> polypheny not starting (without reset) and not displaying interface correctly + //channelFuture.channel().closeFuture().sync(); + + + } catch (Exception e) { + log.error("Exception while starting" + INTERFACE_NAME, e); + + } + + + StatusService.printInfo(String.format("%s started and is listening on port %d.", INTERFACE_NAME, port )); } @@ -94,6 +153,9 @@ public List getAvailableSettings() { @Override public void shutdown() { //todo: end things from run() + workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + monitoringPage.remove(); } @@ -106,6 +168,7 @@ public String getInterfaceType() { @Override protected void reloadSettings( List updatedSettings ) { //Todo: if settings are mutable, change it here (can make them mutable) + //nothing in avatica/http interface } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java new file mode 100644 index 0000000000..5ecb151f81 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.CharsetUtil; +import org.polypheny.db.StatusService; + +public class ServerHandler extends ChannelInboundHandlerAdapter { + @Override + public void channelRead (ChannelHandlerContext ctx, Object msg) { + //ECHO-protocol... write buffers it, the flushes + //alt: ctx. writeAndFlush(msg); + StatusService.printInfo(String.format("channel read reached...")); + + String in = (String) msg; + + ctx.write("AuthenticationOk"); + ctx.flush(); + + /* + + ChannelFuture channelFuture = ctx.write("AuthenticationOk"); + //channelFuture = ctx.write("ReadyForQuery"); + channelFuture.addListener(ChannelFutureListener.CLOSE); + + //ctx.write(msg); + //ctx.flush(); + + ByteBuf in = (ByteBuf) msg; + + */ + + } + + @Override + public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } +} + From 4941f5fd4355a6e96305027c6a49690bd24930db Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 25 Aug 2022 16:24:40 +0200 Subject: [PATCH 21/57] working version for a simple connection (using assumeMinServerVersion=9.0), renamed classes, started to implement structure for later --- .../org/polypheny/db/postgresql/Message.java | 60 ----- .../polypheny/db/postgresql/PGInterface.java | 1 + .../PGInterfaceHeaderPrepender.java | 38 +++ .../db/postgresql/PGInterfaceMessage.java | 12 +- .../db/postgresql/PGInterfaceServer.java | 20 ++ .../postgresql/PGInterfaceServerHandler.java | Bin 4324 -> 5824 bytes .../postgresql/PGInterfaceServerReader.java | 30 +++ .../postgresql/PGInterfaceServerWriter.java | 190 +-------------- .../db/postgresql/PostgresqlInterface.java | 229 ------------------ ...ServerHandler.java => ServerHandler2.java} | 48 ++-- 10 files changed, 117 insertions(+), 511 deletions(-) delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java rename postgresql-interface/src/main/java/org/polypheny/db/postgresql/{ServerHandler.java => ServerHandler2.java} (53%) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java deleted file mode 100644 index 556097eb25..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Message.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -public class Message { - - //Message type - private byte type; - - //Message length - private int length; - - //Message body - private String msgBody; - - public Message(byte type, int length, String msgBody) { - this.type = type; - this.length = length; - this.msgBody = msgBody; - } - - public byte getType() { - return type; - } - - public void setType(byte type) { - this.type = type; - } - - public int getLength() { - return length; - } - - public void setLength(int length) { - this.length = length; - } - - public String getMsgBody() { - return msgBody; - } - - public void setMsgBody(String msgBody) { - this.msgBody = msgBody; - } - -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 31c907ea3e..02ff016855 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -94,6 +94,7 @@ public PGInterface(TransactionManager transactionManager, Authenticator authenti @Override public void run() { + //ToDo: Instantiate Server (open port...) try { ServerBootstrap serverBootstrap = new ServerBootstrap(); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java new file mode 100644 index 0000000000..a0ce4b5b25 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +import java.nio.charset.StandardCharsets; + +public class PGInterfaceHeaderPrepender extends MessageToByteEncoder { + String header = "R"; //Authentication request header + //public HeaderPrepender() { } + + @Override + protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { + ByteBuf headerBuf = Unpooled.copiedBuffer(header.getBytes(StandardCharsets.UTF_8)); + out.writeBytes(headerBuf); + //out.writeBytes(msg); + } + + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 78737aee79..4d5fb3b724 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -22,14 +22,14 @@ public class PGInterfaceMessage { private PGInterfaceHeaders header; private String msgBody; private int length; //default is 4, if a different length is mentioned in protocol, this is given - private boolean defaultLength; - private static final char delimiter = '§'; //for the subparts + private int sizeMsgBody; //how many subparts are in the message. seperated by delimiter + private final char delimiter = '§'; - public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength) { + public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, int sizeMsgBody) { this.header = header; this.msgBody = msgBody; this.length = length; - this.defaultLength = defaultLength; + this.sizeMsgBody = sizeMsgBody; } public PGInterfaceHeaders getHeader() { @@ -112,8 +112,8 @@ public void setMsgBody(String msgBody) { * @return a string array with each requested part */ public String[] getMsgPart(int[] part) { - String subStrings[] = msgBody.split(getDelimiter()); - String result[] = new String[part.length]; + String subStrings[] = msgBody.split("§"); + String result[] = new String[0]; for (int i=0; i<(part.length); i++) { result[i] = subStrings[i]; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java new file mode 100644 index 0000000000..9f0dfd646e --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java @@ -0,0 +1,20 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +public class PGInterfaceServer { +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 5b424138642a8c311dde2379207bdcdd8bc12cf5..1669c55aad55adff07057c3cd6af52918d72bd8b 100644 GIT binary patch literal 5824 zcmcgw+iu&&7Jc_uZ0IFYB9oHs6ln|tl^weg;@Uovlb*IHj1f7KSW_H!IE<_o{hR*D z`LVM$Ii!Y`94kOk0=|&5FKgdt#(%j-FX>FBD;>?|h7NlDZ}$&+2M2UJmvp1zRXUf+ zif**}O$G+UOn(^#GRb5}c@j!Z2Bd>j1o&fDy7WovEK&&_cs*(}LCY?+I>#(xrE*$` z6(!10o=M1vGMYxQB>51?)KHXApcZKyi6oG;jLf{yW2Ja3<0mUaO^g7!07JSWHFXI| zRG{a^q;GwHxmkO~YT-4uaJ#0X!xWY7NFT9JlCn zFdmM(Eab=G?fdJGxAfy+G#Xsp4$sGQJ)*Pgt9QfO;q?{XE@*J|6MYz7z3Y;Mw-6Wk zkZQI7FeCP)3=6l7CA+(h6-}|u?^!B?Xc`4DEt%zFCTXTVOP#p!u z(IPU!6ra|4;Kaw@+k>C)Sr9z!rByO{;RG+4f#q|(}&-^6F(u_wKSNZ^BoOpNzK{qKbcjMA%GY(Wn5y?4SOr^Mn0u9Iu9 z>JLIP+G$OssyZ6!6M zLVJv zEau^Ea6(o1yl&Oeg6|_5c1hl_(d|1+XJYx$7bE-VC%+|l@aA?XnVM`I`A(thWLXE(c z$SgfaobUewO`!@FH=qJ{-G55e&FFAiJs_u=69ARLn=G^s$Ez=E8_E_%sldp{xjX{Q z`NZ7GBv5RzQ!Fm&ClMFaD9kqwNtIP4yhA2o?2n>y^r}?n#WIuhNC)vRlk64P~KPYo2RgUo<3ZudV+IK~H7IVeaMzy~JLs z4!OUMeluRLw}K1^@@n`tP;!tPbADrW-N^q@J&(M_ zICe0n*fu-1Y?0EiX3P3+_B>YfREIm{4#!XBU1u2i{w$iHt@ANW-K#jB$~lhRw3JD4 zs}V*LU5_#&W89z2@Pdtv;nUncu7N1T!57D-kavn|y-919<=BMmFV!JC1&CcEgc(5JdH;#@H;DHP9=S_fiodLqS-L^FinL}6Rzp|a> zZtA9n&)zJ~RqIuI&e^(Fp1vL}t@Sp-R=pr^>v-A=iHjTu zGg;kL*tc@R6r1;UYw+kSQ`}`*iN!ISFFCd`^2NvMLh1kHQm4M7jGmHYSKwR)73!57_<> D&>QC< literal 4324 zcmb7I|8CpJ5$2)A0Tu2Q3Jmy9sGLmNPK-+vq&P{o8#RvQ6P2WQMPaPSm9!1H%j_<# zsKq_cy~jP-eM?d@R=sEV}~i>0N*{e!>l9qu0<(saq` zLS^e>$>o|ZwE8bkEQFo>nMk-aJf%{mT$6=pzhDV&%}$TraczW>bQtba-~{|;%kRE$ z5NlOZ&ekNArP6R<2t#v`apIp6URV;65|tO3U^3yf5_VbXX;4Ck@pFTrW|l#m;eldJ zYTgzkwlR8XZSg#cR;yLWDq};X7g1KbVxqIr@Z>x`*@MB2mv3dpjUmlHmO{hX*_v1Z zgAz7_nHgJ=(!>^;W6vsQ@Jb6SqNe@_saZHGVs#_x;JFe?A?Z#5A7JaD09|nvTZj_;pJC^PlPU==``x9Bd&j z{8OQw2QX7OCV5)X7IR1UHdZvpzWZ$oo`|_f;F?^NY{6-vuDF))hzhQAVO&HF3{0I# znaG7@wpzN*gI0W^P6s@Ha6n)>EH=p$rZfC77R;HC*^5pG#wm@6t59-l*I}|`Qt~Vu z*7sLXm~lN+((+IC#h1iKa;9KU^He`&h2?tt)GbS5_)wad>nmi!{bE)#X;|Xi4X4-N z-!KXP0N;roSEX^PGygeU2Hn=B#?NnC(IEJ@cq$nj^ja^qtq|{`|gtL@_J5z-c`>99cnd@AX zn?>88DB1~pSZKsyBE2!<-p zONn0LGG-I4D%38BpA&jXlCK_!82Em#_VPBjuFp2tL-d9zsz2q!b&~PGk=1f9LTWcx z6tNOnD{bT2_``OqMZ%jV@pAwn#y1>lc7xUfufQ%&jBwH;e;+(QKLhPRw(N!K;- z9^DpQ&NW@!ZfR)?1-<~Nv!zjUrQ( z;U$u@I_824rdiINA$49+Q~TZRGcEf!^q8x!x_G&cA626q$Q3p{*3?2iA(5dHST z+mh@xByUS4id*U*M!`p__^qW153OnUP*FEXJmQ){gRJh(%B7yxI5dQTM(iVNkvP#<3 zXG^4Ml{72obFQB_5!YQ=mZ>D@hV^pr^!r*}m~pwV%b-i&(*gdfRfpW(IBa$54Q$Pr zQx-gmAKfc}f$8gX9dut%6p<1CtKLDf()A!WW$0}@Zku3&#+wDV&Lo5J0pltrKujds zaBD)abotC3ADc?K7p3z4D}ZjFT^s0@wmOG4x_44&fax65<7>V~lVw}`cH?+-cNmZM zTRLjBNA1YGz8#rn-v#EN9oS83iS)egqxCGB<19GE#I5u?1SyjeGe^$f{A<9OL^@%~ zi3cq+Fy>H!$?zpX2gg_*A~*)amJP7%q(g((APjXs`rUu;|L4Y|h9{a^umOPS(#?Bk zDq-0K@l<)3lv=|gXqGrb9A@kB9ReDCpWEK5Y6;yJ&7+pgbuhm;9@nqYIGu*9bZ_>b z8qy;z0GE>HINqc*LCoyk28g9yPgSUIU6;^Lx b ideally only use this in the future... - break; - - case "dr": - //send dataRow - String test = ""; - ByteBuf buffer7 = ctx.alloc().buffer(); - buffer7.writeByte(pgMsg.getHeaderChar()); - //buffer7.writeByte('X'); - ctx.writeAndFlush(buffer7); - test += pgMsg.getHeaderChar() + " | "; - - ByteBuf buffer1 = ctx.alloc().buffer(); - ByteBuf buffer2 = ctx.alloc().buffer(); - ByteBuf buffer3 = ctx.alloc().buffer(); - - int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("§","").length())/2; - - //should generally be not the default length, but also works with default length & length = 4 - if (pgMsg.isDefaultLength()) { - //data row does not include msg-length bytes in msg length - buffer1.writeInt(pgMsg.getLength() - (nbrCol*2)); - ctx.writeAndFlush(buffer1); - int lol = (pgMsg.getLength() - (nbrCol*2)); - test += lol + " | "; - } - else { - //bcs it is including self - buffer2.writeInt(pgMsg.getLength() + 4); - ctx.writeAndFlush(buffer2); - test += pgMsg.getLength() + " | "; - } - - buffer3.writeShort(nbrCol); //mues das evtl au 8 sii??? - ctx.writeAndFlush(buffer3); - test += nbrCol + " | "; - - //cut the last § (it is at the end) from the msgBody and set it as the new msgBody - String temp = pgMsg.getMsgBody().substring(0, pgMsg.getMsgBody().length() - 1); - pgMsg.setMsgBody(temp); - - int[] idx = new int[(nbrCol*2)]; - String[] msgParts = pgMsg.getMsgPart(idx); - - for (int i = 0; i < ((nbrCol*2)- 1); i++) { //i<=10? hätt etzt gseit nei - ByteBuf buffer4 = ctx.alloc().buffer(); - ByteBuf buffer5 = ctx.alloc().buffer(); - ByteBuf buffer6 = ctx.alloc().buffer(); - buffer4.writeInt(Integer.parseInt(msgParts[i])); //onde: müesst 10 schecke... - ctx.writeAndFlush(buffer4); //2. durchgang, hier fehler chönnts - //buffer5.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? - buffer5.writeInt(Integer.parseInt(msgParts[i+1])); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? - ctx.writeAndFlush(buffer5); - //buffer6.writeBytes(msgParts[i+2].getBytes(StandardCharsets.UTF_8)); - buffer6.writeByte(0); - //ctx.writeAndFlush(buffer6); - - test += msgParts[i] + " | " + msgParts[i+1] + " | "; - - i++; - } - int x = 2; - break; - - case "test": - //T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff - buffer.writeByte(pgMsg.getHeaderChar()); - //buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); - buffer.writeInt(0); - buffer.writeInt(0); - buffer.writeInt(0); - buffer.writeInt(0); - buffer.writeInt(0); - //buffer.writeInt(24 + "empid".length()); - buffer.writeShort(1); - buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer.writeInt(0); - buffer.writeShort(0); - buffer.writeInt(0); - buffer.writeShort(40); - buffer.writeInt(2); - buffer.writeInt(0); - buffer.writeShort(1); - buffer.writeInt(0); - buffer.writeInt(0); - buffer.writeInt(0); - buffer.writeInt(17); - buffer.writeInt(0); - buffer.writeInt(4); - break; } return buffer; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java deleted file mode 100644 index 1a596c27f8..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterface.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - - -import com.google.common.collect.ImmutableList; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ByteBuf; -import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import io.netty.handler.codec.LengthFieldPrepender; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; -import lombok.extern.slf4j.Slf4j; -import org.polypheny.db.StatusService; -import org.polypheny.db.catalog.Catalog.QueryLanguage; -import org.polypheny.db.iface.Authenticator; -import org.polypheny.db.iface.QueryInterface; -import org.polypheny.db.information.InformationGroup; -import org.polypheny.db.information.InformationManager; -import org.polypheny.db.information.InformationPage; -import org.polypheny.db.information.InformationTable; -import org.polypheny.db.transaction.TransactionManager; -import org.polypheny.db.util.Util; - -import java.nio.ByteOrder; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - - - -@Slf4j -public class PostgresqlInterface extends QueryInterface { - - @SuppressWarnings("WeakerAccess") - public static final String INTERFACE_NAME = "Postgresql Interface"; - @SuppressWarnings("WeakerAccess") - // TODO: Update description text - public static final String INTERFACE_DESCRIPTION = "PostgreSQL-based query interface - in development"; - @SuppressWarnings("WeakerAccess") - public static final List AVAILABLE_SETTINGS = ImmutableList.of( - new QueryInterfaceSettingInteger( "port", false, true, false, 5432 ) - // new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ), - // new QueryInterfaceSettingList( "serialization", false, true, false, ImmutableList.of( "PROTOBUF", "JSON" ) ) - // Possible to add more myself - ); - - - private final int port; - private final String uniqueName; - - // Counters - private final Map statementCounters = new HashMap<>(); - - private final MonitoringPage monitoringPage; - - // Server things - private final EventLoopGroup bossGroup = new NioEventLoopGroup(); - private final EventLoopGroup workerGroup = new NioEventLoopGroup(); - - - - public PostgresqlInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { - super( transactionManager, authenticator, ifaceId, uniqueName, settings, true, true ); - this.uniqueName = uniqueName; - this.port = Integer.parseInt( settings.get( "port" ) ); - if ( !Util.checkIfPortIsAvailable( port ) ) { - // Port is already in use - throw new RuntimeException( "Unable to start " + INTERFACE_NAME + " on port " + port + "! The port is already in use." ); - } - // Add information page - monitoringPage = new MonitoringPage(); - } - - - @Override - public void run() { - //ToDo: Instantiate Server (open port...) - - try { - ServerBootstrap serverBootstrap = new ServerBootstrap(); - serverBootstrap.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { - @Override - public void initChannel(SocketChannel socketChannel) throws Exception { - ChannelPipeline channelPipeline = socketChannel.pipeline(); - - //Inbound - //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, Integer.MAX_VALUE, 1, 4, -4, 0, true)); - //channelPipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 1, 4, -4, 0)); - //channelPipeline.addLast("DecoderText", new Decoder(Integer.MAX_VALUE, 1, 4, -4, 0)); - //channelPipeline.addLast("headerdecoder", new StringDecoder()); - channelPipeline.addLast("decoder", new StringDecoder()); - - - //Outbound - channelPipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); - channelPipeline.addLast("encoder", new StringEncoder()); - - //Handler - channelPipeline.addLast("handler", new ServerHandler()); - - } - }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); - - // Start accepting incoming connections - ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); - - // Waits until server socket is closed --> introduces bugs --> polypheny not starting (without reset) and not displaying interface correctly - //channelFuture.channel().closeFuture().sync(); - - - } catch (Exception e) { - log.error("Exception while starting" + INTERFACE_NAME, e); - - } - - - StatusService.printInfo(String.format("%s started and is listening on port %d.", INTERFACE_NAME, port )); - } - - - - @Override - public List getAvailableSettings() { - return AVAILABLE_SETTINGS; - } - - - @Override - public void shutdown() { - //todo: end things from run() - workerGroup.shutdownGracefully(); - bossGroup.shutdownGracefully(); - monitoringPage.remove(); - } - - - @Override - public String getInterfaceType() { - return INTERFACE_NAME; - } - - - @Override - protected void reloadSettings( List updatedSettings ) { - //Todo: if settings are mutable, change it here (can make them mutable) - //nothing in avatica/http interface - } - - - private class MonitoringPage { - //TodO: vergliiche met anderne interfaces (zeigt infos em ui aah) - - private final InformationPage informationPage; - private final InformationGroup informationGroupRequests; - private final InformationTable statementsTable; - - - public MonitoringPage() { - InformationManager im = InformationManager.getInstance(); - - informationPage = new InformationPage( uniqueName, INTERFACE_NAME ).fullWidth().setLabel( "Interfaces" ); - informationGroupRequests = new InformationGroup( informationPage, "Requests" ); - - im.addPage( informationPage ); - im.addGroup( informationGroupRequests ); - - statementsTable = new InformationTable( - informationGroupRequests, - Arrays.asList( "Language", "Percent", "Absolute" ) - ); - statementsTable.setOrder( 2 ); - im.registerInformation( statementsTable ); - - informationGroupRequests.setRefreshFunction( this::update ); - } - - - //reload button - public void update() { - double total = 0; - for ( AtomicLong counter : statementCounters.values() ) { - total += counter.get(); - } - - DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(); - symbols.setDecimalSeparator( '.' ); - DecimalFormat df = new DecimalFormat( "0.0", symbols ); - statementsTable.reset(); - for ( Map.Entry entry : statementCounters.entrySet() ) { - statementsTable.addRow( entry.getKey().name(), df.format( total == 0 ? 0 : (entry.getValue().longValue() / total) * 100 ) + " %", entry.getValue().longValue() ); - } - } - - - public void remove() { - InformationManager im = InformationManager.getInstance(); - im.removeInformation( statementsTable ); - im.removeGroup( informationGroupRequests ); - im.removePage( informationPage ); - } - - } - -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java similarity index 53% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java rename to postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java index 5ecb151f81..b21953ce8e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java @@ -17,44 +17,28 @@ package org.polypheny.db.postgresql; import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.util.CharsetUtil; import org.polypheny.db.StatusService; -public class ServerHandler extends ChannelInboundHandlerAdapter { - @Override - public void channelRead (ChannelHandlerContext ctx, Object msg) { - //ECHO-protocol... write buffers it, the flushes - //alt: ctx. writeAndFlush(msg); - StatusService.printInfo(String.format("channel read reached...")); - - String in = (String) msg; - - ctx.write("AuthenticationOk"); - ctx.flush(); - - /* - - ChannelFuture channelFuture = ctx.write("AuthenticationOk"); - //channelFuture = ctx.write("ReadyForQuery"); - channelFuture.addListener(ChannelFutureListener.CLOSE); - - //ctx.write(msg); - //ctx.flush(); +import java.nio.charset.StandardCharsets; - ByteBuf in = (ByteBuf) msg; - - */ - - } +public class ServerHandler2 extends ChannelInboundHandlerAdapter { @Override - public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) { - cause.printStackTrace(); - ctx.close(); + public void channelRead (ChannelHandlerContext ctx, Object msg) { + StatusService.printInfo(String.format("channel read reached...2")); + + String param = "client_encoding"; + String paramVal = "UTF8"; + ByteBuf buffer3 = ctx.alloc().buffer(4+param.length() + 1 + paramVal.length() + 2); + buffer3.writeByte('S'); + buffer3.writeInt(4+param.length() + 1 + paramVal.length() + 1); // size excluding char + buffer3.writeBytes(param.getBytes(StandardCharsets.UTF_8)); + buffer3.writeBytes(paramVal.getBytes(StandardCharsets.UTF_8)); + //StatusService.printInfo(String.format("channel read reached...")); + ctx.writeAndFlush(buffer3); } -} +} From aba50d03d0000f7cfdfe647f68d157fd2d6ea009 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 14 Sep 2022 19:44:45 +0200 Subject: [PATCH 22/57] not yet able to handle queries, but set up to start doing so, expanded/generalized responses the 'server' is sending --- .../{Encoder.java => PGInterfaceClient.java} | 25 +- ...GInterfaceInboundCommunicationHandler.java | 62 ++- .../db/postgresql/PGInterfaceMessage.java | 10 +- .../postgresql/PGInterfaceQueryHandler.java | 456 +----------------- .../postgresql/PGInterfaceServerHandler.java | Bin 5824 -> 5247 bytes .../postgresql/PGInterfaceServerWriter.java | 75 ++- .../db/postgresql/ServerHandler2.java | 44 -- 7 files changed, 157 insertions(+), 515 deletions(-) rename postgresql-interface/src/main/java/org/polypheny/db/postgresql/{Encoder.java => PGInterfaceClient.java} (52%) delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/ServerHandler2.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java similarity index 52% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java rename to postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java index 793b29037c..abe97739a5 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Encoder.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java @@ -16,5 +16,28 @@ package org.polypheny.db.postgresql; -public class Encoder { +import io.netty.channel.ChannelHandlerContext; + +import java.net.InetSocketAddress; + +public class PGInterfaceClient { + public static ChannelHandlerContext ctx = null; + public String state; + + public PGInterfaceClient (ChannelHandlerContext ctx) { + this.ctx = ctx; + //int port = ((InetSocketAddress)ctx.channel().remoteAddress()).getPort(); + } + + public static ChannelHandlerContext getCtx() { + return ctx; + } + + public void setState(String state) { + this.state = state; + } + + public String getState() { + return state; + } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 4a3f94a1d4..1ac23726d6 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -18,39 +18,33 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import org.polypheny.db.transaction.TransactionManager; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -/** - * Manages all incoming communication, not using the netty framework - */ public class PGInterfaceInboundCommunicationHandler { String type; + PGInterfaceClient client; ChannelHandlerContext ctx; - TransactionManager transactionManager; - public PGInterfaceInboundCommunicationHandler (String type, ChannelHandlerContext ctx, TransactionManager transactionManager) { + public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client) { this.type = type; - this.ctx = ctx; - this.transactionManager = transactionManager; + this.client = client; + this.ctx = client.getCtx(); } + //ich mues ergendwie identifiziere wele client dases esch... oder muesich öberhaupt speichere was fören phase das de client denne esch... + //muesich das wörklech oder esches eidütig vom protokoll här? --> has gfühl chas eidütig metem protokoll handle - /** - * Decides in what cycle from postgres the client is (startup-phase, query-phase, etc.) - * @param oMsg the incoming message from the client (unchanged) - * @return - */ - public void decideCycle(Object oMsg) { + + public String decideCycle(Object oMsg) { + String cycleState = ""; String msgWithZeroBits = ((String) oMsg); String wholeMsg = msgWithZeroBits.replace("\u0000", ""); - //TODO(FF): simple query phase is not implemented + + switch (wholeMsg.substring(0, 1)) { - case "C": //TODO(FF):was gnau passiert do?? + case "C": PGInterfaceMessage msg = null; msg.setHeader(PGInterfaceHeaders.C); //msg.setMsgBody(); @@ -66,6 +60,7 @@ public void decideCycle(Object oMsg) { break; } + return cycleState; } public void startUpPhase() { @@ -76,7 +71,6 @@ public void startUpPhase() { //server_version (Parameter Status message) PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version§14", 4, true); - //PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter("ss", parameterStatusServerVs, ctx); ctx.writeAndFlush(parameterStatusServerVsWriter.writeOnByteBuf()); @@ -91,6 +85,36 @@ public void simpleQueryPhase() { public void extendedQueryPhase(String incomingMsg) { if (incomingMsg.substring(2,5).equals("SET")) { + //parseComplete + /* + PGInterfaceMessage parseComplete = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, false); + PGInterfaceServerWriter parseCompleteWriter = new PGInterfaceServerWriter("i", parseComplete, ctx); + ctx.writeAndFlush(parseCompleteWriter.writeOnByteBuf()); + + */ + + //ParameterStatus - client_encoding (ParameterStatus message) + String paramu = "SET"; + String paramValu = "UTF8"; + ByteBuf buffer3u = ctx.alloc().buffer(4+paramu.length()+10); + buffer3u.writeByte('1'); + buffer3u.writeInt(4); // size excluding char + //buffer3u.writeBytes(paramu.getBytes(StandardCharsets.UTF_8)); + //buffer3u.writeBytes(paramValu.getBytes(StandardCharsets.UTF_8)); + ctx.writeAndFlush(buffer3u); + + /* + //bindComplete + PGInterfaceMessage bindComplete = new PGInterfaceMessage(PGInterfaceHeaders.TWO, "0", 4, true); + PGInterfaceServerWriter bindCompleteWriter = new PGInterfaceServerWriter("i", bindComplete, ctx); + ctx.writeAndFlush(bindCompleteWriter.writeOnByteBuf()); + + */ + + ByteBuf buffer4u = ctx.alloc().buffer(4+10); + buffer4u.writeByte('2'); + buffer4u.writeInt(4); // size excluding char + ctx.writeAndFlush(buffer4u); sendParseBindComplete(); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 4d5fb3b724..725fc6376c 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -22,14 +22,14 @@ public class PGInterfaceMessage { private PGInterfaceHeaders header; private String msgBody; private int length; //default is 4, if a different length is mentioned in protocol, this is given - private int sizeMsgBody; //how many subparts are in the message. seperated by delimiter - private final char delimiter = '§'; + private boolean defaultLength; + private final char delimiter = '§'; //for the subparts - public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, int sizeMsgBody) { + public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength) { this.header = header; this.msgBody = msgBody; this.length = length; - this.sizeMsgBody = sizeMsgBody; + this.defaultLength = defaultLength; } public PGInterfaceHeaders getHeader() { @@ -113,7 +113,7 @@ public void setMsgBody(String msgBody) { */ public String[] getMsgPart(int[] part) { String subStrings[] = msgBody.split("§"); - String result[] = new String[0]; + String result[] = new String[part.length]; for (int i=0; i<(part.length); i++) { result[i] = subStrings[i]; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 86cd388b45..23d9b31bca 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -16,467 +16,31 @@ package org.polypheny.db.postgresql; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import org.apache.commons.lang.ArrayUtils; -import org.polypheny.db.PolyResult; -import org.polypheny.db.algebra.AlgRoot; -import org.polypheny.db.algebra.constant.Kind; -import org.polypheny.db.algebra.type.AlgDataTypeField; -import org.polypheny.db.catalog.Catalog; -import org.polypheny.db.catalog.entity.*; -import org.polypheny.db.catalog.exceptions.*; -import org.polypheny.db.config.RuntimeConfig; -import org.polypheny.db.languages.QueryParameters; -import org.polypheny.db.nodes.Node; -import org.polypheny.db.processing.Processor; -import org.polypheny.db.processing.QueryProcessor; -import org.polypheny.db.transaction.*; - -import javax.swing.plaf.basic.BasicButtonUI; -import java.nio.charset.StandardCharsets; -import java.sql.ResultSetMetaData; -import java.util.ArrayList; -import java.util.List; - -public class PGInterfaceQueryHandler{ + +public class PGInterfaceQueryHandler { String query; ChannelHandlerContext ctx; - PGInterfaceInboundCommunicationHandler communicationHandler; - private TransactionManager transactionManager; - int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) - List> rows; - public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager) { + public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx) { this.query = query; this.ctx = ctx; - this.communicationHandler = communicationHandler; - Object obj = new Object(); - this.transactionManager = transactionManager; - } - - public void start() { - hardcodeResponse(); - //hardcodeResponse2(); - //sendQueryToPolypheny(); - } - - private void hardcodeResponse2() { - ByteBuf buffer = ctx.alloc().buffer(); - int[] nbr = {1, 2}; - buffer = writeIntArray(nbr, buffer); - buffer.writeByte('T'); - buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte('@'); - buffer.writeByte('D'); - buffer.writeBytes("100".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte('C'); - buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte('Z'); - buffer.writeByte('I'); - ctx.writeAndFlush(buffer); - - } - - private void hardcodeResponse() { - ByteBuf buffer = ctx.alloc().buffer(); - ByteBuf buffer2 = ctx.alloc().buffer(); - /* - 1....2....T......empid...@...............D..........100C....SELECT 1.Z....I - - 1 ... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I - 31 ... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 - T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 - */ - //ParseComplete - //int[] nbrs = {1,0,0,0,4}; - int[] nbrs = {4}; - //BindComplete - //2 - //int[] nbrs2 = {0,0,0,4}; - int[] nbrs2 = {4}; - //RowDescription - //T - //int[] nbrs3 = {0,0,0,1e,0,1}; --> 1e ist short länge?? etzt schtemmt nome no d reihefolg ned... - int[] nbrs3 = {1}; - //empid - //int[] nbrs4 = {0,0,0,40,0c,0,1,0,0,0,17,0,4,ff,ff,ff,ff,0,0}; - int[] nbrs4 = {40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; - //D - //int[] nbrs5 = {0,0,0,0d,0,1,0,0,0,3}; - int[] nbrs5 = {0,0,0,0,0,1,0,0,0,3}; - //100C - //int[] nbrs6 = {0,0,0,0d}; - int[] nbrs6 = {0,0,0,0}; - //SELECT 1 - int[] nbrs7 = {0}; - //Z - int[] nbrs8 = {0,0,0,5}; - //I - buffer.writeByte('1'); - buffer = writeIntArray(nbrs, buffer); - //buffer.writeInt(2); - buffer.writeByte('2'); - buffer = writeIntArray(nbrs2, buffer); - buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); - buffer.writeShort(0); - buffer.writeShort(24+"empid".length() +1); //1e - buffer.writeShort(1); - //buffer = writeIntArray(nbrs3, buffer); - buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer.writeInt(64); //@ - //buffer.writeByte(64); - //buffer.writeShort(12); //1 abst. zvel zwösche 40 ond 0c - buffer.writeByte(12); //0c - buffer.writeShort(1); - buffer.writeShort(0); - buffer.writeShort(23); //17 - buffer.writeShort(4); - //ctx.writeAndFlush(buffer); - //buffer = writeIntArray(nbrs4, buffer); - buffer.writeShort(2147483647); //ff - buffer.writeShort(2147483647); - buffer.writeByte(0); - buffer.writeByte(0); - buffer.writeBytes("D".getBytes(StandardCharsets.UTF_8)); - buffer.writeShort(0); - buffer.writeShort(13); //0d - buffer.writeShort(1); - buffer.writeShort(0); - buffer.writeShort(3); - //buffer = writeIntArray(nbrs5, buffer); - buffer.writeBytes("100C".getBytes(StandardCharsets.UTF_8)); - buffer.writeShort(0); - buffer.writeShort(13); - //buffer2 = writeIntArray(nbrs6, buffer2); - buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); - //buffer2 = writeIntArray(nbrs7, buffer2); - buffer.writeByte(0); - buffer.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); - //buffer2 = writeIntArray(nbrs8, buffer2); - buffer.writeShort(0); - buffer.writeShort(5); - buffer.writeBytes("I".getBytes(StandardCharsets.UTF_8)); - - ctx.writeAndFlush(buffer); - } - private ByteBuf writeIntArray(int[] nbrs, ByteBuf buffer) { - for (int i=0; i< nbrs.length; i++) { - buffer.writeInt(nbrs[i]); - } - return buffer; - } - - public void sendQueryToPolypheny() { String type = ""; //query type according to answer tags //get result from polypheny - Transaction transaction; - Statement statement = null; - PolyResult result; - ArrayList data = new ArrayList<>(); - ArrayList header = new ArrayList<>(); - - - - try { - //get transaction letze linie - transaction = transactionManager.startTransaction("pa", "APP", false, "Index Manager"); - statement = transaction.createStatement(); - } - catch (UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e) { - throw new RuntimeException( "Error while starting transaction", e ); - } - - - - //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) - //for loop zom dor alli catalogTables doregoh? - nei - Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); - Node sqlNode = sqlProcessor.parse(query); //go gehts fähler: (see diary) - QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); - if ( sqlNode.isA( Kind.DDL ) ) { - result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); - //TODO(FF): ene try catch block... || evtl no committe (söscht werds ned aazeigt em ui (aso allgemein, wie werds denn aazeigt em ui?) - // exception: java.lang.RuntimeException: No primary key has been provided! - } else { - AlgRoot algRoot = sqlProcessor.translate( - statement, - sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, - new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); - - //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) - final QueryProcessor processor = statement.getQueryProcessor(); - result = processor.prepareQuery(algRoot, true); - - } - - //get type information - from crud.java - //Type of ArrayList was DbColumn, but belongs to webUI (so I don't need it...) --> replaced it with string? - //ArrayList header = getHeader(result, query); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? - header = getHeader(result); - //statement.executeUpdate("SELECT empid FROM public.emps"); - - //get actual result of query in array - from crud.java - rows = result.getRows(statement, -1); //-1 as size valid?? - data = computeResultData(rows, header); //, statement.getTransaction() - - //type = result.getStatementType().name(); - type = result.getStatementType().toString(); //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) //handle result --> depending on query type, prepare answer message accordingly here (flush it) - sendResultToClient(type, data, header); - - } - - /** - * gets the information for the header - * @param result the polyresult the additional information is needed - * @return a list with array, where: - * - array[0] = columnName - * - array[1] = columnType - */ - private ArrayList getHeader(PolyResult result) { //(request = query) - ArrayList header = new ArrayList<>(); - for ( AlgDataTypeField metaData : result.getRowType().getFieldList() ) { - String columnName = metaData.getName(); - //final String name = metaData.getName(); - String dataType = metaData.getType().getPolyType().getTypeName(); //INTEGER, VARCHAR --> aber ergendwie ohnis (20) em header?? - int precision = metaData.getType().getPrecision(); //sizeVarChar - boolean nullable = metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1); - //Integer precision = metaData.getType().getPrecision(); - - //For each column: If it should be filtered empty string if it should not be filtered - /* - String filter = ""; - if ( request.filter != null && request.filter.containsKey( columnName ) ) { - filter = request.filter.get( columnName ); - } - */ - - //For each column: If and how it should be sorted - /* - SortState sort; - if ( request.sortState != null && request.sortState.containsKey( columnName ) ) { - sort = request.sortState.get( columnName ); - } else { - sort = new SortState(); - } - */ - - /* - DbColumn dbCol = new DbColumn( - metaData.getName(), - metaData.getType().getPolyType().getTypeName(), - metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1), - metaData.getType().getPrecision(), - sort, - filter ); - */ - - //bruuch ich ned wörklech? - /* - // Get column default values - if ( catalogTable != null ) { - try { - if ( catalog.checkIfExistsColumn( catalogTable.id, columnName ) ) { - CatalogColumn catalogColumn = catalog.getColumn( catalogTable.id, columnName ); - if ( catalogColumn.defaultValue != null ) { - dbCol.defaultValue = catalogColumn.defaultValue.value; - } - } - } catch ( UnknownColumnException e ) { - log.error( "Caught exception", e ); - } - } - - */ - //header.add( dbCol ); - header.add(new String[]{columnName, dataType, String.valueOf(precision)}); - } - return header; - } - - private ArrayList computeResultData(List> rows, ArrayList header) { - //TODO(FF): bruuch ich de header do öberhaupt? (aso em momänt ned... ) --> hanich sache wonich de chönnt/müesst bruuche? - //ha es paar sache useglöscht... aber wahrschiinli muesmer de no meh lösche... - ArrayList data = new ArrayList<>(); - - for ( List row : rows ) { - String[] temp = new String[row.size()]; //temp esch au 100 --> vo resultat sälber... - int counter = 0; - for ( Object o : row ) { - if ( o == null ) { - temp[counter] = null; - } else { - switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry (only handling "standard" returns - case "TIMESTAMP": - break; - case "DATE": - break; - case "TIME": - break; - case "FILE": - case "IMAGE": - case "SOUND": - case "VIDEO": - break; - //fall through - default: - temp[counter] = o.toString(); - } - if ( header.get( counter )[0].endsWith( "ARRAY" ) ) { - - } - } - counter++; //was macht gnau de counter? (esch etzt 1, chonnt add), rows size = 4 - } - data.add( temp ); - } - - - return data; - } - - - public void sendResultToClient(String type, ArrayList data, ArrayList header) { switch (type) { case "INSERT": - //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) //INSERT oid rows (oid=0, rows = #rows inserted) //1....2....n....C....INSERT 0 1.Z....I - - //insert into table with several vals (but only 1 row) - /* - client: - P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B............D....P.E... .....S.... - - server: - 1....2....n....C....INSERT 0 1.Z....I - */ - - - communicationHandler.sendParseBindComplete(); - communicationHandler.sendCommandCompleteInsert(rowsAffected); - communicationHandler.sendReadyForQuery("I"); - break; - case "CREATE TABLE": - //TODO(FF) do things in polypheny (?) - //1....2....n....C....CREATE TABLE.Z....I - communicationHandler.sendParseBindComplete(); - communicationHandler.sendCommandCompleteCreateTable(); - communicationHandler.sendReadyForQuery("I"); - - break; - - case "SELECT" : //also CREATE TABLE AS - int lol = 4; - ArrayList valuesPerCol = new ArrayList(); - - String fieldName = ""; //get field name from query? momentan no de einzig val em header o - int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 o - int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 o - int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified o - int formatCode = 0; //int16 --> zero(text-inhalt (values)) or one(integer) --> if returned from describe, not yet known = 0 o. - int typeModifier = -1; //The value will generally be -1 for types that do not need atttypmod. --> type specific data (supplied at table creation time o - - int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt - //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types - //For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative - // o. - - - if (lol == 3) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... - //noData - //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) - communicationHandler.sendParseBindComplete(); - communicationHandler.sendReadyForQuery("I"); - } - - else { - //data - //for loop mache för jedi reihe? --> nocheluege wies gmacht werd em ächte psql met mehrere cols & reihe - int numberOfFields = header.size(); - - for (String[] head : header) { - - fieldName = head[0]; - - //TODO(FF): Implement the rest of the cases - switch (head[1]) { - case "BIGINT": - case "DOUBLE": - dataTypeSize = 8; //8 bytes signed - formatCode = 1; //TODO(FF): esch das rechtig? wel es heisst e de doc darstellig vo Integer... - break; - case "BOOLEAN": - dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? - break; - case "DATE": - break; - case "DECIMAL": - break; - case "REAL": - case "INTEGER": - objectIDCol = 32; - dataTypeSize = 4; - formatCode = 1; //Test with 0, normally 1 (?) - break; - case "VARCHAR": - objectIDCol = 1043; - typeModifier = Integer.parseInt(head[2]); - dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize - formatCode = 0; - //dataTypeSize = 4; - //formatCode = 1; - break; - case "SMALLINT": - dataTypeSize = 2; - formatCode = 1; - break; - case "TINYINT": - dataTypeSize = 1; - formatCode = 1; - break; - case "TIMESTAMP": - break; - case "TIME": - break; - case "FILE": - case "IMAGE": - case "SOUND": - case "VIDEO": - break; - } - //rowDescription - //communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); - Object col[] = {fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode}; - valuesPerCol.add(col); - } - communicationHandler.sendParseBindComplete(); - communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); - //sendData - //communicationHandler.sendDataRow(data); - communicationHandler.sendDataRow2(data); - - rowsAffected = data.size(); - communicationHandler.sendCommandCompleteSelect(rowsAffected); - - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - } - - + case "SELECT" : //SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) //1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I //1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I @@ -523,6 +87,18 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... (result: 1,2,3,3,3,3) 1: ParseComplete indicator 2: BindComplete indicator +T: RowDescription - specifies the number of fields in a row (can be 0) - then for each field: + field name (string), lolid + ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 + attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 + ObjectID of fields data type (Int32), 1 + data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 + type modifier (meaning of modifier is type-specific) (see pg_attribute.atttypmod) (Int32), 4 + Format code used for the field (zero(text) or one(binary)) --> if rowDescription is returned from statement variant of DESCRIBE: format code not yet known (always zero) (Int16) + +D: DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: + length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), + value of the col (in format indicated by associated format code) T: RowDescription - specifies the number of fields in a row (can be 0) (as message content!!) - then for each field: field name (string), lolid ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 --> kompliziert diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 1669c55aad55adff07057c3cd6af52918d72bd8b..c828421d620b6601b6bb2b4c5763d7548b28564e 100644 GIT binary patch literal 5247 zcmb7I{chXH5$B=B0X6Ow3Jmm*sYE7iCq`2T?wu{$jT*=DNpjM=qA*tEO4>8Et1OpR zbj7_*fxbukV*L$2B+B0*AWGuS&dhJVm*I;IdO>Y7TUa%oINIIb`SaH9_UDvYl7?rU_Q`qwWD5$HC@*y))0C|IoGA;i!v%>M z6pF+UY9?Y%#*!FYi8W_f;ki{#>2ZrvGjelbC2JY0)LAvm+?u^g90b&L0$5CFY8>{d z({IqxVZYOFF_TZ7!MpC|fIc1edWYwO&PkuTJ!*H)k2`}-_ZG1p~dfz!eZjpqw z;1~I2W*Gt0RBTBZ=Vt3mHuut3G{QRnPiHbxBNYLf9%o`KX>4w!)j&iuX{Rb>kET#C zW|a~(RZh74(JBsV{s}iWVCQRQ1WO0ADwu+Jh(D==<t z?z#h|4|Jop2KXkFrsu;0}t7Ly;R7}u< zt=5wwCcosgZaRwGmlk!0TncEKj+-S<<`jk}?RVX+nKjNtCJBNdPX|ebH&arsm513V z$a-%&gL`qesT?BfIoCKon1f^BW}!q%C0J zhN=`pnMM<=YP@(4r|bch44Mq6MiPcw&%Fo$6v3={#e429rdui$qOO)#7y^Q&3G_z} zAJArRvu=c3@oKTrYpmAFd?|M#bFjI}kpQI;`HzRlEWg+ujHTl}DJ-xacfsZ0^y*Es zwcVnfng_zL*a$8G!jt#<(5^+zJC>ay&N=Z9sIgsBF%01~S}kth)gE4WO!ac_le*Wv z%`#KTP+k2*$;F+{L#*Ui-XMSDRj-f>!&VACBlJ_J9ArcC2Mw zr5~ly#40tEPe*56CR;AA%}5jfP9bY@&X)P+H(|}Gak4COezVCwx-!t+pG!){5b6Zs7VrmPLDv*v7$uAIZNAr$|;s_L!Cl7lotyph9Z^a-y*TDq>fCC&gr2+yz!2OlYO^Hq}S

jJ_XUjJmkL(DBo#OEt4 zAK~*IKKXTm`ycq%H+|fGzs~4SIiqq)=WM>xa6Q;;UK9go|Hm`>+woDGj;%s~Y=Xt} zxi`HIP6)jLbEq$qB_?wJRTKQ^i1_{;-}8%(3E%WBU64m7{5#j5 zzUk-BZ$bDYAe^1F2bA-s(_Z%ji((EBF<$5EQN_1%FPr#bwrlv0LHg~5w=}X>8hM#2 zVaW60;?&q5Gievg=l7(L{rt5l^fOYZgV5f4eu=T4pO-Qb*yaj7oiP>5`!Z&UH*e0X z;9HyDmIbG*H(O=dU#1VOYSKd`shDbM#5scAq<)F!sWJCKJsC*JB}e}ijPCZXO2L}6B8I9gT??Tj z9Go%Myq60US+PX9?#I3R-MF`1lTnD>t9$1CUC)&3?3kUpW2?|o@p(~4KM0Mneu^RE zR7B3$1rK?>3^T`6e)#*56dK`#M@(Ly`!MFv3}?&(f($vv=^oBWB@4u3rVdiPp}_g= zheq=s+yAT~;H{~QtaPvj7z`#nwx5|uBt0Bk%ruBHYoQS&YxEH2S=+v5fKuLL%S%x; zqKCY>SEE@u^S7cbJbchD-f*EiwME7+-5xt^1Ff0oFPtKQ_Pl=L&L0&=Vbqc6dSLNp zpbkC^2PQWAL}^Jk#^S(_Nm=sCx}nl>hNPNj7IXBCnd02Ttr7gD2Y(vI*HLpY8*8t()Ei5mPy4{rhR#wb}dmXXUQ%!w=Ye%pYZ F{tq_&D2f08 delta 1793 zcmb7E&ubGw6sFb^4d^DO)>YbxTxz|PG3zV~C^`+n&kXWmr?mmI<@ z+$4-xv`Lx3mwUf!q$XV6UP#)_O_vLFhukHYQGqWIK`c(1S4nMy3MmGsXQC#aupL}; zSUGNTJ#GuS+!j=yEKUC9y1;~fTE0o?qaAa#pN-fWhJ3qwMLtiC&39PguII-v zY$nisw20!#;TB~k#UQu{I>mogdoB(14%x8J89cMe`?sVx9cv?#wzc?DL> zcG<*&O2aU4E|2p_zd)-tVMuLea(L4+tz2$)DwmB!Q5M{07TP3G-W$YGl(~6)8i)+z z>cvWVwRB^(RDo44tY7Kje3X2xCC+y-`F|h`qYBl$b-UxK3VwW-^5@X8$*}ryE8y-K z!oRXT617$Dv+UJTr@Hg%E#&=!0|B={3BKb5iwsj&Dwv`59j5=$c@Hj=a z*lrPp?k1Kz(Eznp)d%HT- Date: Thu, 22 Sep 2022 11:08:55 +0200 Subject: [PATCH 23/57] (forgot to add) not working vs of psql interface, pushing because of exception while starting polypheny --- .../polypheny/db/postgresql/PGInterface.java | 4 + ...GInterfaceInboundCommunicationHandler.java | 38 +-- .../db/postgresql/PGInterfaceMessage.java | 4 +- .../postgresql/PGInterfaceQueryHandler.java | 236 +++++++++++++++++- .../postgresql/PGInterfaceServerWriter.java | 127 +++++++++- 5 files changed, 363 insertions(+), 46 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 02ff016855..0dd53e41ae 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -91,6 +91,10 @@ public PGInterface(TransactionManager transactionManager, Authenticator authenti this.transactionManager = transactionManager; } + public static TransactionManager getInstance() { + return transactionManager; + } //getTransactionManager + @Override public void run() { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 1ac23726d6..d905e543f6 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; public class PGInterfaceInboundCommunicationHandler { String type; @@ -70,7 +71,7 @@ public void startUpPhase() { ctx.writeAndFlush(authenticationOkWriter.writeOnByteBuf()); //server_version (Parameter Status message) - PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version§14", 4, true); + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter("ss", parameterStatusServerVs, ctx); ctx.writeAndFlush(parameterStatusServerVsWriter.writeOnByteBuf()); @@ -85,36 +86,8 @@ public void simpleQueryPhase() { public void extendedQueryPhase(String incomingMsg) { if (incomingMsg.substring(2,5).equals("SET")) { - //parseComplete - /* - PGInterfaceMessage parseComplete = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, false); - PGInterfaceServerWriter parseCompleteWriter = new PGInterfaceServerWriter("i", parseComplete, ctx); - ctx.writeAndFlush(parseCompleteWriter.writeOnByteBuf()); - - */ - - //ParameterStatus - client_encoding (ParameterStatus message) - String paramu = "SET"; - String paramValu = "UTF8"; - ByteBuf buffer3u = ctx.alloc().buffer(4+paramu.length()+10); - buffer3u.writeByte('1'); - buffer3u.writeInt(4); // size excluding char - //buffer3u.writeBytes(paramu.getBytes(StandardCharsets.UTF_8)); - //buffer3u.writeBytes(paramValu.getBytes(StandardCharsets.UTF_8)); - ctx.writeAndFlush(buffer3u); - - /* - //bindComplete - PGInterfaceMessage bindComplete = new PGInterfaceMessage(PGInterfaceHeaders.TWO, "0", 4, true); - PGInterfaceServerWriter bindCompleteWriter = new PGInterfaceServerWriter("i", bindComplete, ctx); - ctx.writeAndFlush(bindCompleteWriter.writeOnByteBuf()); - - */ - - ByteBuf buffer4u = ctx.alloc().buffer(4+10); - buffer4u.writeByte('2'); - buffer4u.writeInt(4); // size excluding char - ctx.writeAndFlush(buffer4u); + + sendParseBindComplete(); sendParseBindComplete(); @@ -128,7 +101,7 @@ public void extendedQueryPhase(String incomingMsg) { else { //Query does not have ";" at the end!! String query = extractQuery(incomingMsg); - PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this, transactionManager); + PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this); queryHandler.start(); } @@ -327,5 +300,6 @@ public void sendDataRow2(ArrayList data) { ctx.writeAndFlush(buf); + } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 725fc6376c..78737aee79 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -23,7 +23,7 @@ public class PGInterfaceMessage { private String msgBody; private int length; //default is 4, if a different length is mentioned in protocol, this is given private boolean defaultLength; - private final char delimiter = '§'; //for the subparts + private static final char delimiter = '§'; //for the subparts public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength) { this.header = header; @@ -112,7 +112,7 @@ public void setMsgBody(String msgBody) { * @return a string array with each requested part */ public String[] getMsgPart(int[] part) { - String subStrings[] = msgBody.split("§"); + String subStrings[] = msgBody.split(getDelimiter()); String result[] = new String[part.length]; for (int i=0; i<(part.length); i++) { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 23d9b31bca..c44804f899 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -17,30 +17,211 @@ package org.polypheny.db.postgresql; import io.netty.channel.ChannelHandlerContext; - -public class PGInterfaceQueryHandler { +import org.apache.commons.lang.ArrayUtils; +import org.polypheny.db.PolyResult; +import org.polypheny.db.algebra.AlgRoot; +import org.polypheny.db.algebra.constant.Kind; +import org.polypheny.db.algebra.type.AlgDataTypeField; +import org.polypheny.db.catalog.Catalog; +import org.polypheny.db.catalog.entity.*; +import org.polypheny.db.catalog.exceptions.*; +import org.polypheny.db.config.RuntimeConfig; +import org.polypheny.db.languages.QueryParameters; +import org.polypheny.db.nodes.Node; +import org.polypheny.db.processing.Processor; +import org.polypheny.db.processing.QueryProcessor; +import org.polypheny.db.transaction.*; +import java.util.ArrayList; +import java.util.List; + +public class PGInterfaceQueryHandler implements TransactionManager { String query; ChannelHandlerContext ctx; + PGInterfaceInboundCommunicationHandler communicationHandler; + private TransactionManager transactionManager; + int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) + List> rows; - public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx) { + public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler) { this.query = query; this.ctx = ctx; + this.communicationHandler = communicationHandler; + Object obj = new Object(); + this.transactionManager = PGInterface.getInstance(); + } + + public void start() { + sendQueryToPolypheny(); + + //is 2 times inside... delete here or in sendQueryToPolypheny + ArrayList data = null; + sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... } public void sendQueryToPolypheny() { String type = ""; //query type according to answer tags //get result from polypheny + Transaction transaction; + Statement statement = null; + PolyResult result; + ArrayList data = new ArrayList<>(); + + + + try { + //get transaction letze linie + transaction = transactionManager.startTransaction("pa", "APP", false, "Index Manager"); + statement = transaction.createStatement(); + } + catch (UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e) { + throw new RuntimeException( "Error while starting transaction", e ); + } + + + + //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) + //for loop zom dor alli catalogTables doregoh? - nei + Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); + Node sqlNode = sqlProcessor.parse(query); + QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); + if ( sqlNode.isA( Kind.DDL ) ) { + result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); + } else { + AlgRoot algRoot = sqlProcessor.translate( + statement, + sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, + new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds (emmer no???) + + //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) + final QueryProcessor processor = statement.getQueryProcessor(); + result = processor.prepareQuery(algRoot, true); + + } + + //get type information - from crud.java + //Type of ArrayList was DbColumn, but belongs to webUI (so I don't need it...) --> replaced it with string? + ArrayList header = new ArrayList<>(); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? + + //get actual result of query in array - from crud.java + rows = result.getRows(statement, -1); //-1 as size valid?? + data = computeResultData(rows, header, statement.getTransaction()); //computeResultData selber implementieren? --> das esch die aagehnigi ziile + //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) //handle result --> depending on query type, prepare answer message accordingly here (flush it) + sendResultToClient(type, data); + + } + + private ArrayList computeResultData(List> rows, ArrayList header, Transaction transaction) { + //ha es paar sache useglöscht... aber wahrschiinli muesmer de no meh lösche... + ArrayList data = new ArrayList<>(); + /* + for ( List row : rows ) { + String[] temp = new String[row.size()]; + int counter = 0; + for ( Object o : row ) { + if ( o == null ) { + temp[counter] = null; + } else { + switch ( header.get( counter ) ) { + case "TIMESTAMP": + break; + case "DATE": + break; + case "TIME": + break; + case "FILE": + case "IMAGE": + case "SOUND": + case "VIDEO": + break; + //fall through + default: + temp[counter] = o.toString(); + } + if ( header.get( counter ).endsWith( "ARRAY" ) ) { + + } + } + counter++; + } + data.add( temp ); + } + + */ + return data; + } + + + public void sendResultToClient(String type, ArrayList data) { switch (type) { case "INSERT": + //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) //INSERT oid rows (oid=0, rows = #rows inserted) //1....2....n....C....INSERT 0 1.Z....I + + //insert into table with several vals (but only 1 row) + /* + client: + P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B............D....P.E... .....S.... + + server: + 1....2....n....C....INSERT 0 1.Z....I + */ + + + communicationHandler.sendParseBindComplete(); + communicationHandler.sendCommandCompleteInsert(rowsAffected); + communicationHandler.sendReadyForQuery("I"); + break; - case "SELECT" : + case "CREATE TABLE": + //1....2....n....C....CREATE TABLE.Z....I + communicationHandler.sendParseBindComplete(); + communicationHandler.sendCommandCompleteCreateTable(); + communicationHandler.sendReadyForQuery("I"); + + break; + + case "SELECT" : //also CREATE TABLE AS + + if (data.isEmpty()) { + //noData + //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) + communicationHandler.sendParseBindComplete(); + communicationHandler.sendReadyForQuery("I"); + } + + else { + //data + + //rowDescription + String fieldName = ""; //get field name from query? + int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 + int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 + int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified + + int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt + //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types + int typeModifier = 0; //int32 --> meaning of modifier is type specific (pg_attribute.atttypmod) + int formatCode = 0; //int16 --> zero(text) or one(binary) --> if returned from describe, not yet known = 0 + + communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + + communicationHandler.sendDataRow(data); + + + + //rowsAffected = 2; //das fonktioniert met 0 ond 2 --> rein das schecke get kei fähler em frontend + communicationHandler.sendCommandCompleteSelect(data); + communicationHandler.sendParseBindComplete(); + communicationHandler.sendReadyForQuery("I"); + } + + //SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) //1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I //1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I @@ -79,6 +260,41 @@ public void sendQueryToPolypheny() { + @Override + public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin) { + return null; + } + + @Override + public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) { + return null; + } + + @Override + public Transaction startTransaction(String user, String database, boolean analyze, String origin) { + try { + return transactionManager.startTransaction( "pa", "APP", true, "Test Helper" ); + } catch ( GenericCatalogException | UnknownUserException | UnknownDatabaseException | UnknownSchemaException e ) { + throw new RuntimeException( "Error while starting transaction", e ); + } + } + + @Override + public Transaction startTransaction(String user, String database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) throws UnknownUserException, UnknownDatabaseException, UnknownSchemaException { + return null; + } + + @Override + public void removeTransaction(PolyXid xid) { + + } + + @Override + public boolean isActive(PolyXid xid) { + return false; + } + + //Example of server answer to simple select query (from real server) /* 1....2....T......lolid...@...............D..........1D..........2D..........3D..........3D..........3D..........3C... @@ -89,11 +305,19 @@ public void sendQueryToPolypheny() { 2: BindComplete indicator T: RowDescription - specifies the number of fields in a row (can be 0) - then for each field: field name (string), lolid - ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 + ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 --> kompliziert attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 ObjectID of fields data type (Int32), 1 - data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 + + Specifies the object ID of the parameter data type. Placing a zero here is equivalent to leaving the type unspecified. + --> apparently specified in parse message (at the end, if 0, then unspecified...) + + data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 --> polypheny website, typedokumentation, mit länge + real and double in polypheny s gliiche --> luege was postgres macht, mind. länge aaluege --> postgresqlStore schauen welche grössen wie gemappt + gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) + type modifier (meaning of modifier is type-specific) (see pg_attribute.atttypmod) (Int32), 4 + Format code used for the field (zero(text) or one(binary)) --> if rowDescription is returned from statement variant of DESCRIBE: format code not yet known (always zero) (Int16) D: DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index c4cec49670..952e0dae44 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -77,15 +77,17 @@ public ByteBuf writeOnByteBuf() { body = Integer.parseInt(pgMsg.getMsgBody()); } catch (NumberFormatException e) { e.printStackTrace(); - //TODO: send error-message to client + //TODO(FF): send error-message to client } buffer.writeInt(body); break; - case "ss": //write two strings (tag and message) + writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + + /* buffer.writeByte(pgMsg.getHeaderChar()); if (pgMsg.isDefaultLength()) { buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 1); @@ -93,17 +95,70 @@ public ByteBuf writeOnByteBuf() { else { buffer.writeInt(pgMsg.getLength()); } - int[] idx = new int[]{0,1}; - String[] msgParts = pgMsg.getMsgPart(idx); + int[] twoPartsIdx = new int[]{0,1}; + String[] msgParts = pgMsg.getMsgPart(twoPartsIdx); buffer.writeBytes(msgParts[0].getBytes(StandardCharsets.US_ASCII)); buffer.writeByte(0); buffer.writeBytes(msgParts[1].getBytes(StandardCharsets.US_ASCII)); buffer.writeByte(0); + + */ + break; + + + case "sss": + //write 3 strings, example, tag with three components + writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + /* + buffer.writeByte(pgMsg.getHeaderChar()); + if (pgMsg.isDefaultLength()) { + buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 2); + } + else { + buffer.writeInt(pgMsg.getLength()); + } + int[] threePartsIdx = new int[]{0,1,2}; + String[] threeMsgParts = pgMsg.getMsgPart(threePartsIdx); + buffer.writeBytes(threeMsgParts[0].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + buffer.writeBytes(threeMsgParts[1].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + buffer.writeBytes(threeMsgParts[2].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + + */ + break; + + case "ssm": + //several strings modified --> ideally only use this in the future... break; + case "dr": + //send dataRow + buffer.writeByte(pgMsg.getHeaderChar()); + + int[] idxDataRow = new int[3]; + String[] dataRows = pgMsg.getMsgPart(idxDataRow); + + int nbrFollowingColVal = 0; + int colValLenght = 0; + try { + nbrFollowingColVal = Integer.parseInt(dataRows[0]); + colValLenght = Integer.parseInt(dataRows[1]); + } catch (NumberFormatException e) { + e.printStackTrace(); + //TODO(FF): send error-message to client + } + + //dont check for length, bcs is always the same for dataRow + buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 2); + + buffer.writeShort(nbrFollowingColVal); + buffer.writeByte(0); + buffer.writeInt(colValLenght); + buffer.writeByte(0); + buffer.writeBytes(dataRows[2].getBytes(StandardCharsets.UTF_8)); - case "cc": - //two chars? break; @@ -144,6 +199,66 @@ public ByteBuf writeIntHeaderOnByteBuf(char header) { return buffer; } + public ByteBuf writeRowDescription(String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode) { + //I don't check for length, bcs rowDescription is always the same + ByteBuf buffer = ctx.alloc().buffer(); + + //bytebuf.writeInt(int value) = 32-bit int + //bytebuf.writeShort(int value) = 16-bit short integer; + + buffer.writeByte(pgMsg.getHeaderChar()); + buffer.writeInt(pgMsg.getLength() + fieldName.length() + 6); + + buffer.writeBytes(fieldName.getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + buffer.writeInt(objectIDTable); + buffer.writeByte(0); + buffer.writeShort(attributeNoCol); + buffer.writeByte(0); + buffer.writeInt(objectIDCol); + buffer.writeByte(0); + buffer.writeShort(dataTypeSize); + buffer.writeByte(0); + buffer.writeInt(typeModifier); + buffer.writeByte(0); + buffer.writeShort(formatCode); + + return buffer; + } + + public ByteBuf writeSeveralStrings(int nbrStrings) { + ByteBuf buffer = ctx.alloc().buffer(); + + buffer.writeByte(pgMsg.getHeaderChar()); + if (pgMsg.isDefaultLength()) { + buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - (nbrStrings -1)); + } + else { + buffer.writeInt(pgMsg.getLength()); + } + + int[] idx = new int[nbrStrings]; + String[] msgParts = pgMsg.getMsgPart(idx); + + for (int i = 0; i < nbrStrings; i++) { + buffer.writeBytes(msgParts[i].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + } + + return buffer; + } + + public ByteBuf writeIntHeaderOnByteBuf(char header) { + //write a int header... ("i" (for char headers) doesn't work TODO(FF): Figure out a way to do this with case "i" + //since headers with numbers are always indicators, don't I don't check for not standard lengths + ByteBuf buffer = ctx.alloc().buffer(); + + buffer.writeByte(header); + buffer.writeInt(4); // size excluding char + + return buffer; + } + public ByteBuf writeRowDescription(ArrayList valuesPerCol) { //I don't check for length, bcs rowDescription is always the same ByteBuf buffer = ctx.alloc().buffer(); From 55d1fb134a974b9fcf798e658586d9865dc497f6 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 22 Sep 2022 13:26:59 +0200 Subject: [PATCH 24/57] now it works again as far as implemented should (still not works as a whole). Exception on startup remains --- .../polypheny/db/postgresql/PGInterface.java | 5 --- ...GInterfaceInboundCommunicationHandler.java | 10 +++-- .../postgresql/PGInterfaceQueryHandler.java | 41 ++---------------- .../postgresql/PGInterfaceServerHandler.java | Bin 5247 -> 5362 bytes .../postgresql/PGInterfaceServerWriter.java | 4 +- 5 files changed, 13 insertions(+), 47 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 0dd53e41ae..4bd3968642 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -91,10 +91,6 @@ public PGInterface(TransactionManager transactionManager, Authenticator authenti this.transactionManager = transactionManager; } - public static TransactionManager getInstance() { - return transactionManager; - } //getTransactionManager - @Override public void run() { @@ -115,7 +111,6 @@ public void initChannel(SocketChannel socketChannel) throws Exception { //Handler channelPipeline.addLast("handler", new PGInterfaceServerHandler(transactionManager)); - } }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index d905e543f6..516f425242 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -18,6 +18,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; +import org.polypheny.db.transaction.TransactionManager; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -26,11 +27,13 @@ public class PGInterfaceInboundCommunicationHandler { String type; PGInterfaceClient client; ChannelHandlerContext ctx; + TransactionManager transactionManager; - public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client) { + public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client, TransactionManager transactionManager) { this.type = type; this.client = client; this.ctx = client.getCtx(); + this.transactionManager = transactionManager; } //ich mues ergendwie identifiziere wele client dases esch... oder muesich öberhaupt speichere was fören phase das de client denne esch... @@ -71,7 +74,8 @@ public void startUpPhase() { ctx.writeAndFlush(authenticationOkWriter.writeOnByteBuf()); //server_version (Parameter Status message) - PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version§14", 4, true); + //PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter("ss", parameterStatusServerVs, ctx); ctx.writeAndFlush(parameterStatusServerVsWriter.writeOnByteBuf()); @@ -101,7 +105,7 @@ public void extendedQueryPhase(String incomingMsg) { else { //Query does not have ";" at the end!! String query = extractQuery(incomingMsg); - PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this); + PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this, transactionManager); queryHandler.start(); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index c44804f899..2d0b97d572 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -34,7 +34,7 @@ import java.util.ArrayList; import java.util.List; -public class PGInterfaceQueryHandler implements TransactionManager { +public class PGInterfaceQueryHandler{ String query; ChannelHandlerContext ctx; PGInterfaceInboundCommunicationHandler communicationHandler; @@ -42,12 +42,12 @@ public class PGInterfaceQueryHandler implements TransactionManager { int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) List> rows; - public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler) { + public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager) { this.query = query; this.ctx = ctx; this.communicationHandler = communicationHandler; Object obj = new Object(); - this.transactionManager = PGInterface.getInstance(); + this.transactionManager = transactionManager; } public void start() { @@ -86,6 +86,7 @@ public void sendQueryToPolypheny() { QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); if ( sqlNode.isA( Kind.DDL ) ) { result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); + // exception: java.lang.RuntimeException: No primary key has been provided! } else { AlgRoot algRoot = sqlProcessor.translate( statement, @@ -260,40 +261,6 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... - @Override - public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin) { - return null; - } - - @Override - public Transaction startTransaction(CatalogUser user, CatalogSchema defaultSchema, CatalogDatabase database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) { - return null; - } - - @Override - public Transaction startTransaction(String user, String database, boolean analyze, String origin) { - try { - return transactionManager.startTransaction( "pa", "APP", true, "Test Helper" ); - } catch ( GenericCatalogException | UnknownUserException | UnknownDatabaseException | UnknownSchemaException e ) { - throw new RuntimeException( "Error while starting transaction", e ); - } - } - - @Override - public Transaction startTransaction(String user, String database, boolean analyze, String origin, Transaction.MultimediaFlavor flavor) throws UnknownUserException, UnknownDatabaseException, UnknownSchemaException { - return null; - } - - @Override - public void removeTransaction(PolyXid xid) { - - } - - @Override - public boolean isActive(PolyXid xid) { - return false; - } - //Example of server answer to simple select query (from real server) /* diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index c828421d620b6601b6bb2b4c5763d7548b28564e..47ee50a5849bb6da2f3b4dcce1973f50881795ac 100644 GIT binary patch delta 256 zcmeyb@kw*TRHn(-m}<;2a|`l|N)+;o()9}Rb1DlmQu8YHQj+vaiW2jR6O&6a^YipV z5NzMXyu|d>qRI1^LyRzm6_9j6Ra$d#DF8u1X;MyR^5nJ5lJOcu>C;rG25SUqF3HF& gMs^U?Xa!qr_D%K|R@=dtmUP@w7 XiZg^?JlUN&WOE=(3+v{WoSfVMC3`re diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 952e0dae44..9ffbdb347a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -85,7 +85,7 @@ public ByteBuf writeOnByteBuf() { case "ss": //write two strings (tag and message) - writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + buffer = writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution (switch case(?))?? /* buffer.writeByte(pgMsg.getHeaderChar()); @@ -108,7 +108,7 @@ public ByteBuf writeOnByteBuf() { case "sss": //write 3 strings, example, tag with three components - writeSeveralStrings(2); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? + buffer = writeSeveralStrings(3); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? /* buffer.writeByte(pgMsg.getHeaderChar()); if (pgMsg.isDefaultLength()) { From 8a1127f8d62e76e83f8e71624d38cced3cb9aaa1 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 28 Sep 2022 10:56:35 +0200 Subject: [PATCH 25/57] data from Polypheny is handled, and ready to be sent to the client, but not yet sent correctly to the client --- ...GInterfaceInboundCommunicationHandler.java | 1 + .../postgresql/PGInterfaceQueryHandler.java | 199 +++++++++++++++--- 2 files changed, 167 insertions(+), 33 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 516f425242..f072a88740 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -218,6 +218,7 @@ public void sendCommandCompleteSelect(int rowsSelected) { + public void sendRowDescription(int numberOfFields, ArrayList valuesPerCol) { //String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 2d0b97d572..385a49a97a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -31,6 +31,8 @@ import org.polypheny.db.processing.Processor; import org.polypheny.db.processing.QueryProcessor; import org.polypheny.db.transaction.*; + +import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.List; @@ -54,8 +56,9 @@ public void start() { sendQueryToPolypheny(); //is 2 times inside... delete here or in sendQueryToPolypheny - ArrayList data = null; - sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... + //ArrayList data = null; //chonnt vo sendQueryToPolypheny zrogg, ond goht etzt es insert ine... aber + //aber ebe, esch dopplet wie onde + //sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... } public void sendQueryToPolypheny() { @@ -65,6 +68,7 @@ public void sendQueryToPolypheny() { Statement statement = null; PolyResult result; ArrayList data = new ArrayList<>(); + ArrayList header = new ArrayList<>(); @@ -91,7 +95,7 @@ public void sendQueryToPolypheny() { AlgRoot algRoot = sqlProcessor.translate( statement, sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, - new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds (emmer no???) + new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds: org.polypheny.db.runtime.PolyphenyDbContextException: From line 1, column 13 to line 1, column 15: Table 'lol' not found //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) final QueryProcessor processor = statement.getQueryProcessor(); @@ -101,32 +105,105 @@ public void sendQueryToPolypheny() { //get type information - from crud.java //Type of ArrayList was DbColumn, but belongs to webUI (so I don't need it...) --> replaced it with string? - ArrayList header = new ArrayList<>(); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? - + //ArrayList header = getHeader(result, query); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? +header = getHeader(result); + //statement.executeUpdate("SELECT empid FROM public.emps"); + //get actual result of query in array - from crud.java rows = result.getRows(statement, -1); //-1 as size valid?? - data = computeResultData(rows, header, statement.getTransaction()); //computeResultData selber implementieren? --> das esch die aagehnigi ziile + data = computeResultData(rows, header); //, statement.getTransaction() + //type = result.getStatementType().name(); + type = result.getStatementType().toString(); //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) //handle result --> depending on query type, prepare answer message accordingly here (flush it) - sendResultToClient(type, data); + sendResultToClient(type, data, header); + + } + + /** + * gets the information for the header + * @param result the polyresult the additional information is needed + * @return a list with array, where: + * - array[0] = columnName + * - array[1] = columnType + */ + private ArrayList getHeader(PolyResult result) { //(request = query) + ArrayList header = new ArrayList<>(); + for ( AlgDataTypeField metaData : result.getRowType().getFieldList() ) { + String columnName = metaData.getName(); + //final String name = metaData.getName(); + String dataType = metaData.getType().getPolyType().getTypeName(); //INTEGER, VARCHAR --> aber ergendwie ohnis (20) em header?? + int precision = metaData.getType().getPrecision(); //sizeVarChar + boolean nullable = metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1); + //Integer precision = metaData.getType().getPrecision(); + + //For each column: If it should be filtered empty string if it should not be filtered + /* + String filter = ""; + if ( request.filter != null && request.filter.containsKey( columnName ) ) { + filter = request.filter.get( columnName ); + } + */ + + //For each column: If and how it should be sorted + /* + SortState sort; + if ( request.sortState != null && request.sortState.containsKey( columnName ) ) { + sort = request.sortState.get( columnName ); + } else { + sort = new SortState(); + } + */ + + /* + DbColumn dbCol = new DbColumn( + metaData.getName(), + metaData.getType().getPolyType().getTypeName(), + metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1), + metaData.getType().getPrecision(), + sort, + filter ); + */ + + //bruuch ich ned wörklech? + /* + // Get column default values + if ( catalogTable != null ) { + try { + if ( catalog.checkIfExistsColumn( catalogTable.id, columnName ) ) { + CatalogColumn catalogColumn = catalog.getColumn( catalogTable.id, columnName ); + if ( catalogColumn.defaultValue != null ) { + dbCol.defaultValue = catalogColumn.defaultValue.value; + } + } + } catch ( UnknownColumnException e ) { + log.error( "Caught exception", e ); + } + } + */ + //header.add( dbCol ); + header.add(new String[]{columnName, dataType, String.valueOf(precision)}); + } + return header; } - private ArrayList computeResultData(List> rows, ArrayList header, Transaction transaction) { + private ArrayList computeResultData(List> rows, ArrayList header) { + //TODO(FF): bruuch ich de header do öberhaupt? (aso em momänt ned... ) --> hanich sache wonich de chönnt/müesst bruuche? //ha es paar sache useglöscht... aber wahrschiinli muesmer de no meh lösche... ArrayList data = new ArrayList<>(); - /* + for ( List row : rows ) { - String[] temp = new String[row.size()]; + String[] temp = new String[row.size()]; //temp esch au 100 --> vo resultat sälber... int counter = 0; for ( Object o : row ) { if ( o == null ) { temp[counter] = null; } else { - switch ( header.get( counter ) ) { + switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry case "TIMESTAMP": break; case "DATE": @@ -140,23 +217,23 @@ private ArrayList computeResultData(List> rows, ArrayList break; //fall through default: - temp[counter] = o.toString(); + temp[counter] = o.toString(); //em momänt werd do no 100 aaghänkt?? --> s 1. resultat vo rows } - if ( header.get( counter ).endsWith( "ARRAY" ) ) { + if ( header.get( counter )[0].endsWith( "ARRAY" ) ) { } } - counter++; + counter++; //was macht gnau de counter? (esch etzt 1, chonnt add), rows size = 4 } data.add( temp ); } - */ + return data; } - public void sendResultToClient(String type, ArrayList data) { + public void sendResultToClient(String type, ArrayList data, ArrayList header) { switch (type) { case "INSERT": //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) @@ -180,6 +257,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "CREATE TABLE": + //TODO(FF) do things in polypheny (?) //1....2....n....C....CREATE TABLE.Z....I communicationHandler.sendParseBindComplete(); communicationHandler.sendCommandCompleteCreateTable(); @@ -188,8 +266,23 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "SELECT" : //also CREATE TABLE AS + int lol = 4; + ArrayList valuesPerCol = new ArrayList(); + + String fieldName = ""; //get field name from query? momentan no de einzig val em header o + int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 o + int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 o + int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified o + int formatCode = 0; //int16 --> zero(text-inhalt (values)) or one(integer) --> if returned from describe, not yet known = 0 o. + int typeModifier = -1; //The value will generally be -1 for types that do not need atttypmod. --> type specific data (supplied at table creation time o - if (data.isEmpty()) { + int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt + //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types + //For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative + // o. + + + if (lol == 3) { //data.isEmpty() //noData //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) communicationHandler.sendParseBindComplete(); @@ -198,24 +291,64 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... else { //data - - //rowDescription - String fieldName = ""; //get field name from query? - int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 - int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 - int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified - - int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt - //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types - int typeModifier = 0; //int32 --> meaning of modifier is type specific (pg_attribute.atttypmod) - int formatCode = 0; //int16 --> zero(text) or one(binary) --> if returned from describe, not yet known = 0 - - communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); - + //for loop mache för jedi reihe? --> nocheluege wies gmacht werd em ächte psql met mehrere cols & reihe + int numberOfFields = header.size(); + + for (String[] head : header) { + + fieldName = head[0]; + + //TODO(FF): Implement the rest of the cases + switch (head[1]) { + case "BIGINT": + case "DOUBLE": + dataTypeSize = 8; //8 bytes signed + formatCode = 1; //TODO(FF): esch das rechtig? wel es heisst e de doc darstellig vo Integer... + break; + case "BOOLEAN": + dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? + break; + case "DATE": + break; + case "DECIMAL": + break; + case "REAL": + case "INTEGER": + dataTypeSize = 4; + formatCode = 1; + break; + case "VARCHAR": + dataTypeSize = Integer.parseInt(head[2]); + formatCode = 0; + break; + case "SMALLINT": + dataTypeSize = 2; + formatCode = 1; + break; + case "TINYINT": + dataTypeSize = 1; + formatCode = 1; + break; + case "TIMESTAMP": + break; + case "TIME": + break; + case "FILE": + case "IMAGE": + case "SOUND": + case "VIDEO": + break; + } + //rowDescription + //communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + Object col[] = {fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode}; + valuesPerCol.add(col); + } + communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); + //sendData communicationHandler.sendDataRow(data); - //rowsAffected = 2; //das fonktioniert met 0 ond 2 --> rein das schecke get kei fähler em frontend communicationHandler.sendCommandCompleteSelect(data); communicationHandler.sendParseBindComplete(); @@ -270,7 +403,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... (result: 1,2,3,3,3,3) 1: ParseComplete indicator 2: BindComplete indicator -T: RowDescription - specifies the number of fields in a row (can be 0) - then for each field: +T: RowDescription - specifies the number of fields in a row (can be 0) (as message content!!) - then for each field: field name (string), lolid ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 --> kompliziert attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 From a6f60b8c3b7450fe54d9d9c85a99ae02bb7a03a6 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 29 Sep 2022 17:45:36 +0200 Subject: [PATCH 26/57] answer should now be sent correctly (it is not, but want to commit before debugging) --- .../postgresql/PGInterfaceQueryHandler.java | 23 +++++------ .../postgresql/PGInterfaceServerWriter.java | 39 ++++++++++--------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 385a49a97a..82a484f466 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -54,11 +54,6 @@ public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInter public void start() { sendQueryToPolypheny(); - - //is 2 times inside... delete here or in sendQueryToPolypheny - //ArrayList data = null; //chonnt vo sendQueryToPolypheny zrogg, ond goht etzt es insert ine... aber - //aber ebe, esch dopplet wie onde - //sendResultToClient("INSERT", data); //TODO(FF): rechtig ufrüefe... } public void sendQueryToPolypheny() { @@ -86,16 +81,17 @@ public void sendQueryToPolypheny() { //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) //for loop zom dor alli catalogTables doregoh? - nei Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); - Node sqlNode = sqlProcessor.parse(query); + Node sqlNode = sqlProcessor.parse(query); //go gehts fähler: (see diary) QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); if ( sqlNode.isA( Kind.DDL ) ) { result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); + //TODO(FF): ene try catch block... || evtl no committe (söscht werds ned aazeigt em ui (aso allgemein, wie werds denn aazeigt em ui?) // exception: java.lang.RuntimeException: No primary key has been provided! } else { AlgRoot algRoot = sqlProcessor.translate( statement, sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, - new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //TODO: do nochhär crasheds: org.polypheny.db.runtime.PolyphenyDbContextException: From line 1, column 13 to line 1, column 15: Table 'lol' not found + new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) final QueryProcessor processor = statement.getQueryProcessor(); @@ -203,7 +199,7 @@ private ArrayList computeResultData(List> rows, ArrayList if ( o == null ) { temp[counter] = null; } else { - switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry + switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry (only handling "standard" returns case "TIMESTAMP": break; case "DATE": @@ -217,7 +213,7 @@ private ArrayList computeResultData(List> rows, ArrayList break; //fall through default: - temp[counter] = o.toString(); //em momänt werd do no 100 aaghänkt?? --> s 1. resultat vo rows + temp[counter] = o.toString(); } if ( header.get( counter )[0].endsWith( "ARRAY" ) ) { @@ -282,7 +278,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... // o. - if (lol == 3) { //data.isEmpty() + if (lol == 3) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... //noData //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) communicationHandler.sendParseBindComplete(); @@ -318,7 +314,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... formatCode = 1; break; case "VARCHAR": - dataTypeSize = Integer.parseInt(head[2]); + dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize formatCode = 0; break; case "SMALLINT": @@ -348,9 +344,8 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... //sendData communicationHandler.sendDataRow(data); - - //rowsAffected = 2; //das fonktioniert met 0 ond 2 --> rein das schecke get kei fähler em frontend - communicationHandler.sendCommandCompleteSelect(data); + rowsAffected = data.size(); + communicationHandler.sendCommandCompleteSelect(rowsAffected); communicationHandler.sendParseBindComplete(); communicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 9ffbdb347a..780a4de943 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -137,31 +137,34 @@ public ByteBuf writeOnByteBuf() { //send dataRow buffer.writeByte(pgMsg.getHeaderChar()); - int[] idxDataRow = new int[3]; - String[] dataRows = pgMsg.getMsgPart(idxDataRow); + int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("g","").length())/2; - int nbrFollowingColVal = 0; - int colValLenght = 0; - try { - nbrFollowingColVal = Integer.parseInt(dataRows[0]); - colValLenght = Integer.parseInt(dataRows[1]); - } catch (NumberFormatException e) { - e.printStackTrace(); - //TODO(FF): send error-message to client + //should generally be not the default length, but also works with default length & length = 4 + if (pgMsg.isDefaultLength()) { + //data row does not include msg-length bytes in msg length + buffer.writeInt(pgMsg.getLength()- 4 - (nbrCol*2)); + } + else { + buffer.writeInt(pgMsg.getLength()); } - //dont check for length, bcs is always the same for dataRow - buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 2); + buffer.writeShort(nbrCol); - buffer.writeShort(nbrFollowingColVal); - buffer.writeByte(0); - buffer.writeInt(colValLenght); - buffer.writeByte(0); - buffer.writeBytes(dataRows[2].getBytes(StandardCharsets.UTF_8)); + //cut the last § (it is at the end) from the msgBody and set it as the new msgBody + String temp = pgMsg.getMsgBody().substring(0, pgMsg.getMsgBody().length() - 1); + pgMsg.setMsgBody(temp); - break; + int[] idx = new int[(nbrCol*2)]; + String[] msgParts = pgMsg.getMsgPart(idx); + for (int i = 0; i < (nbrCol*2); i++) { + buffer.writeInt(Integer.parseInt(msgParts[i])); + buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); + buffer.writeByte(0); + i++; + } + break; } return buffer; } From 8fef091e7de79f6b6f75ac4ae34e3a2cf93f4c0f Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 29 Sep 2022 18:08:24 +0200 Subject: [PATCH 27/57] it now sends the message correctly(?), but doesnt close the connection... --- .../org/polypheny/db/postgresql/PGInterfaceServerWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 780a4de943..6c74c27b1b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -137,7 +137,7 @@ public ByteBuf writeOnByteBuf() { //send dataRow buffer.writeByte(pgMsg.getHeaderChar()); - int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("g","").length())/2; + int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("§","").length())/2; //should generally be not the default length, but also works with default length & length = 4 if (pgMsg.isDefaultLength()) { From 0d195aa74bcad0e0e8b5a2683c76005990835c18 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 5 Oct 2022 08:55:49 +0200 Subject: [PATCH 28/57] some code cleanup and fixes, but the client still doesn't accept the select response --- .../org/polypheny/db/postgresql/Decoder.java | 73 ------------------- .../db/postgresql/PGInterfaceClient.java | 43 ----------- .../PGInterfaceHeaderPrepender.java | 38 ---------- .../db/postgresql/PGInterfaceServer.java | 20 ----- .../postgresql/PGInterfaceServerReader.java | 30 -------- 5 files changed, 204 deletions(-) delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java delete mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java deleted file mode 100644 index e841c88663..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/Decoder.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.polypheny.db.postgresql; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import org.polypheny.db.StatusService; - -import java.util.List; - -public class Decoder extends LengthFieldBasedFrameDecoder { - - private static final int HEADER_SIZE = 1; - private byte type; - private int length; - private String msgBody; - private ChannelHandlerContext ctx; - private ByteBuf in; - private List out; - - - public Decoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) throws Exception { - super(maxFrameLength, lengthFieldOffset, lengthFieldLength, - lengthAdjustment, initialBytesToStrip); - Object decoded = decode(ctx, in); - ctx.write(decoded); - } - - - /* - @Override - protected void decode (ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - this.ctx = ctx; - this.in = in; - Object decoded = decode(ctx, in); - if (decoded != null) { - out.add(decoded); - } - - } - - @Override - protected Object decode (ChannelHandlerContext ctx, ByteBuf in) throws Exception { - if (in == null) { - return null; - } - if (in.readableBytes() < HEADER_SIZE) { - throw new Exception("Only Header"); - } - - - type = in.readByte(); - length = in.readByte(); - - if(in.readableBytes() < length) { - //throw new Exception("The message is too short"); - } - - ByteBuf buf = in.readBytes(length); - byte[] b = new byte[buf.readableBytes()]; - buf.readBytes(b); - - msgBody = new String(b, "UTF-8"); - Message msg = new Message(type, length, msgBody); - - //StatusService.printInfo(String.format("decoded message:" + msgBody)); - - return msg; - - - } - - */ -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java deleted file mode 100644 index abe97739a5..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceClient.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -import io.netty.channel.ChannelHandlerContext; - -import java.net.InetSocketAddress; - -public class PGInterfaceClient { - public static ChannelHandlerContext ctx = null; - public String state; - - public PGInterfaceClient (ChannelHandlerContext ctx) { - this.ctx = ctx; - //int port = ((InetSocketAddress)ctx.channel().remoteAddress()).getPort(); - } - - public static ChannelHandlerContext getCtx() { - return ctx; - } - - public void setState(String state) { - this.state = state; - } - - public String getState() { - return state; - } -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java deleted file mode 100644 index a0ce4b5b25..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaderPrepender.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; - -import java.nio.charset.StandardCharsets; - -public class PGInterfaceHeaderPrepender extends MessageToByteEncoder { - String header = "R"; //Authentication request header - //public HeaderPrepender() { } - - @Override - protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { - ByteBuf headerBuf = Unpooled.copiedBuffer(header.getBytes(StandardCharsets.UTF_8)); - out.writeBytes(headerBuf); - //out.writeBytes(msg); - } - - -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java deleted file mode 100644 index 9f0dfd646e..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServer.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -public class PGInterfaceServer { -} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java deleted file mode 100644 index 5aabc4937f..0000000000 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerReader.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2019-2022 The Polypheny Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.polypheny.db.postgresql; - -public class PGInterfaceServerReader { - - public PGInterfaceServerReader(String wholeMsg, PGInterfaceServer server) { - - switch (wholeMsg.substring(0, 1)) { - case "C": - PGInterfaceMessage msg = null; - msg.setHeader(PGInterfaceHeaders.C); - //msg.setMsgBody(); - } - } -} From b67f0168e0a8ef47558cd55c876a3ca9f50ccba6 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 5 Oct 2022 08:56:58 +0200 Subject: [PATCH 29/57] forgot to add in the commit before (missed the deleted files) --- .../polypheny/db/postgresql/PGInterface.java | 2 +- ...GInterfaceInboundCommunicationHandler.java | 47 ++++++------- .../postgresql/PGInterfaceQueryHandler.java | 3 +- .../postgresql/PGInterfaceServerHandler.java | Bin 5362 -> 4324 bytes .../postgresql/PGInterfaceServerWriter.java | 66 +++++++++++++----- 5 files changed, 76 insertions(+), 42 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 4bd3968642..31c907ea3e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -94,7 +94,6 @@ public PGInterface(TransactionManager transactionManager, Authenticator authenti @Override public void run() { - //ToDo: Instantiate Server (open port...) try { ServerBootstrap serverBootstrap = new ServerBootstrap(); @@ -111,6 +110,7 @@ public void initChannel(SocketChannel socketChannel) throws Exception { //Handler channelPipeline.addLast("handler", new PGInterfaceServerHandler(transactionManager)); + } }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index f072a88740..f05ea84735 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -23,32 +23,33 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; +/** + * Manages all incoming communication, not using the netty framework + */ public class PGInterfaceInboundCommunicationHandler { String type; - PGInterfaceClient client; ChannelHandlerContext ctx; TransactionManager transactionManager; - public PGInterfaceInboundCommunicationHandler (String type, PGInterfaceClient client, TransactionManager transactionManager) { + public PGInterfaceInboundCommunicationHandler (String type, ChannelHandlerContext ctx, TransactionManager transactionManager) { this.type = type; - this.client = client; - this.ctx = client.getCtx(); + this.ctx = ctx; this.transactionManager = transactionManager; } - //ich mues ergendwie identifiziere wele client dases esch... oder muesich öberhaupt speichere was fören phase das de client denne esch... - //muesich das wörklech oder esches eidütig vom protokoll här? --> has gfühl chas eidütig metem protokoll handle - - public String decideCycle(Object oMsg) { - String cycleState = ""; + /** + * Decides in what cycle from postgres the client is (startup-phase, query-phase, etc.) + * @param oMsg the incoming message from the client (unchanged) + * @return + */ + public void decideCycle(Object oMsg) { String msgWithZeroBits = ((String) oMsg); String wholeMsg = msgWithZeroBits.replace("\u0000", ""); - - + //TODO(FF): simple query phase is not implemented switch (wholeMsg.substring(0, 1)) { - case "C": + case "C": //TODO(FF):was gnau passiert do?? PGInterfaceMessage msg = null; msg.setHeader(PGInterfaceHeaders.C); //msg.setMsgBody(); @@ -64,7 +65,6 @@ public String decideCycle(Object oMsg) { break; } - return cycleState; } public void startUpPhase() { @@ -207,18 +207,14 @@ public void sendCommandCompleteCreateTable() { //for SELECT and CREATE TABLE AS public void sendCommandCompleteSelect(int rowsSelected) { //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - String body = "SELECT "+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? - //"SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected) - PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, body, 4, true); - PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("s", selectCommandComplete, ctx); - ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); - String lol = buf.toString(Charset.defaultCharset()); - ctx.writeAndFlush(buf); + String body = "SELECT"+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? + PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected), 4, true); + PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("ss", selectCommandComplete, ctx); + ctx.writeAndFlush(selectCommandCompleteWriter.writeOnByteBuf()); } - public void sendRowDescription(int numberOfFields, ArrayList valuesPerCol) { //String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode @@ -227,9 +223,12 @@ public void sendRowDescription(int numberOfFields, ArrayList valuesPer //ByteBuf test = ctx.alloc().buffer(); String body = String.valueOf(numberOfFields); PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription - PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("test",rowDescription, ctx); - //ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); - ctx.writeAndFlush(rowDescriptionWriter.writeOnByteBuf()); + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); + ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); + + //rowDescriptionWriter.writeRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); + //ctx.writeAndFlush(test); + //ctx.writeAndFlush(rowDescriptionWriter); //TODO(FF): glaube das bruucht mer ned?? } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 82a484f466..3939f06ddb 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -340,13 +340,14 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... Object col[] = {fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode}; valuesPerCol.add(col); } + communicationHandler.sendParseBindComplete(); communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); //sendData communicationHandler.sendDataRow(data); rowsAffected = data.size(); communicationHandler.sendCommandCompleteSelect(rowsAffected); - communicationHandler.sendParseBindComplete(); + communicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 47ee50a5849bb6da2f3b4dcce1973f50881795ac..5b424138642a8c311dde2379207bdcdd8bc12cf5 100644 GIT binary patch delta 117 zcmeyQ`9yJp7qh>G)I54Cvy_xWG+^p$x&R~lVdrHnM*2k OCL6K{Z+^+i$qfKJC?=Tz delta 1075 zcma)5&2AGh5Ekl>L@1|9oH$G)qwrrUk}S6=+7?uc^C)u%Al&<^qOanoK8KC%DCpIB<*)Tu z#kn(5jX)|m1U5eeKzY4ZoyYn9stbr&!X>GbTEPlcFYBC!Zm-#LkwykmjAAq-aCflV z$gh+yg6%=s-`ZyL<8hu)`dc;8I>R^=dLl8VpX6JWQGUF;Q*^o=c(mjQ=XH5#(H+km zGUDt&(6~|2j?vm^gv8SBwi{8LOXZ*mcAJn#^Sa2~O5Xi{>Z^)L;De%e!lPPw<@p}> zfb)kHOlZiPXqcf#x9pEzL^O$nbh85(pv#T2H`Ai>@sP~a2@HJ+FfAN98&FW%YPLW` z3WQdLi=+x`5sMDIkiQ+CohrwCh(y#Su*aLj>VpKaG~d2l6wd367b6c=q(;gi)(Tq^VQ;EL03QWd?EE9Pp(ICC{ cqoY>SMa5CR-k5IQaCgcN>)Y4gH*Vkg4FDZ4Gynhq diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 6c74c27b1b..d31ffb67e1 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; public class PGInterfaceServerWriter { String type; @@ -202,30 +203,63 @@ public ByteBuf writeIntHeaderOnByteBuf(char header) { return buffer; } - public ByteBuf writeRowDescription(String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode) { + public ByteBuf writeRowDescription(ArrayList valuesPerCol) { //I don't check for length, bcs rowDescription is always the same ByteBuf buffer = ctx.alloc().buffer(); + //ByteBuf bufferTemp = ctx.alloc().buffer(); + String fieldName; + int objectIDTable; + int attributeNoCol; + int objectIDCol; + int dataTypeSize; + int typeModifier; + int formatCode; //bytebuf.writeInt(int value) = 32-bit int //bytebuf.writeShort(int value) = 16-bit short integer; + int messageLength = 0; buffer.writeByte(pgMsg.getHeaderChar()); - buffer.writeInt(pgMsg.getLength() + fieldName.length() + 6); - - buffer.writeBytes(fieldName.getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); - buffer.writeInt(objectIDTable); - buffer.writeByte(0); - buffer.writeShort(attributeNoCol); - buffer.writeByte(0); - buffer.writeInt(objectIDCol); - buffer.writeByte(0); - buffer.writeShort(dataTypeSize); - buffer.writeByte(0); - buffer.writeInt(typeModifier); - buffer.writeByte(0); - buffer.writeShort(formatCode); + for (int i = 0; i be comission + + ctx.writeAndFlush(bufferTemp); //die erste 3x gohts ohni fähler + } + + //return buffer.writeBytes(bufferTemp); return buffer; } From d1f53107813617b9b032b79492bbef8a48b10f37 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 5 Oct 2022 15:39:03 +0200 Subject: [PATCH 30/57] rowDescription is now sent correctly... although I don't know why... The origin of the number 8 eludes me as of yet... --- .../PGInterfaceInboundCommunicationHandler.java | 4 ---- .../db/postgresql/PGInterfaceQueryHandler.java | 6 ++++-- .../db/postgresql/PGInterfaceServerWriter.java | 16 ++++++---------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index f05ea84735..c86abf1779 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -225,10 +225,6 @@ public void sendRowDescription(int numberOfFields, ArrayList valuesPer PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); - - //rowDescriptionWriter.writeRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); - //ctx.writeAndFlush(test); - //ctx.writeAndFlush(rowDescriptionWriter); //TODO(FF): glaube das bruucht mer ned?? } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 3939f06ddb..5639999b74 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -314,8 +314,10 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... formatCode = 1; break; case "VARCHAR": - dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize - formatCode = 0; + //dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize + //formatCode = 0; + dataTypeSize = 4; + formatCode = 1; break; case "SMALLINT": dataTypeSize = 2; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index d31ffb67e1..ea915b7642 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -215,20 +215,16 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { int typeModifier; int formatCode; - //bytebuf.writeInt(int value) = 32-bit int - //bytebuf.writeShort(int value) = 16-bit short integer; - int messageLength = 0; buffer.writeByte(pgMsg.getHeaderChar()); for (int i = 0; i( oder au ned? werom 8????? for(Object[] oneCol : valuesPerCol) { ByteBuf bufferTemp = ctx.alloc().buffer(); @@ -248,15 +244,15 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { bufferTemp.writeByte(0); bufferTemp.writeShort(attributeNoCol); bufferTemp.writeByte(0); - bufferTemp.writeInt(objectIDCol); + bufferTemp.writeInt(objectIDCol); //objectId of datatype? bufferTemp.writeByte(0); bufferTemp.writeShort(dataTypeSize); bufferTemp.writeByte(0); bufferTemp.writeInt(typeModifier); bufferTemp.writeByte(0); - bufferTemp.writeShort(formatCode); //aber bem 4. esch denn do dezwösche en fähöer cho, vorem nöchste flushl... werom au emmer??? --> be comission + bufferTemp.writeShort(formatCode); //aber bem 4. esch denn do dezwösche en fähler cho, vorem nöchste flushl... werom au emmer??? --> be comission - ctx.writeAndFlush(bufferTemp); //die erste 3x gohts ohni fähler + buffer.writeBytes(bufferTemp); //die erste 3x gohts ohni fähler } //return buffer.writeBytes(bufferTemp); From 1ddc6321be204c02ae195f5e9c08c822407249dc Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 15:00:25 +0200 Subject: [PATCH 31/57] client doesn't respond --- .../postgresql/PGInterfaceQueryHandler.java | 13 +++-- .../postgresql/PGInterfaceServerWriter.java | 50 +++++++++++++++---- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 5639999b74..4492d656bb 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -310,14 +310,17 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "REAL": case "INTEGER": + objectIDCol = 32; dataTypeSize = 4; - formatCode = 1; + formatCode = 1; //Test with 0, normally 1 (?) break; case "VARCHAR": - //dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize - //formatCode = 0; - dataTypeSize = 4; - formatCode = 1; + objectIDCol = 1043; + typeModifier = Integer.parseInt(head[2]); + dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize + formatCode = 0; + //dataTypeSize = 4; + //formatCode = 1; break; case "SMALLINT": dataTypeSize = 2; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index ea915b7642..c41fa5c0a7 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -136,20 +137,36 @@ public ByteBuf writeOnByteBuf() { case "dr": //send dataRow - buffer.writeByte(pgMsg.getHeaderChar()); + String test = ""; + ByteBuf buffer7 = ctx.alloc().buffer(); + buffer7.writeByte(pgMsg.getHeaderChar()); + ctx.writeAndFlush(buffer7); + test += pgMsg.getHeaderChar() + " | "; + + ByteBuf buffer1 = ctx.alloc().buffer(); + ByteBuf buffer2 = ctx.alloc().buffer(); + ByteBuf buffer3 = ctx.alloc().buffer(); int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll("§","").length())/2; //should generally be not the default length, but also works with default length & length = 4 if (pgMsg.isDefaultLength()) { //data row does not include msg-length bytes in msg length - buffer.writeInt(pgMsg.getLength()- 4 - (nbrCol*2)); + buffer1.writeInt(pgMsg.getLength() - (nbrCol*2)); + ctx.writeAndFlush(buffer1); + int lol = (pgMsg.getLength() - (nbrCol*2)); + test += lol + " | "; } else { - buffer.writeInt(pgMsg.getLength()); + //bcs it is including self + buffer2.writeInt(pgMsg.getLength() + 4); + ctx.writeAndFlush(buffer2); + test += pgMsg.getLength() + " | "; } - buffer.writeShort(nbrCol); + buffer3.writeShort(nbrCol); //mues das evtl au 8 sii??? + ctx.writeAndFlush(buffer3); + test += nbrCol + " | "; //cut the last § (it is at the end) from the msgBody and set it as the new msgBody String temp = pgMsg.getMsgBody().substring(0, pgMsg.getMsgBody().length() - 1); @@ -158,13 +175,24 @@ public ByteBuf writeOnByteBuf() { int[] idx = new int[(nbrCol*2)]; String[] msgParts = pgMsg.getMsgPart(idx); - for (int i = 0; i < (nbrCol*2); i++) { - buffer.writeInt(Integer.parseInt(msgParts[i])); - buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); + for (int i = 0; i < ((nbrCol*2)- 1); i++) { //i<=10? hätt etzt gseit nei + ByteBuf buffer4 = ctx.alloc().buffer(); + ByteBuf buffer5 = ctx.alloc().buffer(); + ByteBuf buffer6 = ctx.alloc().buffer(); + buffer4.writeInt(Integer.parseInt(msgParts[i])); //onde: müesst 10 schecke... + ctx.writeAndFlush(buffer4); //2. durchgang, hier fehler chönnts + //buffer5.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? + buffer5.writeInt(Integer.parseInt(msgParts[i+1])); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? + ctx.writeAndFlush(buffer5); + //buffer6.writeBytes(msgParts[i+2].getBytes(StandardCharsets.UTF_8)); + buffer6.writeByte(0); + //ctx.writeAndFlush(buffer6); + + test += msgParts[i] + " | " + msgParts[i+1] + " | "; + i++; } - + int x = 2; break; } return buffer; @@ -224,7 +252,7 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { buffer.writeInt(pgMsg.getLength() + messageLength); //buffer.writeShort(Integer.parseInt(pgMsg.getMsgBody())); - buffer.writeShort(8); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? + buffer.writeShort(1); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? for(Object[] oneCol : valuesPerCol) { ByteBuf bufferTemp = ctx.alloc().buffer(); @@ -256,6 +284,8 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { } //return buffer.writeBytes(bufferTemp); + //String bla = new String(buffer.array(), Charset.defaultCharset()); + String bla = buffer.toString(Charset.defaultCharset()); return buffer; } From 505e72fa7d18eec250379276101ca57c8b99ba58 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 15:51:05 +0200 Subject: [PATCH 32/57] hardcoded, client doesn't respond for real --- ...GInterfaceInboundCommunicationHandler.java | 5 ++-- .../postgresql/PGInterfaceServerWriter.java | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index c86abf1779..0f6229758d 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -223,8 +223,9 @@ public void sendRowDescription(int numberOfFields, ArrayList valuesPer //ByteBuf test = ctx.alloc().buffer(); String body = String.valueOf(numberOfFields); PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription - PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("i",rowDescription, ctx); - ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("test",rowDescription, ctx); + //ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); + ctx.writeAndFlush(rowDescriptionWriter.writeOnByteBuf()); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index c41fa5c0a7..94f334b0d6 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -139,7 +139,8 @@ public ByteBuf writeOnByteBuf() { //send dataRow String test = ""; ByteBuf buffer7 = ctx.alloc().buffer(); - buffer7.writeByte(pgMsg.getHeaderChar()); + //buffer7.writeByte(pgMsg.getHeaderChar()); + buffer7.writeByte('X'); ctx.writeAndFlush(buffer7); test += pgMsg.getHeaderChar() + " | "; @@ -194,6 +195,28 @@ public ByteBuf writeOnByteBuf() { } int x = 2; break; + + case "test": + //T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff + buffer.writeByte(pgMsg.getHeaderChar()); + buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); + //buffer.writeInt(24 + "empid".length()); + buffer.writeShort(1); + buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); + buffer.writeInt(0); + buffer.writeShort(0); + buffer.writeInt(0); + buffer.writeShort(40); + buffer.writeInt(2); + buffer.writeInt(0); + buffer.writeShort(1); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(17); + buffer.writeInt(0); + buffer.writeInt(4); + break; } return buffer; } From 84fe9bf5301b0c019eab1dbcae447b5d4e35d5a6 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 16:44:18 +0200 Subject: [PATCH 33/57] new hardcoded things --- .../PGInterfaceInboundCommunicationHandler.java | 6 ++++-- .../db/postgresql/PGInterfaceQueryHandler.java | 8 +++++++- .../db/postgresql/PGInterfaceServerWriter.java | 11 ++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 0f6229758d..8f94c5837b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext; import org.polypheny.db.transaction.TransactionManager; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -210,7 +211,9 @@ public void sendCommandCompleteSelect(int rowsSelected) { String body = "SELECT"+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected), 4, true); PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("ss", selectCommandComplete, ctx); - ctx.writeAndFlush(selectCommandCompleteWriter.writeOnByteBuf()); + ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); + String lol = buf.toString(Charset.defaultCharset()); + ctx.writeAndFlush(buf); } @@ -301,6 +304,5 @@ public void sendDataRow2(ArrayList data) { ctx.writeAndFlush(buf); - } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 4492d656bb..0e1b7a6a1f 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -348,12 +348,18 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... communicationHandler.sendParseBindComplete(); communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); //sendData - communicationHandler.sendDataRow(data); + //communicationHandler.sendDataRow(data); + communicationHandler.sendDataRow2(data); rowsAffected = data.size(); communicationHandler.sendCommandCompleteSelect(rowsAffected); communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 94f334b0d6..972762bf86 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -139,8 +139,8 @@ public ByteBuf writeOnByteBuf() { //send dataRow String test = ""; ByteBuf buffer7 = ctx.alloc().buffer(); - //buffer7.writeByte(pgMsg.getHeaderChar()); - buffer7.writeByte('X'); + buffer7.writeByte(pgMsg.getHeaderChar()); + //buffer7.writeByte('X'); ctx.writeAndFlush(buffer7); test += pgMsg.getHeaderChar() + " | "; @@ -199,7 +199,12 @@ public ByteBuf writeOnByteBuf() { case "test": //T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff buffer.writeByte(pgMsg.getHeaderChar()); - buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); + //buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); + buffer.writeInt(0); //buffer.writeInt(24 + "empid".length()); buffer.writeShort(1); buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); From a46d56cde2e5cf9636d00d378d7efdb565602131 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 7 Oct 2022 17:44:37 +0200 Subject: [PATCH 34/57] not implemented yet, but byte analysis from wireshark --- .../org/polypheny/db/postgresql/PGInterfaceQueryHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 0e1b7a6a1f..c9526d704f 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -401,7 +401,6 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... - //Example of server answer to simple select query (from real server) /* 1....2....T......lolid...@...............D..........1D..........2D..........3D..........3D..........3D..........3C... From 3000e93d47b5a7ad41825d491c33e5b24dc36365 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Sat, 8 Oct 2022 19:44:09 +0200 Subject: [PATCH 35/57] crude hardcoded version of response to query. Doesn't work yet, far too many 0 now show up in wireshark --- ...GInterfaceInboundCommunicationHandler.java | 7 +- .../postgresql/PGInterfaceQueryHandler.java | 64 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 8f94c5837b..b12d13dfb9 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -208,9 +208,10 @@ public void sendCommandCompleteCreateTable() { //for SELECT and CREATE TABLE AS public void sendCommandCompleteSelect(int rowsSelected) { //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - String body = "SELECT"+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? - PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected), 4, true); - PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("ss", selectCommandComplete, ctx); + String body = "SELECT "+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? + //"SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected) + PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, body, 4, true); + PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("s", selectCommandComplete, ctx); ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); String lol = buf.toString(Charset.defaultCharset()); ctx.writeAndFlush(buf); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index c9526d704f..2497b8804a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -16,6 +16,7 @@ package org.polypheny.db.postgresql; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import org.apache.commons.lang.ArrayUtils; import org.polypheny.db.PolyResult; @@ -32,6 +33,8 @@ import org.polypheny.db.processing.QueryProcessor; import org.polypheny.db.transaction.*; +import javax.swing.plaf.basic.BasicButtonUI; +import java.nio.charset.StandardCharsets; import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.List; @@ -53,9 +56,68 @@ public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInter } public void start() { - sendQueryToPolypheny(); + hardcodeResponse(); + //sendQueryToPolypheny(); } + private void hardcodeResponse() { + ByteBuf buffer = ctx.alloc().buffer(); + /* + 1....2....T......empid...@...............D..........100C....SELECT 1.Z....I + + 1... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I + 1... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 + T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 + */ + int[] nbrs = {1,0,0,0,4}; + //2 + int[] nbrs2 = {0,0,0,4}; + //T + //int[] nbrs3 = {0,0,0,1e,0,1}; + int[] nbrs3 = {0,0,0,0,0,1}; + //empid + //int[] nbrs4 = {0,0,0,40,0c,0,1,0,0,0,17,0,4,ff,ff,ff,ff,0,0}; + int[] nbrs4 = {0,0,0,40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; + //D + //int[] nbrs5 = {0,0,0,0d,0,1,0,0,0,3}; + int[] nbrs5 = {0,0,0,0,0,1,0,0,0,3}; + //100C + //int[] nbrs6 = {0,0,0,0d}; + int[] nbrs6 = {0,0,0,0}; + //SELECT 1 + int[] nbrs7 = {0}; + //Z + int[] nbrs8 = {0,0,0,5}; + //I + buffer = writeIntArray(nbrs, buffer); + buffer.writeInt(2); + buffer = writeIntArray(nbrs2, buffer); + buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs3, buffer); + buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs4, buffer); + buffer.writeBytes("D".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs5, buffer); + buffer.writeBytes("100C".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs6, buffer); + buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs7, buffer); + buffer.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); + buffer = writeIntArray(nbrs8, buffer); + buffer.writeBytes("I".getBytes(StandardCharsets.UTF_8)); + + ctx.writeAndFlush(buffer); + + } + + private ByteBuf writeIntArray(int[] nbrs, ByteBuf buffer) { + for (int i=0; i< nbrs.length; i++) { + buffer.writeInt(nbrs[i]); + } + return buffer; + } + + public void sendQueryToPolypheny() { String type = ""; //query type according to answer tags //get result from polypheny From 96de7bc3a6f37c1a81e81c71a45c8c401d8bc653 Mon Sep 17 00:00:00 2001 From: datomo Date: Mon, 10 Oct 2022 17:01:55 +0200 Subject: [PATCH 36/57] fixed merge conflict --- .../polypheny/db/postgresql/PGInterface.java | 50 ++-- .../db/postgresql/PGInterfaceHeaders.java | 2 - ...GInterfaceInboundCommunicationHandler.java | 203 ++++++++-------- .../db/postgresql/PGInterfaceMessage.java | 52 ++-- .../postgresql/PGInterfaceQueryHandler.java | 196 ++++++++------- .../postgresql/PGInterfaceServerHandler.java | Bin 4324 -> 4297 bytes .../postgresql/PGInterfaceServerWriter.java | 226 +++++++++--------- 7 files changed, 368 insertions(+), 361 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 31c907ea3e..a97f1574c8 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -19,11 +19,22 @@ import com.google.common.collect.ImmutableList; import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.*; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.string.StringDecoder; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.StatusService; import org.polypheny.db.catalog.Catalog.QueryLanguage; @@ -36,15 +47,6 @@ import org.polypheny.db.transaction.TransactionManager; import org.polypheny.db.util.Util; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - - @Slf4j public class PGInterface extends QueryInterface { @@ -77,8 +79,7 @@ public class PGInterface extends QueryInterface { private final EventLoopGroup workerGroup = new NioEventLoopGroup(); - - public PGInterface(TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { + public PGInterface( TransactionManager transactionManager, Authenticator authenticator, int ifaceId, String uniqueName, Map settings ) { super( transactionManager, authenticator, ifaceId, uniqueName, settings, true, true ); this.uniqueName = uniqueName; this.port = Integer.parseInt( settings.get( "port" ) ); @@ -97,41 +98,38 @@ public void run() { try { ServerBootstrap serverBootstrap = new ServerBootstrap(); - serverBootstrap.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { + serverBootstrap.group( bossGroup, workerGroup ) + .channel( NioServerSocketChannel.class ) + .childHandler( new ChannelInitializer() { @Override - public void initChannel(SocketChannel socketChannel) throws Exception { + public void initChannel( SocketChannel socketChannel ) throws Exception { ChannelPipeline channelPipeline = socketChannel.pipeline(); //Inbound - channelPipeline.addLast("decoder", new StringDecoder()); + channelPipeline.addLast( "decoder", new StringDecoder() ); //Handler - channelPipeline.addLast("handler", new PGInterfaceServerHandler(transactionManager)); + channelPipeline.addLast( "handler", new PGInterfaceServerHandler( transactionManager ) ); } - }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); + } ).option( ChannelOption.SO_BACKLOG, 128 ).childOption( ChannelOption.SO_KEEPALIVE, true ); // Start accepting incoming connections - ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); + ChannelFuture channelFuture = serverBootstrap.bind( port ).sync(); // Waits until server socket is closed --> introduces bugs --> polypheny not starting (without reset) and not displaying interface correctly //channelFuture.channel().closeFuture().sync(); - - } catch (Exception e) { - log.error("Exception while starting" + INTERFACE_NAME, e); + } catch ( Exception e ) { + log.error( "Exception while starting" + INTERFACE_NAME, e ); } - - StatusService.printInfo(String.format("%s started and is listening on port %d.", INTERFACE_NAME, port )); + StatusService.printInfo( String.format( "%s started and is listening on port %d.", INTERFACE_NAME, port ) ); } - @Override public List getAvailableSettings() { return AVAILABLE_SETTINGS; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java index 690c161727..f1d162f305 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java @@ -25,7 +25,6 @@ //TODO: not complete with all commands yet (especially for copy commands, extended query cycle and different authentication methods) public enum PGInterfaceHeaders { - //----------------------------------------------- server to client ------------------------------------------------ /** @@ -115,7 +114,6 @@ public enum PGInterfaceHeaders { X - } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index b12d13dfb9..cda4b157d2 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -18,21 +18,22 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import org.polypheny.db.transaction.TransactionManager; - import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import org.polypheny.db.transaction.TransactionManager; /** * Manages all incoming communication, not using the netty framework */ public class PGInterfaceInboundCommunicationHandler { + String type; ChannelHandlerContext ctx; TransactionManager transactionManager; - public PGInterfaceInboundCommunicationHandler (String type, ChannelHandlerContext ctx, TransactionManager transactionManager) { + + public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContext ctx, TransactionManager transactionManager ) { this.type = type; this.ctx = ctx; this.transactionManager = transactionManager; @@ -41,25 +42,26 @@ public PGInterfaceInboundCommunicationHandler (String type, ChannelHandlerContex /** * Decides in what cycle from postgres the client is (startup-phase, query-phase, etc.) + * * @param oMsg the incoming message from the client (unchanged) * @return */ - public void decideCycle(Object oMsg) { + public void decideCycle( Object oMsg ) { String msgWithZeroBits = ((String) oMsg); - String wholeMsg = msgWithZeroBits.replace("\u0000", ""); + String wholeMsg = msgWithZeroBits.replace( "\u0000", "" ); //TODO(FF): simple query phase is not implemented - switch (wholeMsg.substring(0, 1)) { + switch ( wholeMsg.substring( 0, 1 ) ) { case "C": //TODO(FF):was gnau passiert do?? PGInterfaceMessage msg = null; - msg.setHeader(PGInterfaceHeaders.C); + msg.setHeader( PGInterfaceHeaders.C ); //msg.setMsgBody(); break; case "r": startUpPhase(); break; case "P": - extendedQueryPhase(wholeMsg); + extendedQueryPhase( wholeMsg ); break; case "X": terminateConnection(); @@ -68,45 +70,47 @@ public void decideCycle(Object oMsg) { } } + public void startUpPhase() { //authenticationOk - PGInterfaceMessage authenticationOk = new PGInterfaceMessage(PGInterfaceHeaders.R, "0", 8, false); - PGInterfaceServerWriter authenticationOkWriter = new PGInterfaceServerWriter("i", authenticationOk, ctx); - ctx.writeAndFlush(authenticationOkWriter.writeOnByteBuf()); + PGInterfaceMessage authenticationOk = new PGInterfaceMessage( PGInterfaceHeaders.R, "0", 8, false ); + PGInterfaceServerWriter authenticationOkWriter = new PGInterfaceServerWriter( "i", authenticationOk, ctx ); + ctx.writeAndFlush( authenticationOkWriter.writeOnByteBuf() ); //server_version (Parameter Status message) - PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version§14", 4, true); + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage( PGInterfaceHeaders.S, "server_version§14", 4, true ); //PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); - PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter("ss", parameterStatusServerVs, ctx); - ctx.writeAndFlush(parameterStatusServerVsWriter.writeOnByteBuf()); + PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter( "ss", parameterStatusServerVs, ctx ); + ctx.writeAndFlush( parameterStatusServerVsWriter.writeOnByteBuf() ); //ReadyForQuery - sendReadyForQuery("I"); + sendReadyForQuery( "I" ); } + public void simpleQueryPhase() { } - public void extendedQueryPhase(String incomingMsg) { - if (incomingMsg.substring(2,5).equals("SET")) { + public void extendedQueryPhase( String incomingMsg ) { + + if ( incomingMsg.substring( 2, 5 ).equals( "SET" ) ) { sendParseBindComplete(); sendParseBindComplete(); //commandComplete - SET - PGInterfaceMessage commandCompleteSET = new PGInterfaceMessage(PGInterfaceHeaders.C, "SET", 4, true); - PGInterfaceServerWriter commandCompleteSETWriter = new PGInterfaceServerWriter("s", commandCompleteSET, ctx); - ctx.writeAndFlush(commandCompleteSETWriter.writeOnByteBuf()); + PGInterfaceMessage commandCompleteSET = new PGInterfaceMessage( PGInterfaceHeaders.C, "SET", 4, true ); + PGInterfaceServerWriter commandCompleteSETWriter = new PGInterfaceServerWriter( "s", commandCompleteSET, ctx ); + ctx.writeAndFlush( commandCompleteSETWriter.writeOnByteBuf() ); - sendReadyForQuery("I"); - } - else { + sendReadyForQuery( "I" ); + } else { //Query does not have ";" at the end!! - String query = extractQuery(incomingMsg); - PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler(query, ctx, this, transactionManager); + String query = extractQuery( incomingMsg ); + PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler( query, ctx, this, transactionManager ); queryHandler.start(); } @@ -114,41 +118,43 @@ public void extendedQueryPhase(String incomingMsg) { } + /** * creates and sends (flushes on ctx) a readyForQuery message. Tag is choosable. + * * @param msgBody give the Tag - current transaction status indicator (possible vals: I (idle, not in transaction block), - * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) + * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) */ - public void sendReadyForQuery(String msgBody) { - PGInterfaceMessage readyForQuery = new PGInterfaceMessage(PGInterfaceHeaders.Z, msgBody, 5, false); - PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter("c", readyForQuery, ctx); - ctx.writeAndFlush(readyForQueryWriter.writeOnByteBuf()); + public void sendReadyForQuery( String msgBody ) { + PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); + PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx ); + ctx.writeAndFlush( readyForQueryWriter.writeOnByteBuf() ); } /** * prepares the incoming message from the client, so it can be used in the context of polypheny + * * @param incomingMsg unchanged incoming message from the client * @return "normally" readable and usable query string */ - public String extractQuery(String incomingMsg) { + public String extractQuery( String incomingMsg ) { String query = ""; //cut header - query = incomingMsg.substring(2, incomingMsg.length()-1); + query = incomingMsg.substring( 2, incomingMsg.length() - 1 ); //find end of query --> normally it ends with combination of BDPES (are headers, with some weird other bits in between) //B starts immediatelly after query --> find position of correct B and end of query is found - byte[] byteSequence = {66, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 6, 80, 0, 69, 0, 0, 0, 9}; - String msgWithZeroBits = new String(byteSequence, StandardCharsets.UTF_8); - String endSequence = msgWithZeroBits.replace("\u0000", ""); + byte[] byteSequence = { 66, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 6, 80, 0, 69, 0, 0, 0, 9 }; + String msgWithZeroBits = new String( byteSequence, StandardCharsets.UTF_8 ); + String endSequence = msgWithZeroBits.replace( "\u0000", "" ); - String endOfQuery = query.substring(incomingMsg.length()-20); + String endOfQuery = query.substring( incomingMsg.length() - 20 ); - int idx = incomingMsg.indexOf(endSequence); - if (idx != -1) { - query = query.substring(0, idx-2); - } - else { + int idx = incomingMsg.indexOf( endSequence ); + if ( idx != -1 ) { + query = query.substring( 0, idx - 2 ); + } else { //TODO(FF) something went wrong!! --> trow exception (in polypheny), send errormessage to client int lol = 2; } @@ -156,6 +162,7 @@ public String extractQuery(String incomingMsg) { return query; } + public void sendParseBindComplete() { //TODO(FF): This should work with the normal PGInterfaceServerWriter type "i" (called like in the commented out part), // but it does not --> roundabout solution that works, but try to figure out what went wrong... @@ -173,67 +180,70 @@ public void sendParseBindComplete() { */ ByteBuf buffer = ctx.alloc().buffer(); - PGInterfaceMessage mockMessage = new PGInterfaceMessage(PGInterfaceHeaders.ONE, "0", 4, true); - PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter("i", mockMessage, ctx); - buffer = headerWriter.writeIntHeaderOnByteBuf('1'); + PGInterfaceMessage mockMessage = new PGInterfaceMessage( PGInterfaceHeaders.ONE, "0", 4, true ); + PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter( "i", mockMessage, ctx ); + buffer = headerWriter.writeIntHeaderOnByteBuf( '1' ); //ctx.writeAndFlush(buffer); - buffer.writeBytes(headerWriter.writeIntHeaderOnByteBuf('2')); + buffer.writeBytes( headerWriter.writeIntHeaderOnByteBuf( '2' ) ); //buffer = headerWriter.writeIntHeaderOnByteBuf('2'); - ctx.writeAndFlush(buffer); + ctx.writeAndFlush( buffer ); } + public void sendNoData() { //TODO(FF) wenn gnau esch das öberhaupt nötig? Wenn de client kei date scheckt --> aber wenn esch das es problem? - PGInterfaceMessage noData = new PGInterfaceMessage(PGInterfaceHeaders.n, "0", 4, true); - PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter("i", noData, ctx); - ctx.writeAndFlush(noDataWriter.writeOnByteBuf()); + PGInterfaceMessage noData = new PGInterfaceMessage( PGInterfaceHeaders.n, "0", 4, true ); + PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx ); + ctx.writeAndFlush( noDataWriter.writeOnByteBuf() ); } - public void sendCommandCompleteInsert(int rowsInserted) { + + public void sendCommandCompleteInsert( int rowsInserted ) { //send CommandComplete - insert - PGInterfaceMessage insertCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "INSERT" + PGInterfaceMessage.getDelimiter() + "0" + PGInterfaceMessage.getDelimiter() + String.valueOf(rowsInserted), 4, true); - PGInterfaceServerWriter insertCommandCompleteWriter = new PGInterfaceServerWriter("sss", insertCommandComplete, ctx); - ctx.writeAndFlush(insertCommandCompleteWriter.writeOnByteBuf()); + PGInterfaceMessage insertCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, "INSERT" + PGInterfaceMessage.getDelimiter() + "0" + PGInterfaceMessage.getDelimiter() + String.valueOf( rowsInserted ), 4, true ); + PGInterfaceServerWriter insertCommandCompleteWriter = new PGInterfaceServerWriter( "sss", insertCommandComplete, ctx ); + ctx.writeAndFlush( insertCommandCompleteWriter.writeOnByteBuf() ); } + public void sendCommandCompleteCreateTable() { //send CommandComplete - create table - PGInterfaceMessage createTableCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, "CREATE TABLE", 4, true); - PGInterfaceServerWriter createTableCommandCompleteWriter = new PGInterfaceServerWriter("s", createTableCommandComplete, ctx); - ctx.writeAndFlush(createTableCommandCompleteWriter.writeOnByteBuf()); + PGInterfaceMessage createTableCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, "CREATE TABLE", 4, true ); + PGInterfaceServerWriter createTableCommandCompleteWriter = new PGInterfaceServerWriter( "s", createTableCommandComplete, ctx ); + ctx.writeAndFlush( createTableCommandCompleteWriter.writeOnByteBuf() ); } + //for SELECT and CREATE TABLE AS - public void sendCommandCompleteSelect(int rowsSelected) { + public void sendCommandCompleteSelect( int rowsSelected ) { //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - String body = "SELECT "+ String.valueOf(rowsSelected); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? + String body = "SELECT " + String.valueOf( rowsSelected ); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? //"SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected) - PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage(PGInterfaceHeaders.C, body, 4, true); - PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter("s", selectCommandComplete, ctx); + PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); + PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter( "s", selectCommandComplete, ctx ); ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); - String lol = buf.toString(Charset.defaultCharset()); - ctx.writeAndFlush(buf); + String lol = buf.toString( Charset.defaultCharset() ); + ctx.writeAndFlush( buf ); } - - public void sendRowDescription(int numberOfFields, ArrayList valuesPerCol) { + public void sendRowDescription( int numberOfFields, ArrayList valuesPerCol ) { //String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode //bytebuf.writeInt(int value) = 32-bit int //bytebuf.writeShort(int value) = 16-bit short integer; //ByteBuf test = ctx.alloc().buffer(); - String body = String.valueOf(numberOfFields); - PGInterfaceMessage rowDescription = new PGInterfaceMessage(PGInterfaceHeaders.T, body, 4, true); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription - PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter("test",rowDescription, ctx); + String body = String.valueOf( numberOfFields ); + PGInterfaceMessage rowDescription = new PGInterfaceMessage( PGInterfaceHeaders.T, body, 4, true ); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "test", rowDescription, ctx ); //ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); - ctx.writeAndFlush(rowDescriptionWriter.writeOnByteBuf()); + ctx.writeAndFlush( rowDescriptionWriter.writeOnByteBuf() ); } - public void sendDataRow(ArrayList data) { + public void sendDataRow( ArrayList data ) { /* DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: (int16) length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), (int32) @@ -242,68 +252,69 @@ value of the col (in format indicated by associated format code) (string) */ int noCols = data.size(); //number of rows returned --> belongs to rowDescription (?) String colVal = ""; - int nbrFollowingColVal = data.get(0).length; //int16 --> length of String[] --> nbr of column values that follow + int nbrFollowingColVal = data.get( 0 ).length; //int16 --> length of String[] --> nbr of column values that follow int colValLength = 0; //int32 --> length of one String[i] (length of actual string) (n) String body = ""; //Byte*n* --> the string itself String[i] PGInterfaceMessage dataRow; PGInterfaceServerWriter dataRowWriter; - for (int i = 0; i < noCols; i++) { + for ( int i = 0; i < noCols; i++ ) { //can be 0 and -1 (= NULL col val) - for (int j = 0; j < nbrFollowingColVal; j++) { + for ( int j = 0; j < nbrFollowingColVal; j++ ) { //if colValLength -1 : nothing sent at all - colVal = data.get(i)[j]; + colVal = data.get( i )[j]; //TODO(FF): How is null safed in polypheny exactly?? is it correctly checked? - if (colVal == "NULL") { + if ( colVal == "NULL" ) { colValLength = -1; //scheck kei body break; - } - - else { + } else { colValLength += colVal.length(); body += colVal.length() + PGInterfaceMessage.getDelimiter() + colVal + PGInterfaceMessage.getDelimiter(); } } //do gets glaubs ergendwo neu en fähler? - dataRow = new PGInterfaceMessage(PGInterfaceHeaders.D, body, colValLength, false); - dataRowWriter = new PGInterfaceServerWriter("dr", dataRow, ctx); - ctx.writeAndFlush(dataRowWriter.writeOnByteBuf()); + dataRow = new PGInterfaceMessage( PGInterfaceHeaders.D, body, colValLength, false ); + dataRowWriter = new PGInterfaceServerWriter( "dr", dataRow, ctx ); + ctx.writeAndFlush( dataRowWriter.writeOnByteBuf() ); ByteBuf buff = ctx.alloc().buffer(); //C...SELECT 6 - buff.writeBytes("C000SELECT 6".getBytes(StandardCharsets.UTF_8)); + buff.writeBytes( "C000SELECT 6".getBytes( StandardCharsets.UTF_8 ) ); body = ""; } } + public void terminateConnection() { ctx.close(); } - public void sendDataRow2(ArrayList data) { + + public void sendDataRow2( ArrayList data ) { ByteBuf buf = ctx.alloc().buffer(); // 44 00 00 00 0b 00 01 00 00 00 01 31 //buf.writeBytes("440000b01000131".getBytes()); - buf.writeInt(44); - buf.writeInt(0); - buf.writeInt(0); - buf.writeInt(0); - buf.writeInt(0); // - buf.writeInt(0); - buf.writeInt(1); - buf.writeInt(0); - buf.writeInt(0); - buf.writeInt(0); - buf.writeInt(1); - buf.writeInt(31); - String lol = buf.toString(Charset.defaultCharset()); - ctx.writeAndFlush(buf); + buf.writeInt( 44 ); + buf.writeInt( 0 ); + buf.writeInt( 0 ); + buf.writeInt( 0 ); + buf.writeInt( 0 ); // + buf.writeInt( 0 ); + buf.writeInt( 1 ); + buf.writeInt( 0 ); + buf.writeInt( 0 ); + buf.writeInt( 0 ); + buf.writeInt( 1 ); + buf.writeInt( 31 ); + String lol = buf.toString( Charset.defaultCharset() ); + ctx.writeAndFlush( buf ); } + } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 78737aee79..873b234f68 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -25,35 +25,36 @@ public class PGInterfaceMessage { private boolean defaultLength; private static final char delimiter = '§'; //for the subparts - public PGInterfaceMessage(PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength) { + + public PGInterfaceMessage( PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength ) { this.header = header; this.msgBody = msgBody; this.length = length; this.defaultLength = defaultLength; } + public PGInterfaceHeaders getHeader() { return this.header; } + public char getHeaderChar() { //if header is a single character - if (header != PGInterfaceHeaders.ONE && header != PGInterfaceHeaders.TWO && header != PGInterfaceHeaders.THREE) { + if ( header != PGInterfaceHeaders.ONE && header != PGInterfaceHeaders.TWO && header != PGInterfaceHeaders.THREE ) { String headerString = header.toString(); - return headerString.charAt(0); + return headerString.charAt( 0 ); } //if header is a number //TODO: make a nicer version of this... if you cast headerInt to char directly it returns '\u0001' and not '1' else { int headerInt = getHeaderInt(); - if (headerInt == 1) { + if ( headerInt == 1 ) { return '1'; - } - else if (headerInt == 2) { + } else if ( headerInt == 2 ) { return '2'; - } - else if (headerInt == 3) { + } else if ( headerInt == 3 ) { return '3'; } } @@ -61,68 +62,75 @@ else if (headerInt == 3) { return 0; } + public int getHeaderInt() { String headerString = header.toString(); - if(headerString.equals("ONE")) { + if ( headerString.equals( "ONE" ) ) { return 1; - } - else if(headerString.equals("TWO")) { + } else if ( headerString.equals( "TWO" ) ) { return 2; - } - else if (headerString.equals("THREE")) { + } else if ( headerString.equals( "THREE" ) ) { return 3; } //TODO: if returns 0, something went wrong return 0; } - public void setHeader(PGInterfaceHeaders header) { + + public void setHeader( PGInterfaceHeaders header ) { this.header = header; } + public int getLength() { return this.length; } - public void setLength(int length) { + + public void setLength( int length ) { this.length = length; } - public void setDefaultLength(boolean val) { + + public void setDefaultLength( boolean val ) { this.defaultLength = val; } + public boolean isDefaultLength() { return this.defaultLength; } + public String getMsgBody() { return msgBody; } - public void setMsgBody(String msgBody) { + + public void setMsgBody( String msgBody ) { this.msgBody = msgBody; } - /** * gets the different subparts of a message + * * @param part the index of the requested part(s), starting at 0 * @return a string array with each requested part */ - public String[] getMsgPart(int[] part) { - String subStrings[] = msgBody.split(getDelimiter()); + public String[] getMsgPart( int[] part ) { + String subStrings[] = msgBody.split( getDelimiter() ); String result[] = new String[part.length]; - for (int i=0; i<(part.length); i++) { + for ( int i = 0; i < (part.length); i++ ) { result[i] = subStrings[i]; } return result; } + public static String getDelimiter() { - String del = String.valueOf(delimiter); + String del = String.valueOf( delimiter ); return del; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 2497b8804a..bf7cd6a642 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -18,28 +18,30 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import org.apache.commons.lang.ArrayUtils; -import org.polypheny.db.PolyResult; +import java.nio.charset.StandardCharsets; +import java.sql.ResultSetMetaData; +import java.util.ArrayList; +import java.util.List; +import org.polypheny.db.PolyImplementation; import org.polypheny.db.algebra.AlgRoot; import org.polypheny.db.algebra.constant.Kind; import org.polypheny.db.algebra.type.AlgDataTypeField; import org.polypheny.db.catalog.Catalog; -import org.polypheny.db.catalog.entity.*; -import org.polypheny.db.catalog.exceptions.*; +import org.polypheny.db.catalog.exceptions.GenericCatalogException; +import org.polypheny.db.catalog.exceptions.UnknownDatabaseException; +import org.polypheny.db.catalog.exceptions.UnknownSchemaException; +import org.polypheny.db.catalog.exceptions.UnknownUserException; import org.polypheny.db.config.RuntimeConfig; import org.polypheny.db.languages.QueryParameters; import org.polypheny.db.nodes.Node; import org.polypheny.db.processing.Processor; import org.polypheny.db.processing.QueryProcessor; -import org.polypheny.db.transaction.*; +import org.polypheny.db.transaction.Statement; +import org.polypheny.db.transaction.Transaction; +import org.polypheny.db.transaction.TransactionManager; -import javax.swing.plaf.basic.BasicButtonUI; -import java.nio.charset.StandardCharsets; -import java.sql.ResultSetMetaData; -import java.util.ArrayList; -import java.util.List; +public class PGInterfaceQueryHandler { -public class PGInterfaceQueryHandler{ String query; ChannelHandlerContext ctx; PGInterfaceInboundCommunicationHandler communicationHandler; @@ -47,7 +49,8 @@ public class PGInterfaceQueryHandler{ int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) List> rows; - public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager) { + + public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager ) { this.query = query; this.ctx = ctx; this.communicationHandler = communicationHandler; @@ -55,11 +58,13 @@ public PGInterfaceQueryHandler (String query, ChannelHandlerContext ctx, PGInter this.transactionManager = transactionManager; } + public void start() { hardcodeResponse(); //sendQueryToPolypheny(); } + private void hardcodeResponse() { ByteBuf buffer = ctx.alloc().buffer(); /* @@ -69,50 +74,51 @@ private void hardcodeResponse() { 1... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 */ - int[] nbrs = {1,0,0,0,4}; + int[] nbrs = { 1, 0, 0, 0, 4 }; //2 - int[] nbrs2 = {0,0,0,4}; + int[] nbrs2 = { 0, 0, 0, 4 }; //T //int[] nbrs3 = {0,0,0,1e,0,1}; - int[] nbrs3 = {0,0,0,0,0,1}; + int[] nbrs3 = { 0, 0, 0, 0, 0, 1 }; //empid //int[] nbrs4 = {0,0,0,40,0c,0,1,0,0,0,17,0,4,ff,ff,ff,ff,0,0}; - int[] nbrs4 = {0,0,0,40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; + int[] nbrs4 = { 0, 0, 0, 40, 0, 0, 1, 0, 0, 0, 17, 0, 4, 0, 0, 0, 0, 0, 0 }; //D //int[] nbrs5 = {0,0,0,0d,0,1,0,0,0,3}; - int[] nbrs5 = {0,0,0,0,0,1,0,0,0,3}; + int[] nbrs5 = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 3 }; //100C //int[] nbrs6 = {0,0,0,0d}; - int[] nbrs6 = {0,0,0,0}; + int[] nbrs6 = { 0, 0, 0, 0 }; //SELECT 1 - int[] nbrs7 = {0}; + int[] nbrs7 = { 0 }; //Z - int[] nbrs8 = {0,0,0,5}; + int[] nbrs8 = { 0, 0, 0, 5 }; //I - buffer = writeIntArray(nbrs, buffer); - buffer.writeInt(2); - buffer = writeIntArray(nbrs2, buffer); - buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs3, buffer); - buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs4, buffer); - buffer.writeBytes("D".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs5, buffer); - buffer.writeBytes("100C".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs6, buffer); - buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs7, buffer); - buffer.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); - buffer = writeIntArray(nbrs8, buffer); - buffer.writeBytes("I".getBytes(StandardCharsets.UTF_8)); - - ctx.writeAndFlush(buffer); + buffer = writeIntArray( nbrs, buffer ); + buffer.writeInt( 2 ); + buffer = writeIntArray( nbrs2, buffer ); + buffer.writeBytes( "T".getBytes( StandardCharsets.UTF_8 ) ); + buffer = writeIntArray( nbrs3, buffer ); + buffer.writeBytes( "empid".getBytes( StandardCharsets.UTF_8 ) ); + buffer = writeIntArray( nbrs4, buffer ); + buffer.writeBytes( "D".getBytes( StandardCharsets.UTF_8 ) ); + buffer = writeIntArray( nbrs5, buffer ); + buffer.writeBytes( "100C".getBytes( StandardCharsets.UTF_8 ) ); + buffer = writeIntArray( nbrs6, buffer ); + buffer.writeBytes( "SELECT 1".getBytes( StandardCharsets.UTF_8 ) ); + buffer = writeIntArray( nbrs7, buffer ); + buffer.writeBytes( "Z".getBytes( StandardCharsets.UTF_8 ) ); + buffer = writeIntArray( nbrs8, buffer ); + buffer.writeBytes( "I".getBytes( StandardCharsets.UTF_8 ) ); + + ctx.writeAndFlush( buffer ); } - private ByteBuf writeIntArray(int[] nbrs, ByteBuf buffer) { - for (int i=0; i< nbrs.length; i++) { - buffer.writeInt(nbrs[i]); + + private ByteBuf writeIntArray( int[] nbrs, ByteBuf buffer ) { + for ( int i = 0; i < nbrs.length; i++ ) { + buffer.writeInt( nbrs[i] ); } return buffer; } @@ -123,28 +129,23 @@ public void sendQueryToPolypheny() { //get result from polypheny Transaction transaction; Statement statement = null; - PolyResult result; + PolyImplementation result; ArrayList data = new ArrayList<>(); ArrayList header = new ArrayList<>(); - - try { //get transaction letze linie - transaction = transactionManager.startTransaction("pa", "APP", false, "Index Manager"); + transaction = transactionManager.startTransaction( Catalog.defaultUserId, Catalog.defaultDatabaseId, false, "Index Manager" ); statement = transaction.createStatement(); - } - catch (UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e) { + } catch ( UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e ) { throw new RuntimeException( "Error while starting transaction", e ); } - - //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) //for loop zom dor alli catalogTables doregoh? - nei - Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); - Node sqlNode = sqlProcessor.parse(query); //go gehts fähler: (see diary) - QueryParameters parameters = new QueryParameters( query, Catalog.SchemaType.RELATIONAL ); + Processor sqlProcessor = statement.getTransaction().getProcessor( Catalog.QueryLanguage.SQL ); + Node sqlNode = sqlProcessor.parse( query ).get( 0 ); //go gehts fähler: (see diary) + QueryParameters parameters = new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ); if ( sqlNode.isA( Kind.DDL ) ) { result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); //TODO(FF): ene try catch block... || evtl no committe (söscht werds ned aazeigt em ui (aso allgemein, wie werds denn aazeigt em ui?) @@ -152,24 +153,24 @@ public void sendQueryToPolypheny() { } else { AlgRoot algRoot = sqlProcessor.translate( statement, - sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, - new QueryParameters(query, Catalog.SchemaType.RELATIONAL)); + sqlProcessor.validate( statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean() ).left, + new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ) ); //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) final QueryProcessor processor = statement.getQueryProcessor(); - result = processor.prepareQuery(algRoot, true); + result = processor.prepareQuery( algRoot, true ); } //get type information - from crud.java //Type of ArrayList was DbColumn, but belongs to webUI (so I don't need it...) --> replaced it with string? //ArrayList header = getHeader(result, query); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? -header = getHeader(result); +header = getHeader( result ); //statement.executeUpdate("SELECT empid FROM public.emps"); - + //get actual result of query in array - from crud.java - rows = result.getRows(statement, -1); //-1 as size valid?? - data = computeResultData(rows, header); //, statement.getTransaction() + rows = result.getRows( statement, -1 ); //-1 as size valid?? + data = computeResultData( rows, header ); //, statement.getTransaction() //type = result.getStatementType().name(); type = result.getStatementType().toString(); @@ -177,18 +178,20 @@ public void sendQueryToPolypheny() { //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) //handle result --> depending on query type, prepare answer message accordingly here (flush it) - sendResultToClient(type, data, header); + sendResultToClient( type, data, header ); } + /** * gets the information for the header + * * @param result the polyresult the additional information is needed * @return a list with array, where: - * - array[0] = columnName - * - array[1] = columnType + * - array[0] = columnName + * - array[1] = columnType */ - private ArrayList getHeader(PolyResult result) { //(request = query) + private ArrayList getHeader( PolyImplementation result ) { //(request = query) ArrayList header = new ArrayList<>(); for ( AlgDataTypeField metaData : result.getRowType().getFieldList() ) { String columnName = metaData.getName(); @@ -244,12 +247,13 @@ private ArrayList getHeader(PolyResult result) { //(request = query */ //header.add( dbCol ); - header.add(new String[]{columnName, dataType, String.valueOf(precision)}); + header.add( new String[]{ columnName, dataType, String.valueOf( precision ) } ); } return header; } - private ArrayList computeResultData(List> rows, ArrayList header) { + + private ArrayList computeResultData( List> rows, ArrayList header ) { //TODO(FF): bruuch ich de header do öberhaupt? (aso em momänt ned... ) --> hanich sache wonich de chönnt/müesst bruuche? //ha es paar sache useglöscht... aber wahrschiinli muesmer de no meh lösche... ArrayList data = new ArrayList<>(); @@ -273,7 +277,7 @@ private ArrayList computeResultData(List> rows, ArrayList case "SOUND": case "VIDEO": break; - //fall through + //fall through default: temp[counter] = o.toString(); } @@ -286,13 +290,12 @@ private ArrayList computeResultData(List> rows, ArrayList data.add( temp ); } - return data; } - public void sendResultToClient(String type, ArrayList data, ArrayList header) { - switch (type) { + public void sendResultToClient( String type, ArrayList data, ArrayList header ) { + switch ( type ) { case "INSERT": //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) //INSERT oid rows (oid=0, rows = #rows inserted) @@ -307,10 +310,9 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... 1....2....n....C....INSERT 0 1.Z....I */ - communicationHandler.sendParseBindComplete(); - communicationHandler.sendCommandCompleteInsert(rowsAffected); - communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendCommandCompleteInsert( rowsAffected ); + communicationHandler.sendReadyForQuery( "I" ); break; @@ -319,11 +321,11 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... //1....2....n....C....CREATE TABLE.Z....I communicationHandler.sendParseBindComplete(); communicationHandler.sendCommandCompleteCreateTable(); - communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendReadyForQuery( "I" ); break; - case "SELECT" : //also CREATE TABLE AS + case "SELECT": //also CREATE TABLE AS int lol = 4; ArrayList valuesPerCol = new ArrayList(); @@ -339,25 +341,22 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... //For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative // o. - - if (lol == 3) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... + if ( lol == 3 ) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... //noData //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) communicationHandler.sendParseBindComplete(); - communicationHandler.sendReadyForQuery("I"); - } - - else { + communicationHandler.sendReadyForQuery( "I" ); + } else { //data //for loop mache för jedi reihe? --> nocheluege wies gmacht werd em ächte psql met mehrere cols & reihe int numberOfFields = header.size(); - for (String[] head : header) { + for ( String[] head : header ) { fieldName = head[0]; //TODO(FF): Implement the rest of the cases - switch (head[1]) { + switch ( head[1] ) { case "BIGINT": case "DOUBLE": dataTypeSize = 8; //8 bytes signed @@ -378,8 +377,8 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "VARCHAR": objectIDCol = 1043; - typeModifier = Integer.parseInt(head[2]); - dataTypeSize = Integer.parseInt(head[2]); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize + typeModifier = Integer.parseInt( head[2] ); + dataTypeSize = Integer.parseInt( head[2] ); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize formatCode = 0; //dataTypeSize = 4; //formatCode = 1; @@ -404,33 +403,32 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... } //rowDescription //communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); - Object col[] = {fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode}; - valuesPerCol.add(col); + Object col[] = { fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode }; + valuesPerCol.add( col ); } communicationHandler.sendParseBindComplete(); - communicationHandler.sendRowDescription(numberOfFields, valuesPerCol); + communicationHandler.sendRowDescription( numberOfFields, valuesPerCol ); //sendData //communicationHandler.sendDataRow(data); - communicationHandler.sendDataRow2(data); + communicationHandler.sendDataRow2( data ); rowsAffected = data.size(); - communicationHandler.sendCommandCompleteSelect(rowsAffected); - - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); - communicationHandler.sendReadyForQuery("I"); + communicationHandler.sendCommandCompleteSelect( rowsAffected ); + + communicationHandler.sendReadyForQuery( "I" ); + communicationHandler.sendReadyForQuery( "I" ); + communicationHandler.sendReadyForQuery( "I" ); + communicationHandler.sendReadyForQuery( "I" ); + communicationHandler.sendReadyForQuery( "I" ); + communicationHandler.sendReadyForQuery( "I" ); } - //SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) //1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I //1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I break; - case "DELETE" : + case "DELETE": //DELETE rows (rows = #rows deleted) break; @@ -461,8 +459,6 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... (select_abst._1) */ - - //Example of server answer to simple select query (from real server) /* 1....2....T......lolid...@...............D..........1D..........2D..........3D..........3D..........3D..........3C... diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 5b424138642a8c311dde2379207bdcdd8bc12cf5..a71e6ae0ade3dc2e03095b0b88e08df5a489d6b1 100644 GIT binary patch delta 112 zcmaE&cv5i#6Z2$E=6#c&G3!niVo{y^idl_OVR8(M valuesPerCol) { + + public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { //I don't check for length, bcs rowDescription is always the same ByteBuf buffer = ctx.alloc().buffer(); //ByteBuf bufferTemp = ctx.alloc().buffer(); @@ -272,17 +268,17 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { int formatCode; int messageLength = 0; - buffer.writeByte(pgMsg.getHeaderChar()); + buffer.writeByte( pgMsg.getHeaderChar() ); - for (int i = 0; i( oder au ned? werom 8????? + buffer.writeShort( 1 ); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? - for(Object[] oneCol : valuesPerCol) { + for ( Object[] oneCol : valuesPerCol ) { ByteBuf bufferTemp = ctx.alloc().buffer(); fieldName = oneCol[0].toString(); objectIDTable = (Integer) oneCol[1]; @@ -294,26 +290,26 @@ public ByteBuf writeRowDescription(ArrayList valuesPerCol) { //messageLength += (fieldName.length() + 6); - bufferTemp.writeBytes(fieldName.getBytes(StandardCharsets.UTF_8)); - bufferTemp.writeByte(0); - bufferTemp.writeInt(objectIDTable); - bufferTemp.writeByte(0); - bufferTemp.writeShort(attributeNoCol); - bufferTemp.writeByte(0); - bufferTemp.writeInt(objectIDCol); //objectId of datatype? - bufferTemp.writeByte(0); - bufferTemp.writeShort(dataTypeSize); - bufferTemp.writeByte(0); - bufferTemp.writeInt(typeModifier); - bufferTemp.writeByte(0); - bufferTemp.writeShort(formatCode); //aber bem 4. esch denn do dezwösche en fähler cho, vorem nöchste flushl... werom au emmer??? --> be comission - - buffer.writeBytes(bufferTemp); //die erste 3x gohts ohni fähler + bufferTemp.writeBytes( fieldName.getBytes( StandardCharsets.UTF_8 ) ); + bufferTemp.writeByte( 0 ); + bufferTemp.writeInt( objectIDTable ); + bufferTemp.writeByte( 0 ); + bufferTemp.writeShort( attributeNoCol ); + bufferTemp.writeByte( 0 ); + bufferTemp.writeInt( objectIDCol ); //objectId of datatype? + bufferTemp.writeByte( 0 ); + bufferTemp.writeShort( dataTypeSize ); + bufferTemp.writeByte( 0 ); + bufferTemp.writeInt( typeModifier ); + bufferTemp.writeByte( 0 ); + bufferTemp.writeShort( formatCode ); //aber bem 4. esch denn do dezwösche en fähler cho, vorem nöchste flushl... werom au emmer??? --> be comission + + buffer.writeBytes( bufferTemp ); //die erste 3x gohts ohni fähler } //return buffer.writeBytes(bufferTemp); //String bla = new String(buffer.array(), Charset.defaultCharset()); - String bla = buffer.toString(Charset.defaultCharset()); + String bla = buffer.toString( Charset.defaultCharset() ); return buffer; } From c0dc2ae1f2d6a8bff7d02cba2758a96a43fd3883 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Mon, 10 Oct 2022 18:57:14 +0200 Subject: [PATCH 37/57] seems I didn't push before and only commited (?)... working select-response sent bytewise --- .../postgresql/PGInterfaceQueryHandler.java | 114 +++++++++++++----- 1 file changed, 82 insertions(+), 32 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index bf7cd6a642..9d6e2fc2b4 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -58,58 +58,108 @@ public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInter this.transactionManager = transactionManager; } - public void start() { hardcodeResponse(); + //hardcodeResponse2(); //sendQueryToPolypheny(); } + private void hardcodeResponse2() { + ByteBuf buffer = ctx.alloc().buffer(); + int[] nbr = {1, 2}; + buffer = writeIntArray(nbr, buffer); + buffer.writeByte('T'); + buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); + buffer.writeByte('@'); + buffer.writeByte('D'); + buffer.writeBytes("100".getBytes(StandardCharsets.UTF_8)); + buffer.writeByte('C'); + buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); + buffer.writeByte('Z'); + buffer.writeByte('I'); + ctx.writeAndFlush(buffer); + + } private void hardcodeResponse() { ByteBuf buffer = ctx.alloc().buffer(); + ByteBuf buffer2 = ctx.alloc().buffer(); /* 1....2....T......empid...@...............D..........100C....SELECT 1.Z....I - 1... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I - 1... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 + 1 ... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I + 31 ... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 */ - int[] nbrs = { 1, 0, 0, 0, 4 }; + //ParseComplete + //int[] nbrs = {1,0,0,0,4}; + int[] nbrs = {4}; + //BindComplete //2 - int[] nbrs2 = { 0, 0, 0, 4 }; + //int[] nbrs2 = {0,0,0,4}; + int[] nbrs2 = {4}; + //RowDescription //T - //int[] nbrs3 = {0,0,0,1e,0,1}; - int[] nbrs3 = { 0, 0, 0, 0, 0, 1 }; + //int[] nbrs3 = {0,0,0,1e,0,1}; --> 1e ist short länge?? etzt schtemmt nome no d reihefolg ned... + int[] nbrs3 = {1}; //empid //int[] nbrs4 = {0,0,0,40,0c,0,1,0,0,0,17,0,4,ff,ff,ff,ff,0,0}; - int[] nbrs4 = { 0, 0, 0, 40, 0, 0, 1, 0, 0, 0, 17, 0, 4, 0, 0, 0, 0, 0, 0 }; + int[] nbrs4 = {40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; //D //int[] nbrs5 = {0,0,0,0d,0,1,0,0,0,3}; - int[] nbrs5 = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 3 }; + int[] nbrs5 = {0,0,0,0,0,1,0,0,0,3}; //100C //int[] nbrs6 = {0,0,0,0d}; - int[] nbrs6 = { 0, 0, 0, 0 }; + int[] nbrs6 = {0,0,0,0}; //SELECT 1 - int[] nbrs7 = { 0 }; + int[] nbrs7 = {0}; //Z - int[] nbrs8 = { 0, 0, 0, 5 }; + int[] nbrs8 = {0,0,0,5}; //I - buffer = writeIntArray( nbrs, buffer ); - buffer.writeInt( 2 ); - buffer = writeIntArray( nbrs2, buffer ); - buffer.writeBytes( "T".getBytes( StandardCharsets.UTF_8 ) ); - buffer = writeIntArray( nbrs3, buffer ); - buffer.writeBytes( "empid".getBytes( StandardCharsets.UTF_8 ) ); - buffer = writeIntArray( nbrs4, buffer ); - buffer.writeBytes( "D".getBytes( StandardCharsets.UTF_8 ) ); - buffer = writeIntArray( nbrs5, buffer ); - buffer.writeBytes( "100C".getBytes( StandardCharsets.UTF_8 ) ); - buffer = writeIntArray( nbrs6, buffer ); - buffer.writeBytes( "SELECT 1".getBytes( StandardCharsets.UTF_8 ) ); - buffer = writeIntArray( nbrs7, buffer ); - buffer.writeBytes( "Z".getBytes( StandardCharsets.UTF_8 ) ); - buffer = writeIntArray( nbrs8, buffer ); - buffer.writeBytes( "I".getBytes( StandardCharsets.UTF_8 ) ); + buffer.writeByte('1'); + buffer = writeIntArray(nbrs, buffer); + //buffer.writeInt(2); + buffer.writeByte('2'); + buffer = writeIntArray(nbrs2, buffer); + buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); + buffer.writeShort(0); + buffer.writeShort(24+"empid".length() +1); //1e + buffer.writeShort(1); + //buffer = writeIntArray(nbrs3, buffer); + buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); + buffer.writeInt(64); //@ + //buffer.writeByte(64); + //buffer.writeShort(12); //1 abst. zvel zwösche 40 ond 0c + buffer.writeByte(12); //0c + buffer.writeShort(1); + buffer.writeShort(0); + buffer.writeShort(23); //17 + buffer.writeShort(4); + //ctx.writeAndFlush(buffer); + //buffer = writeIntArray(nbrs4, buffer); + buffer.writeShort(2147483647); //ff + buffer.writeShort(2147483647); + buffer.writeByte(0); + buffer.writeByte(0); + buffer.writeBytes("D".getBytes(StandardCharsets.UTF_8)); + buffer.writeShort(0); + buffer.writeShort(13); //0d + buffer.writeShort(1); + buffer.writeShort(0); + buffer.writeShort(3); + //buffer = writeIntArray(nbrs5, buffer); + buffer.writeBytes("100C".getBytes(StandardCharsets.UTF_8)); + buffer.writeShort(0); + buffer.writeShort(13); + //buffer2 = writeIntArray(nbrs6, buffer2); + buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); + //buffer2 = writeIntArray(nbrs7, buffer2); + buffer.writeByte(0); + buffer.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); + //buffer2 = writeIntArray(nbrs8, buffer2); + buffer.writeShort(0); + buffer.writeShort(5); + buffer.writeBytes("I".getBytes(StandardCharsets.UTF_8)); ctx.writeAndFlush( buffer ); @@ -182,14 +232,12 @@ public void sendQueryToPolypheny() { } - /** * gets the information for the header - * * @param result the polyresult the additional information is needed * @return a list with array, where: - * - array[0] = columnName - * - array[1] = columnType + * - array[0] = columnName + * - array[1] = columnType */ private ArrayList getHeader( PolyImplementation result ) { //(request = query) ArrayList header = new ArrayList<>(); @@ -459,6 +507,8 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... (select_abst._1) */ + + //Example of server answer to simple select query (from real server) /* 1....2....T......lolid...@...............D..........1D..........2D..........3D..........3D..........3D..........3C... From 09c7ff00b85c5a87cd7ec21f60d9b415116c720b Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Mon, 10 Oct 2022 20:47:51 +0200 Subject: [PATCH 38/57] a byte version that works and makes somehow a bit sense (analysis in comments)... as well as bugfix of CommandComplete --- ...GInterfaceInboundCommunicationHandler.java | 11 +- .../postgresql/PGInterfaceQueryHandler.java | 126 ++++++++++-------- 2 files changed, 75 insertions(+), 62 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index cda4b157d2..4e21986ff5 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -201,8 +201,10 @@ public void sendNoData() { public void sendCommandCompleteInsert( int rowsInserted ) { //send CommandComplete - insert - PGInterfaceMessage insertCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, "INSERT" + PGInterfaceMessage.getDelimiter() + "0" + PGInterfaceMessage.getDelimiter() + String.valueOf( rowsInserted ), 4, true ); - PGInterfaceServerWriter insertCommandCompleteWriter = new PGInterfaceServerWriter( "sss", insertCommandComplete, ctx ); + String body = "INSERT " + String.valueOf(rowsInserted); + //String body = "INSERT" + PGInterfaceMessage.getDelimiter() + "0" + PGInterfaceMessage.getDelimiter() + String.valueOf( rowsInserted ); + PGInterfaceMessage insertCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); + PGInterfaceServerWriter insertCommandCompleteWriter = new PGInterfaceServerWriter( "s", insertCommandComplete, ctx ); ctx.writeAndFlush( insertCommandCompleteWriter.writeOnByteBuf() ); } @@ -219,8 +221,9 @@ public void sendCommandCompleteCreateTable() { //for SELECT and CREATE TABLE AS public void sendCommandCompleteSelect( int rowsSelected ) { //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - String body = "SELECT " + String.valueOf( rowsSelected ); //TODO(FF): delimiter?? werom scheckts de scheiss ned???? - //"SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected) + String body = "SELECT " + String.valueOf( rowsSelected ); + //String body = "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected); + //String body = "SELECT" + PGInterfaceMessage.getDelimiter() + " " + PGInterfaceMessage.getDelimiter() + String.valueOf( rowsSelected ); PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter( "s", selectCommandComplete, ctx ); ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 9d6e2fc2b4..12e2d9ebc8 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -82,8 +82,12 @@ private void hardcodeResponse2() { } private void hardcodeResponse() { + ByteBuf buffer = ctx.alloc().buffer(); ByteBuf buffer2 = ctx.alloc().buffer(); + ByteBuf buffer3 = ctx.alloc().buffer(); + ByteBuf buffer4 = ctx.alloc().buffer(); + ByteBuf buffer5 = ctx.alloc().buffer(); /* 1....2....T......empid...@...............D..........100C....SELECT 1.Z....I @@ -91,77 +95,83 @@ private void hardcodeResponse() { 31 ... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 */ - //ParseComplete - //int[] nbrs = {1,0,0,0,4}; - int[] nbrs = {4}; - //BindComplete - //2 - //int[] nbrs2 = {0,0,0,4}; - int[] nbrs2 = {4}; + + /* + //parseComplete + buffer2.writeByte('1'); + //buffer = writeIntArray(nbrs, buffer); + buffer2.writeInt(4); + //bindComplete + buffer2.writeByte('2'); + //buffer = writeIntArray(nbrs2, buffer); + buffer2.writeInt(4); + ctx.writeAndFlush(buffer2); + */ + communicationHandler.sendParseBindComplete(); + //RowDescription - //T - //int[] nbrs3 = {0,0,0,1e,0,1}; --> 1e ist short länge?? etzt schtemmt nome no d reihefolg ned... - int[] nbrs3 = {1}; - //empid - //int[] nbrs4 = {0,0,0,40,0c,0,1,0,0,0,17,0,4,ff,ff,ff,ff,0,0}; - int[] nbrs4 = {40,0,0,1,0,0,0,17,0,4,0,0,0,0,0,0}; - //D - //int[] nbrs5 = {0,0,0,0d,0,1,0,0,0,3}; - int[] nbrs5 = {0,0,0,0,0,1,0,0,0,3}; - //100C - //int[] nbrs6 = {0,0,0,0d}; - int[] nbrs6 = {0,0,0,0}; - //SELECT 1 - int[] nbrs7 = {0}; - //Z - int[] nbrs8 = {0,0,0,5}; - //I - buffer.writeByte('1'); - buffer = writeIntArray(nbrs, buffer); - //buffer.writeInt(2); - buffer.writeByte('2'); - buffer = writeIntArray(nbrs2, buffer); buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); - buffer.writeShort(0); - buffer.writeShort(24+"empid".length() +1); //1e - buffer.writeShort(1); + //buffer.writeShort(23); + //buffer.writeShort(24+"empid".length() +1); //1e --> egal? + buffer.writeInt(24+"empid".length() +1); //egal? -20, +550... + buffer.writeShort(1); //mues stemme --> nbr of fields? //buffer = writeIntArray(nbrs3, buffer); buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer.writeInt(64); //@ + buffer.writeByte(0); //mues 0 sii... + buffer.writeInt(64); //@ --> egal: 654, 0 //buffer.writeByte(64); - //buffer.writeShort(12); //1 abst. zvel zwösche 40 ond 0c - buffer.writeByte(12); //0c - buffer.writeShort(1); - buffer.writeShort(0); - buffer.writeShort(23); //17 - buffer.writeShort(4); + buffer.writeShort(25); //1 abst. zvel zwösche 40 ond 0c + //buffer.writeByte(0); //0c --> egal (mer cha au d reihefolg zwösche short ond byte wächsle + //buffer.writeShort(1); //egal + //buffer.writeShort(0); + //buffer.writeShort(23); //17 + buffer.writeInt(23); //17 --> egal: 254, 0 + buffer.writeShort(4); //egal: 400, 0 //ctx.writeAndFlush(buffer); //buffer = writeIntArray(nbrs4, buffer); - buffer.writeShort(2147483647); //ff - buffer.writeShort(2147483647); - buffer.writeByte(0); - buffer.writeByte(0); - buffer.writeBytes("D".getBytes(StandardCharsets.UTF_8)); - buffer.writeShort(0); - buffer.writeShort(13); //0d - buffer.writeShort(1); - buffer.writeShort(0); - buffer.writeShort(3); + //buffer.writeShort(2147483647); //ff ff + //buffer.writeShort(2147483647); + buffer.writeInt(-1); //statt 2 short (ff wahrsch. -1?), egal: -1, 20, 2550, 0 + //buffer.writeByte(0); + //buffer.writeByte(0); //short statt 2 bytes + buffer.writeShort(0); //0 (54, 111): chonnt 1111111111 ah | 1: 825307441 + + //DataRow + buffer5.writeBytes("D".getBytes(StandardCharsets.UTF_8)); + buffer5.writeInt(20); //egal? --> 20, 200, 400, 0 + //buffer5.writeShort(0); //egal? --> 20, 200 (short met int ersetzt) + //buffer5.writeShort(13); //0d --> chonnt ned wörklech drufah was dren esch... (donkt mi) --> fonktioniert met 1 ond 200 + buffer5.writeShort(1); //das mues stemme, söscht warted de client + //buffer5.writeShort(0); //usegnoh, ond deför onders of int gwächslet + buffer5.writeInt("1111111111".length()); //length of the datatype --> mues stemme, sösch fähler + //buffer5.writeInt(4); //length of the datatype --> mues stemme, sösch fähler --> för writeInt = 4 //buffer = writeIntArray(nbrs5, buffer); - buffer.writeBytes("100C".getBytes(StandardCharsets.UTF_8)); - buffer.writeShort(0); - buffer.writeShort(13); + buffer5.writeBytes("1111111111".getBytes(StandardCharsets.UTF_8)); + //buffer5.writeInt(1111111111); + + //CommandComplete + buffer4.writeBytes("C".getBytes(StandardCharsets.UTF_8)); + buffer4.writeShort(0); + buffer4.writeShort(13); //buffer2 = writeIntArray(nbrs6, buffer2); - buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); + buffer4.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); //buffer2 = writeIntArray(nbrs7, buffer2); - buffer.writeByte(0); - buffer.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); + buffer4.writeByte(0); + + //ReadyForQuery + buffer3.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); //buffer2 = writeIntArray(nbrs8, buffer2); - buffer.writeShort(0); - buffer.writeShort(5); - buffer.writeBytes("I".getBytes(StandardCharsets.UTF_8)); + buffer3.writeShort(0); + buffer3.writeShort(5); + buffer3.writeBytes("I".getBytes(StandardCharsets.UTF_8)); + ctx.writeAndFlush( buffer ); + ctx.writeAndFlush( buffer5 ); + //ctx.writeAndFlush( buffer4 ); + communicationHandler.sendCommandCompleteSelect( 1 ); + //ctx.writeAndFlush( buffer3 ); + communicationHandler.sendReadyForQuery( "I" ); } From 93848f13f3b871d3ae43251196fbd971e44d5468 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 12 Oct 2022 09:20:23 +0200 Subject: [PATCH 39/57] One value single value is sent correctly!!! With no hardcodiing!! Yay!! --- ...GInterfaceInboundCommunicationHandler.java | 10 +++---- .../postgresql/PGInterfaceQueryHandler.java | 26 ++++++++----------- .../postgresql/PGInterfaceServerWriter.java | 16 ++++++------ 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 4e21986ff5..9792191b12 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -240,9 +240,9 @@ public void sendRowDescription( int numberOfFields, ArrayList valuesPe //ByteBuf test = ctx.alloc().buffer(); String body = String.valueOf( numberOfFields ); PGInterfaceMessage rowDescription = new PGInterfaceMessage( PGInterfaceHeaders.T, body, 4, true ); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription - PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "test", rowDescription, ctx ); - //ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); - ctx.writeAndFlush( rowDescriptionWriter.writeOnByteBuf() ); + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "i", rowDescription, ctx ); + ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); + //ctx.writeAndFlush( rowDescriptionWriter.writeOnByteBuf() ); } @@ -283,9 +283,9 @@ value of the col (in format indicated by associated format code) (string) dataRow = new PGInterfaceMessage( PGInterfaceHeaders.D, body, colValLength, false ); dataRowWriter = new PGInterfaceServerWriter( "dr", dataRow, ctx ); ctx.writeAndFlush( dataRowWriter.writeOnByteBuf() ); - ByteBuf buff = ctx.alloc().buffer(); + //ByteBuf buff = ctx.alloc().buffer(); //TODO(FF): das ergendwie no uselösche?? //C...SELECT 6 - buff.writeBytes( "C000SELECT 6".getBytes( StandardCharsets.UTF_8 ) ); + //buff.writeBytes( "C000SELECT 6".getBytes( StandardCharsets.UTF_8 ) ); body = ""; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 12e2d9ebc8..dd172a433d 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -59,9 +59,9 @@ public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInter } public void start() { - hardcodeResponse(); + //hardcodeResponse(); //hardcodeResponse2(); - //sendQueryToPolypheny(); + sendQueryToPolypheny(); } private void hardcodeResponse2() { @@ -117,8 +117,8 @@ private void hardcodeResponse() { buffer.writeShort(1); //mues stemme --> nbr of fields? //buffer = writeIntArray(nbrs3, buffer); buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); //mues 0 sii... - buffer.writeInt(64); //@ --> egal: 654, 0 + buffer.writeByte(0); //mues 0 sii... --> wennmers onde macht, ond int zgross esch, gets en fähler... + buffer.writeInt(1); //@ --> egal: 654, 0, 1111111111 //buffer.writeByte(64); buffer.writeShort(25); //1 abst. zvel zwösche 40 ond 0c //buffer.writeByte(0); //0c --> egal (mer cha au d reihefolg zwösche short ond byte wächsle @@ -391,6 +391,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 o int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 o int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified o + //send everything with writeBytes, if sent with writeInt it needs to be 1 int formatCode = 0; //int16 --> zero(text-inhalt (values)) or one(integer) --> if returned from describe, not yet known = 0 o. int typeModifier = -1; //The value will generally be -1 for types that do not need atttypmod. --> type specific data (supplied at table creation time o @@ -418,7 +419,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... case "BIGINT": case "DOUBLE": dataTypeSize = 8; //8 bytes signed - formatCode = 1; //TODO(FF): esch das rechtig? wel es heisst e de doc darstellig vo Integer... + formatCode = 0; //TODO(FF): esch das rechtig? wel es heisst e de doc darstellig vo Integer... break; case "BOOLEAN": dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? @@ -431,7 +432,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... case "INTEGER": objectIDCol = 32; dataTypeSize = 4; - formatCode = 1; //Test with 0, normally 1 (?) + formatCode = 0; //Test with 0, normally 1 (?) break; case "VARCHAR": objectIDCol = 1043; @@ -443,11 +444,11 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "SMALLINT": dataTypeSize = 2; - formatCode = 1; + formatCode = 0; break; case "TINYINT": dataTypeSize = 1; - formatCode = 1; + formatCode = 0; break; case "TIMESTAMP": break; @@ -467,18 +468,13 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... communicationHandler.sendParseBindComplete(); communicationHandler.sendRowDescription( numberOfFields, valuesPerCol ); //sendData - //communicationHandler.sendDataRow(data); - communicationHandler.sendDataRow2( data ); + communicationHandler.sendDataRow(data); + //communicationHandler.sendDataRow2( data ); rowsAffected = data.size(); communicationHandler.sendCommandCompleteSelect( rowsAffected ); communicationHandler.sendReadyForQuery( "I" ); - communicationHandler.sendReadyForQuery( "I" ); - communicationHandler.sendReadyForQuery( "I" ); - communicationHandler.sendReadyForQuery( "I" ); - communicationHandler.sendReadyForQuery( "I" ); - communicationHandler.sendReadyForQuery( "I" ); } //SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 9d40af86a2..4bd6e758ea 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -176,11 +176,11 @@ public ByteBuf writeOnByteBuf() { ByteBuf buffer6 = ctx.alloc().buffer(); buffer4.writeInt( Integer.parseInt( msgParts[i] ) ); //onde: müesst 10 schecke... ctx.writeAndFlush( buffer4 ); //2. durchgang, hier fehler chönnts - //buffer5.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? - buffer5.writeInt( Integer.parseInt( msgParts[i + 1] ) ); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? + buffer5.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? + //buffer5.writeInt( Integer.parseInt( msgParts[i + 1] ) ); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? ctx.writeAndFlush( buffer5 ); //buffer6.writeBytes(msgParts[i+2].getBytes(StandardCharsets.UTF_8)); - buffer6.writeByte( 0 ); + //buffer6.writeByte( 0 ); //ctx.writeAndFlush(buffer6); test += msgParts[i] + " | " + msgParts[i + 1] + " | "; @@ -293,15 +293,15 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { bufferTemp.writeBytes( fieldName.getBytes( StandardCharsets.UTF_8 ) ); bufferTemp.writeByte( 0 ); bufferTemp.writeInt( objectIDTable ); - bufferTemp.writeByte( 0 ); + //bufferTemp.writeByte( 0 ); bufferTemp.writeShort( attributeNoCol ); - bufferTemp.writeByte( 0 ); + //bufferTemp.writeByte( 0 ); bufferTemp.writeInt( objectIDCol ); //objectId of datatype? - bufferTemp.writeByte( 0 ); + //bufferTemp.writeByte( 0 ); bufferTemp.writeShort( dataTypeSize ); - bufferTemp.writeByte( 0 ); + //bufferTemp.writeByte( 0 ); bufferTemp.writeInt( typeModifier ); - bufferTemp.writeByte( 0 ); + //bufferTemp.writeByte( 0 ); bufferTemp.writeShort( formatCode ); //aber bem 4. esch denn do dezwösche en fähler cho, vorem nöchste flushl... werom au emmer??? --> be comission buffer.writeBytes( bufferTemp ); //die erste 3x gohts ohni fähler From 1db8cd173eb2e59079b76b049d4273413fa2ee1c Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 12 Oct 2022 09:38:04 +0200 Subject: [PATCH 40/57] select * woooorks!!!! --- .../postgresql/PGInterfaceServerWriter.java | 35 +++++-------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 4bd6e758ea..680089fdd6 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -133,34 +133,24 @@ public ByteBuf writeOnByteBuf() { case "dr": //send dataRow String test = ""; - ByteBuf buffer7 = ctx.alloc().buffer(); - buffer7.writeByte( pgMsg.getHeaderChar() ); - //buffer7.writeByte('X'); - ctx.writeAndFlush( buffer7 ); + buffer.writeByte( pgMsg.getHeaderChar() ); test += pgMsg.getHeaderChar() + " | "; - ByteBuf buffer1 = ctx.alloc().buffer(); - ByteBuf buffer2 = ctx.alloc().buffer(); - ByteBuf buffer3 = ctx.alloc().buffer(); - int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll( "§", "" ).length()) / 2; //should generally be not the default length, but also works with default length & length = 4 if ( pgMsg.isDefaultLength() ) { //data row does not include msg-length bytes in msg length - buffer1.writeInt( pgMsg.getLength() - (nbrCol * 2) ); - ctx.writeAndFlush( buffer1 ); + buffer.writeInt( pgMsg.getLength() - (nbrCol * 2) ); int lol = (pgMsg.getLength() - (nbrCol * 2)); test += lol + " | "; } else { //bcs it is including self - buffer2.writeInt( pgMsg.getLength() + 4 ); - ctx.writeAndFlush( buffer2 ); + buffer.writeInt( pgMsg.getLength() + 4 ); test += pgMsg.getLength() + " | "; } - buffer3.writeShort( nbrCol ); //mues das evtl au 8 sii??? - ctx.writeAndFlush( buffer3 ); + buffer.writeShort( nbrCol ); //mues das evtl au 8 sii??? test += nbrCol + " | "; //cut the last § (it is at the end) from the msgBody and set it as the new msgBody @@ -171,17 +161,8 @@ public ByteBuf writeOnByteBuf() { String[] msgParts = pgMsg.getMsgPart( idx ); for ( int i = 0; i < ((nbrCol * 2) - 1); i++ ) { //i<=10? hätt etzt gseit nei - ByteBuf buffer4 = ctx.alloc().buffer(); - ByteBuf buffer5 = ctx.alloc().buffer(); - ByteBuf buffer6 = ctx.alloc().buffer(); - buffer4.writeInt( Integer.parseInt( msgParts[i] ) ); //onde: müesst 10 schecke... - ctx.writeAndFlush( buffer4 ); //2. durchgang, hier fehler chönnts - buffer5.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? - //buffer5.writeInt( Integer.parseInt( msgParts[i + 1] ) ); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? - ctx.writeAndFlush( buffer5 ); - //buffer6.writeBytes(msgParts[i+2].getBytes(StandardCharsets.UTF_8)); - //buffer6.writeByte( 0 ); - //ctx.writeAndFlush(buffer6); + buffer.writeInt( Integer.parseInt( msgParts[i] ) ); //onde: müesst 10 schecke... + buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? test += msgParts[i] + " | " + msgParts[i + 1] + " | "; @@ -275,8 +256,8 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { } buffer.writeInt( pgMsg.getLength() + messageLength ); - //buffer.writeShort(Integer.parseInt(pgMsg.getMsgBody())); - buffer.writeShort( 1 ); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? + buffer.writeShort(Integer.parseInt(pgMsg.getMsgBody())); + //buffer.writeShort( 1 ); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? for ( Object[] oneCol : valuesPerCol ) { ByteBuf bufferTemp = ctx.alloc().buffer(); From 8beef66e56052452e6e4c6dfa2ee9e3aeb6fbc2c Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 12 Oct 2022 15:14:57 +0200 Subject: [PATCH 41/57] Some code cleanup and documentation --- ...GInterfaceInboundCommunicationHandler.java | 152 ++++++----------- .../db/postgresql/PGInterfaceMessage.java | 19 ++- .../postgresql/PGInterfaceQueryHandler.java | 161 ++++++++---------- .../postgresql/PGInterfaceServerHandler.java | Bin 4297 -> 1842 bytes .../postgresql/PGInterfaceServerWriter.java | 149 ++++++---------- 5 files changed, 189 insertions(+), 292 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 9792191b12..c9e985b849 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -18,13 +18,12 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import org.polypheny.db.transaction.TransactionManager; /** - * Manages all incoming communication, not using the netty framework + * Manages all incoming communication, not using the netty framework (but being a handler in netty) */ public class PGInterfaceInboundCommunicationHandler { @@ -55,7 +54,6 @@ public void decideCycle( Object oMsg ) { case "C": //TODO(FF):was gnau passiert do?? PGInterfaceMessage msg = null; msg.setHeader( PGInterfaceHeaders.C ); - //msg.setMsgBody(); break; case "r": startUpPhase(); @@ -71,6 +69,10 @@ public void decideCycle( Object oMsg ) { } + /** + * Performs necessary steps on the first connection with the client (mostly sends necessary replies, but doesn't really set anything on the server side). + * Sends authenticationOk (without checking authentication), sets server version, sends readyForQuery + */ public void startUpPhase() { //authenticationOk PGInterfaceMessage authenticationOk = new PGInterfaceMessage( PGInterfaceHeaders.R, "0", 8, false ); @@ -78,8 +80,7 @@ public void startUpPhase() { ctx.writeAndFlush( authenticationOkWriter.writeOnByteBuf() ); //server_version (Parameter Status message) - PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage( PGInterfaceHeaders.S, "server_version§14", 4, true ); - //PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter( "ss", parameterStatusServerVs, ctx ); ctx.writeAndFlush( parameterStatusServerVsWriter.writeOnByteBuf() ); @@ -89,24 +90,25 @@ public void startUpPhase() { public void simpleQueryPhase() { - + //TODO(FF): (low priority) The simple query phase is handled a bit differently than the extended query phase. The most important difference is that the simple query phase accepts several queries at once and sends some different response messages (e.g. no parse/bindComplete). + //Several queries seperated with ";" } + /** + * Sends necessary responses to client (without really setting anything in backend) and prepares the incoming query for usage. Continues query forward to QueryHandler + * @param incomingMsg unchanged incoming message (transformed to string by netty) + */ public void extendedQueryPhase( String incomingMsg ) { if ( incomingMsg.substring( 2, 5 ).equals( "SET" ) ) { sendParseBindComplete(); - sendParseBindComplete(); - - //commandComplete - SET - PGInterfaceMessage commandCompleteSET = new PGInterfaceMessage( PGInterfaceHeaders.C, "SET", 4, true ); - PGInterfaceServerWriter commandCompleteSETWriter = new PGInterfaceServerWriter( "s", commandCompleteSET, ctx ); - ctx.writeAndFlush( commandCompleteSETWriter.writeOnByteBuf() ); + sendCommandComplete("SET", -1); sendReadyForQuery( "I" ); + } else { //Query does not have ";" at the end!! String query = extractQuery( incomingMsg ); @@ -114,15 +116,13 @@ public void extendedQueryPhase( String incomingMsg ) { queryHandler.start(); } - - } /** - * creates and sends (flushes on ctx) a readyForQuery message. Tag is choosable. + * Creates and sends (flushes on ctx) a readyForQuery message with a tag. The tag is choosable (see below for options). * - * @param msgBody give the Tag - current transaction status indicator (possible vals: I (idle, not in transaction block), + * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) */ public void sendReadyForQuery( String msgBody ) { @@ -133,7 +133,8 @@ public void sendReadyForQuery( String msgBody ) { /** - * prepares the incoming message from the client, so it can be used in the context of polypheny + * Prepares (parses) the incoming message from the client, so it can be used in the context of polypheny + * NOTE: Some incoming messages from the client are disregarded (they are sent the same way all the time, if something unusual occurs, this is not handled yet, i.e. hardcoded to find the end of the query itself). * * @param incomingMsg unchanged incoming message from the client * @return "normally" readable and usable query string @@ -143,8 +144,8 @@ public String extractQuery( String incomingMsg ) { //cut header query = incomingMsg.substring( 2, incomingMsg.length() - 1 ); - //find end of query --> normally it ends with combination of BDPES (are headers, with some weird other bits in between) - //B starts immediatelly after query --> find position of correct B and end of query is found + //find end of query --> normally it ends with combination of BDPES (are headers (some indicators from client), with some weird other bits in between) + //B starts immediately after query --> find position of correct B and end of query is found byte[] byteSequence = { 66, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 6, 80, 0, 69, 0, 0, 0, 9 }; String msgWithZeroBits = new String( byteSequence, StandardCharsets.UTF_8 ); String endSequence = msgWithZeroBits.replace( "\u0000", "" ); @@ -183,109 +184,90 @@ public void sendParseBindComplete() { PGInterfaceMessage mockMessage = new PGInterfaceMessage( PGInterfaceHeaders.ONE, "0", 4, true ); PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter( "i", mockMessage, ctx ); buffer = headerWriter.writeIntHeaderOnByteBuf( '1' ); - //ctx.writeAndFlush(buffer); buffer.writeBytes( headerWriter.writeIntHeaderOnByteBuf( '2' ) ); - //buffer = headerWriter.writeIntHeaderOnByteBuf('2'); ctx.writeAndFlush( buffer ); } + public void sendNoData() { - //TODO(FF) wenn gnau esch das öberhaupt nötig? Wenn de client kei date scheckt --> aber wenn esch das es problem? + //TODO(FF): not entirely sure in which case this would be needed? PGInterfaceMessage noData = new PGInterfaceMessage( PGInterfaceHeaders.n, "0", 4, true ); PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx ); ctx.writeAndFlush( noDataWriter.writeOnByteBuf() ); } - public void sendCommandCompleteInsert( int rowsInserted ) { - //send CommandComplete - insert - String body = "INSERT " + String.valueOf(rowsInserted); - //String body = "INSERT" + PGInterfaceMessage.getDelimiter() + "0" + PGInterfaceMessage.getDelimiter() + String.valueOf( rowsInserted ); - PGInterfaceMessage insertCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); - PGInterfaceServerWriter insertCommandCompleteWriter = new PGInterfaceServerWriter( "s", insertCommandComplete, ctx ); - ctx.writeAndFlush( insertCommandCompleteWriter.writeOnByteBuf() ); - - } - + /** + * Sends CommandComplete to client, with choosable command type + * @param command which command is completed (no space afterwards, space is added here) + * @param rowsAffected number of rows affected (if it is not necessary to send a number, put -1) + */ + public void sendCommandComplete( String command, int rowsAffected ) { + String body = ""; + PGInterfaceMessage commandComplete; + PGInterfaceServerWriter commandCompleteWriter; - public void sendCommandCompleteCreateTable() { - //send CommandComplete - create table - PGInterfaceMessage createTableCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, "CREATE TABLE", 4, true ); - PGInterfaceServerWriter createTableCommandCompleteWriter = new PGInterfaceServerWriter( "s", createTableCommandComplete, ctx ); - ctx.writeAndFlush( createTableCommandCompleteWriter.writeOnByteBuf() ); - } + if ( rowsAffected == -1) { + body = command; + } else { + body = command + " " + String.valueOf( rowsAffected ); + } - //for SELECT and CREATE TABLE AS - public void sendCommandCompleteSelect( int rowsSelected ) { - //send CommandComplete - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - String body = "SELECT " + String.valueOf( rowsSelected ); - //String body = "SELECT"+ PGInterfaceMessage.getDelimiter() + String.valueOf(rowsSelected); - //String body = "SELECT" + PGInterfaceMessage.getDelimiter() + " " + PGInterfaceMessage.getDelimiter() + String.valueOf( rowsSelected ); - PGInterfaceMessage selectCommandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); - PGInterfaceServerWriter selectCommandCompleteWriter = new PGInterfaceServerWriter( "s", selectCommandComplete, ctx ); - ByteBuf buf = selectCommandCompleteWriter.writeOnByteBuf(); - String lol = buf.toString( Charset.defaultCharset() ); - ctx.writeAndFlush( buf ); + commandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); + commandCompleteWriter = new PGInterfaceServerWriter( "s", commandComplete, ctx ); + ctx.writeAndFlush( commandCompleteWriter.writeOnByteBuf() ); } + /** + * Prepares everything to send rowDescription + * @param numberOfFields how many fields are in a row of the result + * @param valuesPerCol The values that should be sent for each field (information about each column) + */ public void sendRowDescription( int numberOfFields, ArrayList valuesPerCol ) { - //String fieldName, int objectIDTable, int attributeNoCol, int objectIDCol, int dataTypeSize, int typeModifier, int formatCode - - //bytebuf.writeInt(int value) = 32-bit int - //bytebuf.writeShort(int value) = 16-bit short integer; - //ByteBuf test = ctx.alloc().buffer(); String body = String.valueOf( numberOfFields ); PGInterfaceMessage rowDescription = new PGInterfaceMessage( PGInterfaceHeaders.T, body, 4, true ); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "i", rowDescription, ctx ); ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); - //ctx.writeAndFlush( rowDescriptionWriter.writeOnByteBuf() ); } + /** + * Prepares everything to send DataRows, with its corresponding needed information + * @param data data that should be sent + */ public void sendDataRow( ArrayList data ) { - /* - DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: (int16) - length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), (int32) - value of the col (in format indicated by associated format code) (string) - - */ - int noCols = data.size(); //number of rows returned --> belongs to rowDescription (?) - String colVal = ""; - int nbrFollowingColVal = data.get( 0 ).length; //int16 --> length of String[] --> nbr of column values that follow - int colValLength = 0; //int32 --> length of one String[i] (length of actual string) (n) - String body = ""; //Byte*n* --> the string itself String[i] + int noCols = data.size(); //number of rows returned + String colVal = ""; //The value of the result + int colValLength = 0; //length of the colVal - can be 0 and -1 (-1= NULL is colVal) + String body = ""; //combination of colVal and colValLength + int nbrFollowingColVal = data.get( 0 ).length; PGInterfaceMessage dataRow; PGInterfaceServerWriter dataRowWriter; for ( int i = 0; i < noCols; i++ ) { - //can be 0 and -1 (= NULL col val) for ( int j = 0; j < nbrFollowingColVal; j++ ) { - //if colValLength -1 : nothing sent at all colVal = data.get( i )[j]; //TODO(FF): How is null safed in polypheny exactly?? is it correctly checked? if ( colVal == "NULL" ) { colValLength = -1; - //scheck kei body + //no body should be sent break; } else { colValLength += colVal.length(); body += colVal.length() + PGInterfaceMessage.getDelimiter() + colVal + PGInterfaceMessage.getDelimiter(); } - } //do gets glaubs ergendwo neu en fähler? + } dataRow = new PGInterfaceMessage( PGInterfaceHeaders.D, body, colValLength, false ); dataRowWriter = new PGInterfaceServerWriter( "dr", dataRow, ctx ); ctx.writeAndFlush( dataRowWriter.writeOnByteBuf() ); - //ByteBuf buff = ctx.alloc().buffer(); //TODO(FF): das ergendwie no uselösche?? - //C...SELECT 6 - //buff.writeBytes( "C000SELECT 6".getBytes( StandardCharsets.UTF_8 ) ); body = ""; } @@ -296,28 +278,4 @@ value of the col (in format indicated by associated format code) (string) public void terminateConnection() { ctx.close(); } - - - public void sendDataRow2( ArrayList data ) { - ByteBuf buf = ctx.alloc().buffer(); - // 44 00 00 00 0b 00 01 00 00 00 01 31 - //buf.writeBytes("440000b01000131".getBytes()); - buf.writeInt( 44 ); - buf.writeInt( 0 ); - buf.writeInt( 0 ); - buf.writeInt( 0 ); - buf.writeInt( 0 ); // - buf.writeInt( 0 ); - buf.writeInt( 1 ); - buf.writeInt( 0 ); - buf.writeInt( 0 ); - buf.writeInt( 0 ); - buf.writeInt( 1 ); - buf.writeInt( 31 ); - String lol = buf.toString( Charset.defaultCharset() ); - ctx.writeAndFlush( buf ); - - - } - } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 873b234f68..77bba51154 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -26,6 +26,13 @@ public class PGInterfaceMessage { private static final char delimiter = '§'; //for the subparts + /** + * Creates a PG-Message. It contains all relevant information to send a message to the client + * @param header What header should be sent (depends on message-type) + * @param msgBody The message itself + * @param length The length of the message (the length itself is included) + * @param defaultLength The length of the length sent (which is included). Length is 4 + */ public PGInterfaceMessage( PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength ) { this.header = header; this.msgBody = msgBody; @@ -47,7 +54,7 @@ public char getHeaderChar() { return headerString.charAt( 0 ); } //if header is a number - //TODO: make a nicer version of this... if you cast headerInt to char directly it returns '\u0001' and not '1' + //TODO(FF): make a nicer version of this... if you cast headerInt to char directly it returns '\u0001' and not '1' else { int headerInt = getHeaderInt(); if ( headerInt == 1 ) { @@ -58,7 +65,7 @@ public char getHeaderChar() { return '3'; } } - //TODO: if returns 0, something went wrong + //TODO(FF): if returns 0, something went wrong --> inform client return 0; } @@ -72,7 +79,7 @@ public int getHeaderInt() { } else if ( headerString.equals( "THREE" ) ) { return 3; } - //TODO: if returns 0, something went wrong + //TODO(FF): if returns 0, something went wrong return 0; } @@ -113,7 +120,7 @@ public void setMsgBody( String msgBody ) { /** - * gets the different subparts of a message + * Gets the different sub-parts of a message * * @param part the index of the requested part(s), starting at 0 * @return a string array with each requested part @@ -129,6 +136,10 @@ public String[] getMsgPart( int[] part ) { } + /** + * Get what delimiter is currently set + * @return the current delimiter as string + */ public static String getDelimiter() { String del = String.valueOf( delimiter ); return del; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index dd172a433d..c463be85c4 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -60,27 +60,9 @@ public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInter public void start() { //hardcodeResponse(); - //hardcodeResponse2(); sendQueryToPolypheny(); } - private void hardcodeResponse2() { - ByteBuf buffer = ctx.alloc().buffer(); - int[] nbr = {1, 2}; - buffer = writeIntArray(nbr, buffer); - buffer.writeByte('T'); - buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte('@'); - buffer.writeByte('D'); - buffer.writeBytes("100".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte('C'); - buffer.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte('Z'); - buffer.writeByte('I'); - ctx.writeAndFlush(buffer); - - } - private void hardcodeResponse() { ByteBuf buffer = ctx.alloc().buffer(); @@ -169,24 +151,18 @@ private void hardcodeResponse() { ctx.writeAndFlush( buffer ); ctx.writeAndFlush( buffer5 ); //ctx.writeAndFlush( buffer4 ); - communicationHandler.sendCommandCompleteSelect( 1 ); + communicationHandler.sendCommandComplete( "SELECT", 1 ); //ctx.writeAndFlush( buffer3 ); communicationHandler.sendReadyForQuery( "I" ); } - private ByteBuf writeIntArray( int[] nbrs, ByteBuf buffer ) { - for ( int i = 0; i < nbrs.length; i++ ) { - buffer.writeInt( nbrs[i] ); - } - return buffer; - } - - + /** + * Forwards the message to Polypheny, and get result from it + */ public void sendQueryToPolypheny() { - String type = ""; //query type according to answer tags - //get result from polypheny + String type = ""; //query type according to answer tags Transaction transaction; Statement statement = null; PolyImplementation result; @@ -198,13 +174,13 @@ public void sendQueryToPolypheny() { transaction = transactionManager.startTransaction( Catalog.defaultUserId, Catalog.defaultDatabaseId, false, "Index Manager" ); statement = transaction.createStatement(); } catch ( UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e ) { + //TODO(FF): Inform client that something went wrong throw new RuntimeException( "Error while starting transaction", e ); } //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) - //for loop zom dor alli catalogTables doregoh? - nei Processor sqlProcessor = statement.getTransaction().getProcessor( Catalog.QueryLanguage.SQL ); - Node sqlNode = sqlProcessor.parse( query ).get( 0 ); //go gehts fähler: (see diary) + Node sqlNode = sqlProcessor.parse( query ).get( 0 ); QueryParameters parameters = new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ); if ( sqlNode.isA( Kind.DDL ) ) { result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); @@ -223,41 +199,36 @@ public void sendQueryToPolypheny() { } //get type information - from crud.java - //Type of ArrayList was DbColumn, but belongs to webUI (so I don't need it...) --> replaced it with string? - //ArrayList header = getHeader(result, query); //descriptor för jedi col befors es resultat get (aahgehni ziile) --> de muesi no hole?? -header = getHeader( result ); - //statement.executeUpdate("SELECT empid FROM public.emps"); + header = getHeader( result ); //get actual result of query in array - from crud.java - rows = result.getRows( statement, -1 ); //-1 as size valid?? - data = computeResultData( rows, header ); //, statement.getTransaction() + rows = result.getRows( statement, -1 ); + data = computeResultData( rows, header ); - //type = result.getStatementType().name(); type = result.getStatementType().toString(); - //how to handle reusable queries?? (do i have to safe them/check if it is reusable?) + //TODO(FF): how to handle reusable queries?? (do i have to safe them/check if it is reusable?) - //handle result --> depending on query type, prepare answer message accordingly here (flush it) + //handle result, depending on query type sendResultToClient( type, data, header ); } /** - * gets the information for the header - * @param result the polyresult the additional information is needed + * Gets the information for the header - Information for each column + * @param result the PolyImplementation the additional information is needed for * @return a list with array, where: * - array[0] = columnName * - array[1] = columnType + * - array[2] = precision */ - private ArrayList getHeader( PolyImplementation result ) { //(request = query) + private ArrayList getHeader( PolyImplementation result ) { ArrayList header = new ArrayList<>(); for ( AlgDataTypeField metaData : result.getRowType().getFieldList() ) { String columnName = metaData.getName(); - //final String name = metaData.getName(); - String dataType = metaData.getType().getPolyType().getTypeName(); //INTEGER, VARCHAR --> aber ergendwie ohnis (20) em header?? - int precision = metaData.getType().getPrecision(); //sizeVarChar + String dataType = metaData.getType().getPolyType().getTypeName(); //INTEGER, VARCHAR + int precision = metaData.getType().getPrecision(); //sizeVarChar, decimal places double boolean nullable = metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1); - //Integer precision = metaData.getType().getPrecision(); //For each column: If it should be filtered empty string if it should not be filtered /* @@ -304,20 +275,24 @@ private ArrayList getHeader( PolyImplementation result ) { //(reque } */ - //header.add( dbCol ); header.add( new String[]{ columnName, dataType, String.valueOf( precision ) } ); } return header; } + /** + * Transforms the data into Strings. Possble to expand and change it into other datatypes + * @param rows The result-data as object-type + * @param header Header-data - additional information about the data (rows) + * @return the rows transformed accordingly (right now turned into a string) + */ private ArrayList computeResultData( List> rows, ArrayList header ) { //TODO(FF): bruuch ich de header do öberhaupt? (aso em momänt ned... ) --> hanich sache wonich de chönnt/müesst bruuche? - //ha es paar sache useglöscht... aber wahrschiinli muesmer de no meh lösche... ArrayList data = new ArrayList<>(); for ( List row : rows ) { - String[] temp = new String[row.size()]; //temp esch au 100 --> vo resultat sälber... + String[] temp = new String[row.size()]; int counter = 0; for ( Object o : row ) { if ( o == null ) { @@ -343,7 +318,7 @@ private ArrayList computeResultData( List> rows, ArrayLis } } - counter++; //was macht gnau de counter? (esch etzt 1, chonnt add), rows size = 4 + counter++; } data.add( temp ); } @@ -352,10 +327,16 @@ private ArrayList computeResultData( List> rows, ArrayLis } + /** + * Prepares according to the query from the client what (and how) should be sent as a response + * @param type Type of the query (e.g.: Select, Insert, Create Table, etc.) + * @param data The data that needs to be sent to the client + * @param header Additional information for the data + */ public void sendResultToClient( String type, ArrayList data, ArrayList header ) { switch ( type ) { case "INSERT": - //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) + //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) (put it in header?) but not here, done in sendToPolypheny //INSERT oid rows (oid=0, rows = #rows inserted) //1....2....n....C....INSERT 0 1.Z....I @@ -369,46 +350,41 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... */ communicationHandler.sendParseBindComplete(); - communicationHandler.sendCommandCompleteInsert( rowsAffected ); + communicationHandler.sendCommandComplete( type, rowsAffected ); communicationHandler.sendReadyForQuery( "I" ); break; case "CREATE TABLE": - //TODO(FF) do things in polypheny (?) + //TODO(FF) do things in polypheny (?) --> not here, but check what to do with commits //1....2....n....C....CREATE TABLE.Z....I communicationHandler.sendParseBindComplete(); - communicationHandler.sendCommandCompleteCreateTable(); + //communicationHandler.sendCommandCompleteCreateTable(); + communicationHandler.sendCommandComplete( type, -1 ); communicationHandler.sendReadyForQuery( "I" ); break; - case "SELECT": //also CREATE TABLE AS + case "SELECT": int lol = 4; ArrayList valuesPerCol = new ArrayList(); - String fieldName = ""; //get field name from query? momentan no de einzig val em header o - int objectIDTable = 0; //int32 --> eig. ObjectID of table (if col can be id'd to table) --> otherwise 0 o - int attributeNoCol = 0; //int16 --> attr.no of col (if col can be id'd to table) --> otherwise 0 o - int objectIDCol = 0; //int32 --> objectID of parameter datatype (specified in parse message (F), at the end) --> 0=unspecified o - //send everything with writeBytes, if sent with writeInt it needs to be 1 - int formatCode = 0; //int16 --> zero(text-inhalt (values)) or one(integer) --> if returned from describe, not yet known = 0 o. - int typeModifier = -1; //The value will generally be -1 for types that do not need atttypmod. --> type specific data (supplied at table creation time o - - int dataTypeSize = 0; //int16 --> polypheny website typedocumentation aaluege (real=double in polypheny) --> in postgresqlStore shauen welche grösse wie gemappt - //gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) --> irgendwas mit negative vals=variable width types - //For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative - // o. + String fieldName = ""; //string - column name (field name) (matters) + int objectIDTable = 0; //int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + int attributeNoCol = 0; //int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + int objectIDColDataType = 0; //int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending) + int dataTypeSize = 0; //int16 - size of dataType (if formatCode = 1, this needs to be set for colValLength) (doesn't matter to client while sending) + int typeModifier = -1; //int32 - The value will generally be -1 (doesn't matter to client while sending) + int formatCode = 0; //int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) - if ( lol == 3 ) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... + if ( lol == 3 ) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... Verdacht: eif normal schecke, halt eif alles 0 ond kei date //noData - //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) + //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) error when sent here - communicationHandler.sendParseBindComplete(); communicationHandler.sendReadyForQuery( "I" ); } else { //data - //for loop mache för jedi reihe? --> nocheluege wies gmacht werd em ächte psql met mehrere cols & reihe - int numberOfFields = header.size(); + int numberOfFields = header.size(); //int16 - number of fields (cols) (matters) for ( String[] head : header ) { @@ -418,8 +394,9 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... switch ( head[1] ) { case "BIGINT": case "DOUBLE": + //TODO(FF): head[2] is the number of decimal places, is set to 3 in standard postgres ("dismissed in beginning, not checked what it actually is") dataTypeSize = 8; //8 bytes signed - formatCode = 0; //TODO(FF): esch das rechtig? wel es heisst e de doc darstellig vo Integer... + formatCode = 0; break; case "BOOLEAN": dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? @@ -430,17 +407,15 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "REAL": case "INTEGER": - objectIDCol = 32; + //objectIDColDataType = 32; dataTypeSize = 4; - formatCode = 0; //Test with 0, normally 1 (?) + formatCode = 0; break; case "VARCHAR": - objectIDCol = 1043; + //objectIDColDataType = 1043; typeModifier = Integer.parseInt( head[2] ); - dataTypeSize = Integer.parseInt( head[2] ); //TODO(FF): wennd varchar längi de type modifier esch, was esch denn dataTypeSize + dataTypeSize = Integer.parseInt( head[2] ); //TODO(FF): I just send the length of the varchar here, because the client doesn't complain. formatCode = 0; - //dataTypeSize = 4; - //formatCode = 1; break; case "SMALLINT": dataTypeSize = 2; @@ -460,26 +435,17 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... case "VIDEO": break; } - //rowDescription - //communicationHandler.sendRowDescription(fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode); - Object col[] = { fieldName, objectIDTable, attributeNoCol, objectIDCol, dataTypeSize, typeModifier, formatCode }; + Object col[] = { fieldName, objectIDTable, attributeNoCol, objectIDColDataType, dataTypeSize, typeModifier, formatCode }; valuesPerCol.add( col ); } communicationHandler.sendParseBindComplete(); communicationHandler.sendRowDescription( numberOfFields, valuesPerCol ); - //sendData communicationHandler.sendDataRow(data); - //communicationHandler.sendDataRow2( data ); rowsAffected = data.size(); - communicationHandler.sendCommandCompleteSelect( rowsAffected ); - + communicationHandler.sendCommandComplete( type, rowsAffected ); communicationHandler.sendReadyForQuery( "I" ); } - - //SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands) - //1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I - //1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I break; case "DELETE": @@ -607,6 +573,21 @@ COPY rows (rows = #rows copied --> only on PSQL 8.2 and later) n: noData indicator C: CommandComplete +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +See diary for darstellung with Null (12.10.22) + + r  user flufi database flufi client_encoding UTF8 DateStyle ISO TimeZone Europe/Berlin extra_float_digits 2 + + P " SET extra_float_digits = 3 B E S  + + P 7 SET application_name = 'PostgreSQL JDBC Driver' B E S  + + P ) INSERT INTO lol(LolId) VALUES (3) B D  P E S  + + P  SELECT LolId FROM lol B D P E S  + P  SELECT LolId FROM lol B D P E S  + + */ } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index a71e6ae0ade3dc2e03095b0b88e08df5a489d6b1..fdaeb5a3ce2b37e58713ba56d10c01180c581d6d 100644 GIT binary patch delta 15 WcmX@9xQTB8+vH*vwat6^c^CmM?gb41 literal 4297 zcmb7I>u%e~73QMF0u}ZZ3LNlHsH{xdPK>4rvRFx$8#RvQ6_upBMPZD{ku(iC!^{k= zs70Tr@6jjgHzXxfv7I=C#mmf@bNS9?&NzD9p~o~-#YT(e%F^-S(Vq{F508&&w&HZD zvQ4q#azmF|{gWpa#E$-4BwQMvQYlle$%3?Bumq20rbq9%HbO}{4i71C1b#E+cV9Rb z8&y)yHYAm$(s1w)h87~@#6Kmxup}fUDlam@WWs4J?5dK}a0wlcUmG53ZW+iK78Dy& zi#8##t|Lz;gqg@&>74Y2|W zC2S5gGqxtBi7hq9oK;TYwH8*$Wsi(n*frDKX_*RRwV0Q753j}!g4JyTAjTy5{g}qF zPlJ9uj(d*D`|<46kZS*U+MMu;~th%wJB5uUrCpdT*H|j#TlkF~-yWwq# z^zu$M+=~BnYR!M1z+^2_BnqxZwQD6(YGPo@SsH9X*bf9s?57@0=B_SLZkBs0MNy2{ zER6#d86FlI-Wbb;3SuOqT!skxoY}x{TW1vX&8on7iDT^U<<6q5kr;dr9>%k zakKSV<#6Z9FA=>Y$=7Yae}On4-|y9S-T|*Gq|NmZ$zh80PWfzR;!TqRxr6?eQO#`7TJQ=8V^avHJ@OA>*0UZhSY~+3j23mB4ewD< zQOI0f#p9NgHc{XUFm>8gh_$#PPQr>qU#4eSX;wkauO6Jp!N&4Ixdu<#;20r_u|M%acr?Bm55BXF+1TS;_FvN@j z+e*W)W47ga7i!zc@jOp^zw7gKMc7+1V>{Tk3!W!?`^IACy;l3A-X0CL8 zMv2IIg6RQ%Kj2qgBi#Ss-oA@*`~5znKUIvH-QK16m4xfT=Fw%namBx!(_c>qLps$0 z0rChe9?re%jnQdLXEeT;O(;`YaIUg(+NF2>^S9X9gC||^qXD`55AI%FbV_*A_jE}f zjof>sKYbTh)t)mG%vG)n7`kH@opWQb>RN))e{;DKtiCpFF(8=#LLenFMSrg}$CKTb6fa z%+6kVj5g^e`1Z>1uHZEF<^WB@Ui#2YO}ein)!Q8vu6C6OVE;1~{>>)RCVj`UirVF8 zi=-))G%ptmuAev(S6x|_sU+xz^>Fa?$68#Nak;dspi4i}5q{OEb{^TA|w7)9W%1h)gaeu=$$`qt6+l0nkBbRC4&|M9VvQ2^k&*{ zYeJxO^~`M_+f2EaOJ)5xFuJ{WZCSUZ)iJb{y%$0QG~nnXU-J!$EZga~@5ht7-FR}? zl2MC2X?y1NZO=6G&M`-A$8JMQq!)D^t((#ud%+ocZ>2XOK$({4IdcByZv)OG!U;o; zJZPzbMu!Tthc5{-I2!a2&M|1XY=B`$9U7c;(AfR#cmIC)kI$AGo@j1?1{lm%uID>f z3CpJNr^>^m)EXK=vcw+Zc(#`B0no_%()3PLi|9UYp0sExXF6Ygy+^K3%GjNTti<8{ zi+wVzRqN{DnlN|XZujp|RE^b5GJ-q#Fw^K_+tx?XOr`2M1^n7(-RFd^UFqjE5|Y!k z(klSS@%oPIxsYjztXh{kb#pmQd9Ey9VdJDFH_0kf#&Ago2S1TmG$joWWw^l!9w)!* cFh;)n*FfP~0G)08UFbRtE8?wszzKi<2f-I3Y5)KL diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 680089fdd6..b60da1c618 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -22,6 +22,9 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; +/** + * Writes the messages that need to be sent to the client byte-wise on the buffer + */ public class PGInterfaceServerWriter { String type; @@ -36,12 +39,16 @@ public PGInterfaceServerWriter( String type, PGInterfaceMessage pgMsg, ChannelHa } + /** + * Handles different cases of writing things on the buffer (e.g. strings, int, etc.) + * @return The buffer with the message written on it + */ public ByteBuf writeOnByteBuf() { ByteBuf buffer = ctx.alloc().buffer(); switch ( type ) { + //write string case "s": - //write string buffer.writeByte( pgMsg.getHeaderChar() ); if ( pgMsg.isDefaultLength() ) { buffer.writeInt( pgMsg.getLength() + pgMsg.getMsgBody().length() ); @@ -51,9 +58,8 @@ public ByteBuf writeOnByteBuf() { buffer.writeBytes( pgMsg.getMsgBody().getBytes( StandardCharsets.US_ASCII ) ); break; + //write byte (char) case "c": - //write byte (char) - //writebyte header and writebyte as a message buffer.writeByte( pgMsg.getHeaderChar() ); if ( pgMsg.isDefaultLength() ) { buffer.writeInt( pgMsg.getLength() + 1 ); @@ -64,7 +70,8 @@ public ByteBuf writeOnByteBuf() { buffer.writeByte( msgBody ); break; - case "i": //write int + //write int + case "i": buffer.writeByte( pgMsg.getHeaderChar() ); if ( pgMsg.isDefaultLength() ) { buffer.writeInt( pgMsg.getLength() ); @@ -81,77 +88,35 @@ public ByteBuf writeOnByteBuf() { buffer.writeInt( body ); break; + //write two strings (tag and message) case "ss": - //write two strings (tag and message) - buffer = writeSeveralStrings( 2 ); //TODO(FF)!!: check if this works, and if yes, maybe find better solution (switch case(?))?? - - /* - buffer.writeByte(pgMsg.getHeaderChar()); - if (pgMsg.isDefaultLength()) { - buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 1); - } - else { - buffer.writeInt(pgMsg.getLength()); - } - int[] twoPartsIdx = new int[]{0,1}; - String[] msgParts = pgMsg.getMsgPart(twoPartsIdx); - buffer.writeBytes(msgParts[0].getBytes(StandardCharsets.US_ASCII)); - buffer.writeByte(0); - buffer.writeBytes(msgParts[1].getBytes(StandardCharsets.US_ASCII)); - buffer.writeByte(0); - - */ + buffer = writeSeveralStrings( 2 ); //TODO(FF): maybe find better solution (switch case(?))?? break; + //write 3 strings, example, tag with three components case "sss": - //write 3 strings, example, tag with three components - buffer = writeSeveralStrings( 3 ); //TODO(FF)!!: check if this works, and if yes, maybe find better solution?? - /* - buffer.writeByte(pgMsg.getHeaderChar()); - if (pgMsg.isDefaultLength()) { - buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - 2); - } - else { - buffer.writeInt(pgMsg.getLength()); - } - int[] threePartsIdx = new int[]{0,1,2}; - String[] threeMsgParts = pgMsg.getMsgPart(threePartsIdx); - buffer.writeBytes(threeMsgParts[0].getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); - buffer.writeBytes(threeMsgParts[1].getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); - buffer.writeBytes(threeMsgParts[2].getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); - - */ + buffer = writeSeveralStrings( 3 ); //TODO(FF): maybe find better solution?? break; case "ssm": //several strings modified --> ideally only use this in the future... break; + //send dataRow case "dr": - //send dataRow - String test = ""; buffer.writeByte( pgMsg.getHeaderChar() ); - test += pgMsg.getHeaderChar() + " | "; - int nbrCol = (pgMsg.getMsgBody().length() - pgMsg.getMsgBody().replaceAll( "§", "" ).length()) / 2; //should generally be not the default length, but also works with default length & length = 4 if ( pgMsg.isDefaultLength() ) { //data row does not include msg-length bytes in msg length buffer.writeInt( pgMsg.getLength() - (nbrCol * 2) ); - int lol = (pgMsg.getLength() - (nbrCol * 2)); - test += lol + " | "; } else { //bcs it is including self buffer.writeInt( pgMsg.getLength() + 4 ); - test += pgMsg.getLength() + " | "; } - buffer.writeShort( nbrCol ); //mues das evtl au 8 sii??? - test += nbrCol + " | "; + buffer.writeShort( nbrCol ); //cut the last § (it is at the end) from the msgBody and set it as the new msgBody String temp = pgMsg.getMsgBody().substring( 0, pgMsg.getMsgBody().length() - 1 ); @@ -160,48 +125,24 @@ public ByteBuf writeOnByteBuf() { int[] idx = new int[(nbrCol * 2)]; String[] msgParts = pgMsg.getMsgPart( idx ); - for ( int i = 0; i < ((nbrCol * 2) - 1); i++ ) { //i<=10? hätt etzt gseit nei - buffer.writeInt( Integer.parseInt( msgParts[i] ) ); //onde: müesst 10 schecke... - buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); //chönnt sproblem sii dases als bytes gscheckt werd? (welich vorhär int gseit ha?? - - test += msgParts[i] + " | " + msgParts[i + 1] + " | "; + for ( int i = 0; i < ((nbrCol * 2) - 1); i++ ) { + buffer.writeInt( Integer.parseInt( msgParts[i] ) ); + buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); i++; - } - int x = 2; - break; - case "test": - //T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff - buffer.writeByte( pgMsg.getHeaderChar() ); - //buffer.writeBytes("00000".getBytes(StandardCharsets.UTF_8)); - buffer.writeInt( 0 ); - buffer.writeInt( 0 ); - buffer.writeInt( 0 ); - buffer.writeInt( 0 ); - buffer.writeInt( 0 ); - //buffer.writeInt(24 + "empid".length()); - buffer.writeShort( 1 ); - buffer.writeBytes( "empid".getBytes( StandardCharsets.UTF_8 ) ); - buffer.writeInt( 0 ); - buffer.writeShort( 0 ); - buffer.writeInt( 0 ); - buffer.writeShort( 40 ); - buffer.writeInt( 2 ); - buffer.writeInt( 0 ); - buffer.writeShort( 1 ); - buffer.writeInt( 0 ); - buffer.writeInt( 0 ); - buffer.writeInt( 0 ); - buffer.writeInt( 17 ); - buffer.writeInt( 0 ); - buffer.writeInt( 4 ); + } break; } return buffer; } + /** + * If there are several Strings that need to be written on the buffer (for example message and tag(s)) - The Strings are in the msgBody, seperated by the delimiter + * @param nbrStrings How many elements are in the msgBody (seperated by the delimiter) + * @return The buffer with the message written on it + */ public ByteBuf writeSeveralStrings( int nbrStrings ) { ByteBuf buffer = ctx.alloc().buffer(); @@ -224,6 +165,11 @@ public ByteBuf writeSeveralStrings( int nbrStrings ) { } + /** + * If the header is a number and not a letter, use this method to write the message (messages with a number as headers don't have a msgBody) + * @param header The header you want to write on the buffer + * @return The buffer with the message written on it + */ public ByteBuf writeIntHeaderOnByteBuf( char header ) { //write a int header... ("i" (for char headers) doesn't work TODO(FF): Figure out a way to do this with case "i" //since headers with numbers are always indicators, don't I don't check for not standard lengths @@ -236,10 +182,22 @@ public ByteBuf writeIntHeaderOnByteBuf( char header ) { } + /** + * Special case: write the rowDescription + * @param valuesPerCol The values that are needed to be sent in the rowDescription: + * String fieldName, + * int objectIDTable, + * int attributeNoCol, + * int objectIDCol, + * int dataTypeSize, + * int typeModifier, + * int formatCode, + * @return The buffer with the message written on it + */ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { //I don't check for length, bcs rowDescription is always the same ByteBuf buffer = ctx.alloc().buffer(); - //ByteBuf bufferTemp = ctx.alloc().buffer(); + String fieldName; int objectIDTable; int attributeNoCol; @@ -257,7 +215,6 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { buffer.writeInt( pgMsg.getLength() + messageLength ); buffer.writeShort(Integer.parseInt(pgMsg.getMsgBody())); - //buffer.writeShort( 1 ); //FIXME(FF): Si wänd do ned d number of fields, sondern wievel descriptors ich för jedes field aagebe... >( oder au ned? werom 8????? for ( Object[] oneCol : valuesPerCol ) { ByteBuf bufferTemp = ctx.alloc().buffer(); @@ -269,28 +226,18 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { typeModifier = (Integer) oneCol[5]; formatCode = (Integer) oneCol[6]; - //messageLength += (fieldName.length() + 6); - bufferTemp.writeBytes( fieldName.getBytes( StandardCharsets.UTF_8 ) ); bufferTemp.writeByte( 0 ); bufferTemp.writeInt( objectIDTable ); - //bufferTemp.writeByte( 0 ); bufferTemp.writeShort( attributeNoCol ); - //bufferTemp.writeByte( 0 ); - bufferTemp.writeInt( objectIDCol ); //objectId of datatype? - //bufferTemp.writeByte( 0 ); + bufferTemp.writeInt( objectIDCol ); bufferTemp.writeShort( dataTypeSize ); - //bufferTemp.writeByte( 0 ); bufferTemp.writeInt( typeModifier ); - //bufferTemp.writeByte( 0 ); - bufferTemp.writeShort( formatCode ); //aber bem 4. esch denn do dezwösche en fähler cho, vorem nöchste flushl... werom au emmer??? --> be comission + bufferTemp.writeShort( formatCode ); - buffer.writeBytes( bufferTemp ); //die erste 3x gohts ohni fähler + buffer.writeBytes( bufferTemp ); } - - //return buffer.writeBytes(bufferTemp); - //String bla = new String(buffer.array(), Charset.defaultCharset()); - String bla = buffer.toString( Charset.defaultCharset() ); + //String bla = buffer.toString( Charset.defaultCharset() ); return buffer; } From c975cc3623e3dfdce363122ec0d413121db31dea Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Mon, 17 Oct 2022 09:41:27 +0200 Subject: [PATCH 42/57] Select, create table and insert work now. Although I am not too sure about my error handling (internally) yet... --- .../postgresql/PGInterfaceErrorHandler.java | 37 +++++ ...GInterfaceInboundCommunicationHandler.java | 6 +- .../postgresql/PGInterfaceQueryHandler.java | 146 ++++++++++++++---- 3 files changed, 161 insertions(+), 28 deletions(-) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java new file mode 100644 index 0000000000..4fb407bed2 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import lombok.Setter; + +public class PGInterfaceErrorHandler { + + private String errorMsg; + private Throwable exception; + + @Setter + private String generatedQuery; + + public PGInterfaceErrorHandler(Throwable e ) { + this.exception = e; + if ( e.getMessage() != null ) { + this.errorMsg = e.getMessage(); + } else { + this.errorMsg = e.getClass().getSimpleName(); + } + } +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index c9e985b849..b89399670a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -270,12 +270,16 @@ public void sendDataRow( ArrayList data ) { ctx.writeAndFlush( dataRowWriter.writeOnByteBuf() ); body = ""; } + } - } + private void sendErrorResponse(String error) { + } public void terminateConnection() { ctx.close(); } } + + diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index c463be85c4..7d4f5844b3 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -38,6 +38,7 @@ import org.polypheny.db.processing.QueryProcessor; import org.polypheny.db.transaction.Statement; import org.polypheny.db.transaction.Transaction; +import org.polypheny.db.transaction.TransactionException; import org.polypheny.db.transaction.TransactionManager; public class PGInterfaceQueryHandler { @@ -163,6 +164,7 @@ private void hardcodeResponse() { */ public void sendQueryToPolypheny() { String type = ""; //query type according to answer tags + String commitStatus; Transaction transaction; Statement statement = null; PolyImplementation result; @@ -178,39 +180,128 @@ public void sendQueryToPolypheny() { throw new RuntimeException( "Error while starting transaction", e ); } - //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) - Processor sqlProcessor = statement.getTransaction().getProcessor( Catalog.QueryLanguage.SQL ); - Node sqlNode = sqlProcessor.parse( query ).get( 0 ); - QueryParameters parameters = new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ); - if ( sqlNode.isA( Kind.DDL ) ) { - result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); - //TODO(FF): ene try catch block... || evtl no committe (söscht werds ned aazeigt em ui (aso allgemein, wie werds denn aazeigt em ui?) - // exception: java.lang.RuntimeException: No primary key has been provided! - } else { - AlgRoot algRoot = sqlProcessor.translate( - statement, - sqlProcessor.validate( statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean() ).left, - new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ) ); - - //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) - final QueryProcessor processor = statement.getQueryProcessor(); - result = processor.prepareQuery( algRoot, true ); + //TODO: en try catch block ine --> committe? + try { + //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) + Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); + Node sqlNode = sqlProcessor.parse(query).get(0); + QueryParameters parameters = new QueryParameters(query, Catalog.NamespaceType.RELATIONAL); + if (sqlNode.isA(Kind.DDL)) { + result = sqlProcessor.prepareDdl(statement, sqlNode, parameters); + type = sqlNode.getKind().name(); + sendResultToClient( type, data, header ); + + } else { + AlgRoot algRoot = sqlProcessor.translate( + statement, + sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, + new QueryParameters(query, Catalog.NamespaceType.RELATIONAL)); + + //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) + final QueryProcessor processor = statement.getQueryProcessor(); + result = processor.prepareQuery(algRoot, true); + + //get type information - from crud.java + header = getHeader( result ); + + //get actual result of query in array - from crud.java + rows = result.getRows( statement, -1 ); + data = computeResultData( rows, header ); + + //type = result.getStatementType().toString(); + type = result.getKind().name(); + + //FIXME(FF): macht das senn dasmer nome dors transaction.commit() de fähler bechonnt?? + transaction.commit(); + + //TODO(FF): how to handle reusable queries?? (do i have to safe them/check if it is reusable?) + //TODO(Extended Queries): met dem denn values dezue tue + //statement.getDataContext().setParameterTypes(); //döfs erscht bem execute step mache... + //statement.getDataContext().setParameterValues(); + //java.lang.RuntimeException: The table 'emps' is provided by a data source which does not support data modification. + + + //committe of transaction (commitAndFinish (languageCrud) + //transaction.commit(); (try catch --> be catch rollback + + + //handle result, depending on query type + sendResultToClient( type, data, header ); + + } + } catch (Throwable t) { //TransactionExeption? + List lol = null; + //TODO(FF): Rollback and send error to client + //log.error( "Caught exception while executing query", e ); + lol.add(new PGInterfaceErrorHandler( t )); + //result = new PGInterfaceErrorHandler( t ).setGeneratedQuery( query ); + try { + transaction.rollback(); + commitStatus = "Rolled back"; + } catch (TransactionException ex) { + //log.error( "Could not rollback CREATE TABLE statement: {}", ex.getMessage(), ex ); + commitStatus = "Error while rolling back"; + } } - //get type information - from crud.java - header = getHeader( result ); - //get actual result of query in array - from crud.java - rows = result.getRows( statement, -1 ); - data = computeResultData( rows, header ); - type = result.getStatementType().toString(); - //TODO(FF): how to handle reusable queries?? (do i have to safe them/check if it is reusable?) + /* + //Bsp Crud.java > createTable --> wie rollbacke (?o. exceptions handle oder biedes?) + try { + int a = executeSqlUpdate( transaction, query.toString() ); + result = new Result( a ).setGeneratedQuery( query.toString() ); + transaction.commit(); + } catch ( QueryExecutionException | TransactionException e ) { + log.error( "Caught exception while creating a table", e ); + result = new Result( e ).setGeneratedQuery( query.toString() ); + try { + transaction.rollback(); + } catch ( TransactionException ex ) { + log.error( "Could not rollback CREATE TABLE statement: {}", ex.getMessage(), ex ); + } + } + + //anders biispel us Result.java (för was??) + public Result( Throwable e ) { + this.exception = e; + if ( e.getMessage() != null ) { + this.error = e.getMessage(); + } else { + this.error = e.getClass().getSimpleName(); + } + } + + + //anders biispel: LanguageCrud > anyMongoQuery --> ganz onde de catch block, metem attack_error (aber was das gnau macht?) + + + //anders Biispel: LanguageCrud > commitAndFinish --> alles e chli? --> wie commite + executionTime = System.nanoTime() - executionTime; + String commitStatus; + try { + transaction.commit(); + commitStatus = "Committed"; + } catch ( TransactionException e ) { + log.error( "Caught exception", e ); + results.add( new Result( e ) ); + try { + transaction.rollback(); + commitStatus = "Rolled back"; + } catch ( TransactionException ex ) { + log.error( "Caught exception while rollback", e ); + commitStatus = "Error while rolling back"; + } + } + + if ( queryAnalyzer != null ) { + Crud.attachQueryAnalyzer( queryAnalyzer, executionTime, commitStatus, results.size() ); + } + + */ - //handle result, depending on query type - sendResultToClient( type, data, header ); } @@ -355,11 +446,12 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; - case "CREATE TABLE": + case "CREATE_TABLE": //TODO(FF) do things in polypheny (?) --> not here, but check what to do with commits //1....2....n....C....CREATE TABLE.Z....I communicationHandler.sendParseBindComplete(); //communicationHandler.sendCommandCompleteCreateTable(); + //type = "CREATE TABLE"; communicationHandler.sendCommandComplete( type, -1 ); communicationHandler.sendReadyForQuery( "I" ); From 77f5b05b35407009871503809d79ee7f2836975e Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 20 Oct 2022 00:00:39 +0200 Subject: [PATCH 43/57] barebones of prepared Statements --- ...GInterfaceInboundCommunicationHandler.java | 97 +++++++++++++++---- .../PGInterfacePreparedMessage.java | 61 ++++++++++++ 2 files changed, 139 insertions(+), 19 deletions(-) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index b89399670a..2a4f511a5b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -20,6 +20,8 @@ import io.netty.channel.ChannelHandlerContext; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.List; + import org.polypheny.db.transaction.TransactionManager; /** @@ -30,6 +32,7 @@ public class PGInterfaceInboundCommunicationHandler { String type; ChannelHandlerContext ctx; TransactionManager transactionManager; + ArrayList executeStatementNames; public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContext ctx, TransactionManager transactionManager ) { @@ -102,36 +105,46 @@ public void simpleQueryPhase() { public void extendedQueryPhase( String incomingMsg ) { if ( incomingMsg.substring( 2, 5 ).equals( "SET" ) ) { - sendParseBindComplete(); - sendCommandComplete("SET", -1); - sendReadyForQuery( "I" ); - } else { - //Query does not have ";" at the end!! + } else if (incomingMsg.substring(2, 9).equals("PREPARE")) { + //Prepared Statement + //TODO(FF): was wenn execute ned as ei message metem prepared chonnt... + //set name ond luege öber scho existiert... --> mues also ergendwo en liste met prepared statements speichere + String[] query = extractPreparedQuery( incomingMsg ); + //check if name already exists + PGInterfacePreparedMessage preparedMessage = new PGInterfacePreparedMessage(query[0], query[1], ctx); + executeStatementNames.add(extractPreparedQueryName(query[0])); + //safe everything possible and necessary + //send: 1....2....n....C....PREPARE + if (!query[1].contains("§")) { //execute was already sent + //check if execute name == prepare name... wenn not, break + //safe rest(hier?) + //everything ready... do stuff.. + } + List lol = preparedMessage.extractValues(); + + } else if (incomingMsg.substring(2, 9).equals("EXECUTE")) { + //get execute statement + String[] query = extractPreparedQuery( incomingMsg ); + //check if name exists already + //update and safe everything necessary + //create executePreparedStatement?? --> mues denn au polypheny uufrüefe + //ond mues denn au de name weder us de lischte lösche!!! + + } + + else { + //"Normal" query String query = extractQuery( incomingMsg ); PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler( query, ctx, this, transactionManager ); queryHandler.start(); - } } - /** - * Creates and sends (flushes on ctx) a readyForQuery message with a tag. The tag is choosable (see below for options). - * - * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), - * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) - */ - public void sendReadyForQuery( String msgBody ) { - PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); - PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx ); - ctx.writeAndFlush( readyForQueryWriter.writeOnByteBuf() ); - } - - /** * Prepares (parses) the incoming message from the client, so it can be used in the context of polypheny * NOTE: Some incoming messages from the client are disregarded (they are sent the same way all the time, if something unusual occurs, this is not handled yet, i.e. hardcoded to find the end of the query itself). @@ -164,6 +177,52 @@ public String extractQuery( String incomingMsg ) { } + private String[] extractPreparedQuery(String incomingMsg) { + String prepareString = extractQuery(incomingMsg); + String executeString = "§"; + + + if (incomingMsg.contains("EXECUTE")) { + executeString = extractExecutePart(incomingMsg); + } + + String[] result = {prepareString, executeString}; + return result; + } + + private String extractExecutePart(String incomingMsg) { + + int idx = incomingMsg.indexOf("EXECUTE"); + String executeStringWithBufferStuff = incomingMsg.substring(idx, incomingMsg.length()); + String executeString = executeStringWithBufferStuff.split("\\(")[0]; + + return executeString; + } + + private String extractPreparedQueryName(String cleanedQuery) { + + String startNamePlusQuery = cleanedQuery.substring(8); + String name = startNamePlusQuery.split("\\(")[0]; + + return name.replace(" ", ""); + } + + + + /** + * Creates and sends (flushes on ctx) a readyForQuery message with a tag. The tag is choosable (see below for options). + * + * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), + * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) + */ + public void sendReadyForQuery( String msgBody ) { + PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); + PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx ); + ctx.writeAndFlush( readyForQueryWriter.writeOnByteBuf() ); + } + + + public void sendParseBindComplete() { //TODO(FF): This should work with the normal PGInterfaceServerWriter type "i" (called like in the commented out part), // but it does not --> roundabout solution that works, but try to figure out what went wrong... diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java new file mode 100644 index 0000000000..14c90789bb --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import io.netty.channel.ChannelHandlerContext; + +import java.util.List; + +public class PGInterfacePreparedMessage { + private String name; + private List datatype; + private ChannelHandlerContext ctx; + private String query; + private String prepareString; + private String executeString; + private List values; + private static final String executeDelimiter = ", "; + + + public PGInterfacePreparedMessage(String query, String executeString, ChannelHandlerContext ctx) { + this.query = query; + this.executeString = executeString; + this.ctx = ctx; + } + + public PGInterfacePreparedMessage(ChannelHandlerContext ctx) { + this.ctx = ctx; + } + + public void setQuery(String query) { + this.query = query; + } + + public void setExecuteString(String executeString) { + this.executeString = executeString; + } + + public static String getExecuteDelimiter() {return executeDelimiter;} + + public List extractValues() { + //us execute string - seperator: ', ' + //bool ersetze... + //cut string at ( and ) (remove chlammere) --> denn mach eif. split, ond problem solved... + String onlyExecuteValues = executeString.split("\\(|\\)")[1]; + return List.of(onlyExecuteValues.split(getExecuteDelimiter())); + } +} From 028a80e6a5dbb4f3ffb6dd04133272e2e007a3fa Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 21 Oct 2022 16:18:17 +0200 Subject: [PATCH 44/57] prepared message is correctly prepared to be processed by polypheny --- ...GInterfaceInboundCommunicationHandler.java | 82 ++++++++++++++----- .../PGInterfacePreparedMessage.java | 71 ++++++++++++++-- .../postgresql/PGInterfaceQueryHandler.java | 12 ++- 3 files changed, 135 insertions(+), 30 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 2a4f511a5b..1866fae875 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -20,7 +20,6 @@ import io.netty.channel.ChannelHandlerContext; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.List; import org.polypheny.db.transaction.TransactionManager; @@ -32,7 +31,8 @@ public class PGInterfaceInboundCommunicationHandler { String type; ChannelHandlerContext ctx; TransactionManager transactionManager; - ArrayList executeStatementNames; + ArrayList preparedStatementNames = new ArrayList<>(); + ArrayList preparedMessages = new ArrayList<>(); public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContext ctx, TransactionManager transactionManager ) { @@ -114,26 +114,55 @@ public void extendedQueryPhase( String incomingMsg ) { //TODO(FF): was wenn execute ned as ei message metem prepared chonnt... //set name ond luege öber scho existiert... --> mues also ergendwo en liste met prepared statements speichere String[] query = extractPreparedQuery( incomingMsg ); - //check if name already exists - PGInterfacePreparedMessage preparedMessage = new PGInterfacePreparedMessage(query[0], query[1], ctx); - executeStatementNames.add(extractPreparedQueryName(query[0])); - //safe everything possible and necessary - //send: 1....2....n....C....PREPARE - if (!query[1].contains("§")) { //execute was already sent - //check if execute name == prepare name... wenn not, break - //safe rest(hier?) - //everything ready... do stuff.. + String prepareString = query[0]; + String executeString = query[1]; + String prepareStringQueryName = extractPreparedQueryName(prepareString); + + //check if name already exists --> muesi das öberhaupt?? chamer ned eif es existierends öberschriibe? + if (preparedStatementNames.isEmpty() || (!preparedStatementNames.contains(prepareStringQueryName))) { + PGInterfacePreparedMessage preparedMessage = new PGInterfacePreparedMessage(prepareStringQueryName, prepareString, ctx); + preparedMessage.prepareQuery(); + preparedStatementNames.add(prepareStringQueryName); + preparedMessages.add(preparedMessage); + //safe everything possible and necessary + //send: 1....2....n....C....PREPARE + sendParseBindComplete(); + sendNoData(); + sendCommandComplete( "PREPARE", -1 ); + + if (!executeString.isEmpty()) { //an execute statement was sent along + String statementName = extractPreparedQueryName(executeString); + + //check if name exists already + if (preparedStatementNames.contains(statementName)) { + executePreparedStatement(executeString, statementName); + } else { + String errorMsg = "There does not exist a prepared statement called" + statementName; + //TODO(FF): send error message to client + } + + } else { + sendReadyForQuery( "I" ); + } + } else { + String errorMsg = "There already exists a prepared statement with the name" + prepareStringQueryName + "which has not yet been executed"; + //TODO(FF): send error message to client } - List lol = preparedMessage.extractValues(); + + //List lol = preparedMessage.extractValues(); } else if (incomingMsg.substring(2, 9).equals("EXECUTE")) { //get execute statement - String[] query = extractPreparedQuery( incomingMsg ); - //check if name exists already - //update and safe everything necessary - //create executePreparedStatement?? --> mues denn au polypheny uufrüefe - //ond mues denn au de name weder us de lischte lösche!!! + String executeQuery = extractQuery(incomingMsg); + String statementName = extractPreparedQueryName(executeQuery); + //check if name exists already + if (preparedStatementNames.contains(statementName)) { + executePreparedStatement(executeQuery, statementName); + } else { + String errorMsg = "There does not exist a prepared statement called" + statementName; + //TODO(FF): send error message to client + } } else { @@ -144,6 +173,17 @@ public void extendedQueryPhase( String incomingMsg ) { } } + private void executePreparedStatement(String executeString, String statementName) { + int idx = preparedStatementNames.indexOf(statementName); + PGInterfacePreparedMessage preparedMessage = preparedMessages.get(idx); + preparedMessage.setExecuteString(executeString); + preparedMessage.extractAndSetValues(); + + PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler( preparedMessage, ctx, this, transactionManager ); + //queryHandler.start(); + //send commandComplete according to query type... (oder em query handler... wo au emmer dases gscheckt werd...) ond parse bind ond ready for query... + } + /** * Prepares (parses) the incoming message from the client, so it can be used in the context of polypheny @@ -179,7 +219,7 @@ public String extractQuery( String incomingMsg ) { private String[] extractPreparedQuery(String incomingMsg) { String prepareString = extractQuery(incomingMsg); - String executeString = "§"; + String executeString = new String(); if (incomingMsg.contains("EXECUTE")) { @@ -194,7 +234,8 @@ private String extractExecutePart(String incomingMsg) { int idx = incomingMsg.indexOf("EXECUTE"); String executeStringWithBufferStuff = incomingMsg.substring(idx, incomingMsg.length()); - String executeString = executeStringWithBufferStuff.split("\\(")[0]; + String executeString = executeStringWithBufferStuff.split("\\)")[0]; + executeString = executeString + ")"; return executeString; } @@ -209,6 +250,7 @@ private String extractPreparedQueryName(String cleanedQuery) { + /** * Creates and sends (flushes on ctx) a readyForQuery message with a tag. The tag is choosable (see below for options). * @@ -254,7 +296,7 @@ public void sendNoData() { //TODO(FF): not entirely sure in which case this would be needed? PGInterfaceMessage noData = new PGInterfaceMessage( PGInterfaceHeaders.n, "0", 4, true ); PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx ); - ctx.writeAndFlush( noDataWriter.writeOnByteBuf() ); + ctx.writeAndFlush( noDataWriter.writeIntHeaderOnByteBuf('n') ); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index 14c90789bb..54b3efaf68 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -18,26 +18,28 @@ import io.netty.channel.ChannelHandlerContext; +import java.util.Arrays; import java.util.List; +import java.util.ListIterator; public class PGInterfacePreparedMessage { private String name; - private List datatype; private ChannelHandlerContext ctx; private String query; - private String prepareString; + private String wholePrepareString; private String executeString; - private List values; + private List datatypes; private static final String executeDelimiter = ", "; - public PGInterfacePreparedMessage(String query, String executeString, ChannelHandlerContext ctx) { - this.query = query; - this.executeString = executeString; + public PGInterfacePreparedMessage(String name, String wholePrepareString, ChannelHandlerContext ctx) { + this.name = name; + this.wholePrepareString = wholePrepareString; this.ctx = ctx; } - public PGInterfacePreparedMessage(ChannelHandlerContext ctx) { + public PGInterfacePreparedMessage(String name, ChannelHandlerContext ctx) { + this.name = name; this.ctx = ctx; } @@ -49,13 +51,64 @@ public void setExecuteString(String executeString) { this.executeString = executeString; } + public void setWholePrepareString(String wholePrepareString) { + this.wholePrepareString = wholePrepareString; + } + + private void setDatatypes(List datatypes) { this.datatypes = datatypes; } + public static String getExecuteDelimiter() {return executeDelimiter;} - public List extractValues() { + public void extractAndSetValues() { //us execute string - seperator: ', ' //bool ersetze... //cut string at ( and ) (remove chlammere) --> denn mach eif. split, ond problem solved... String onlyExecuteValues = executeString.split("\\(|\\)")[1]; - return List.of(onlyExecuteValues.split(getExecuteDelimiter())); + List valueList = Arrays.asList(onlyExecuteValues.split(getExecuteDelimiter())); + setDatatypes(valueList); + } + + public void extractAndSetTypes() { + String types = wholePrepareString.split("\\(|\\)")[1]; + List typeList = Arrays.asList(types.split(getExecuteDelimiter())); + + //replace all bool with boolean to match polypheny dt + if (typeList.contains("bool") || typeList.contains("BOOL")) { + ListIterator iterator = typeList.listIterator(); + while (iterator.hasNext()) { + String next = iterator.next(); + if (next.equals("bool")) { + typeList.set(iterator.nextIndex()-1, "BOOLEAN"); + } + } + } + setDatatypes(typeList); + } + + public void changeParameterSymbol() { + + String[] parts = wholePrepareString.split("\\$"); + String newPrepareString = new String(); + + for (int i = 1; i lol = null; //TODO(FF): Rollback and send error to client //log.error( "Caught exception while executing query", e ); + String errorMsg = t.getMessage(); lol.add(new PGInterfaceErrorHandler( t )); //result = new PGInterfaceErrorHandler( t ).setGeneratedQuery( query ); try { From 03368c6a225d14a6fa22c071a826d4afd451e9cf Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 21 Oct 2022 16:52:11 +0200 Subject: [PATCH 45/57] except for adding the necessary values and types to the prepared statement, everything is now in place for them to be executed (hopefully) --- .../PGInterfacePreparedMessage.java | 12 ++- .../postgresql/PGInterfaceQueryHandler.java | 98 +++++-------------- 2 files changed, 34 insertions(+), 76 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index 54b3efaf68..053537df2d 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -28,7 +28,7 @@ public class PGInterfacePreparedMessage { private String query; private String wholePrepareString; private String executeString; - private List datatypes; + private List dataTypes; private static final String executeDelimiter = ", "; @@ -55,17 +55,21 @@ public void setWholePrepareString(String wholePrepareString) { this.wholePrepareString = wholePrepareString; } - private void setDatatypes(List datatypes) { this.datatypes = datatypes; } + private void setDataTypes(List dataTypes) { this.dataTypes = dataTypes; } public static String getExecuteDelimiter() {return executeDelimiter;} + public String getQuery() { return query;} + + public List getDataTypes() { return dataTypes;} + public void extractAndSetValues() { //us execute string - seperator: ', ' //bool ersetze... //cut string at ( and ) (remove chlammere) --> denn mach eif. split, ond problem solved... String onlyExecuteValues = executeString.split("\\(|\\)")[1]; List valueList = Arrays.asList(onlyExecuteValues.split(getExecuteDelimiter())); - setDatatypes(valueList); + setDataTypes(valueList); } public void extractAndSetTypes() { @@ -82,7 +86,7 @@ public void extractAndSetTypes() { } } } - setDatatypes(typeList); + setDataTypes(typeList); } public void changeParameterSymbol() { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index d3df094407..5c242870ef 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -22,9 +22,12 @@ import java.sql.ResultSetMetaData; import java.util.ArrayList; import java.util.List; +import java.util.Map; + import org.polypheny.db.PolyImplementation; import org.polypheny.db.algebra.AlgRoot; import org.polypheny.db.algebra.constant.Kind; +import org.polypheny.db.algebra.type.AlgDataType; import org.polypheny.db.algebra.type.AlgDataTypeField; import org.polypheny.db.catalog.Catalog; import org.polypheny.db.catalog.exceptions.GenericCatalogException; @@ -43,20 +46,20 @@ public class PGInterfaceQueryHandler { - String query; - PGInterfacePreparedMessage preparedMessage; - ChannelHandlerContext ctx; - PGInterfaceInboundCommunicationHandler communicationHandler; + private String query; + private PGInterfacePreparedMessage preparedMessage; + private Boolean preparedQueryCycle = false; + private ChannelHandlerContext ctx; + private PGInterfaceInboundCommunicationHandler communicationHandler; private TransactionManager transactionManager; - int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) - List> rows; + private int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) + private List> rows; public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager ) { this.query = query; this.ctx = ctx; this.communicationHandler = communicationHandler; - Object obj = new Object(); this.transactionManager = transactionManager; } @@ -64,13 +67,18 @@ public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, Chan this.preparedMessage = preparedMessage; this.ctx = ctx; this.communicationHandler = communicationHandler; - Object obj = new Object(); this.transactionManager = transactionManager; + preparedQueryCycle = true; } public void start() { //hardcodeResponse(); - sendQueryToPolypheny(); + if (!preparedQueryCycle) { + sendQueryToPolypheny(); + } else { + this.query = preparedMessage.getQuery(); + } + } private void hardcodeResponse() { @@ -189,8 +197,16 @@ public void sendQueryToPolypheny() { throw new RuntimeException( "Error while starting transaction", e ); } - //TODO: en try catch block ine --> committe? try { + if (preparedQueryCycle) { + //TODO(FF): how to handle reusable queries?? (do i have to safe them/check if it is reusable?) + //TODO(prepared Queries): met dem denn values dezue tue + Map types = null; + List> values = null; + statement.getDataContext().setParameterTypes(types); //döfs erscht bem execute step mache... + statement.getDataContext().setParameterValues(values); + + } //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); Node sqlNode = sqlProcessor.parse(query).get(0); @@ -223,10 +239,6 @@ public void sendQueryToPolypheny() { //FIXME(FF): macht das senn dasmer nome dors transaction.commit() de fähler bechonnt?? transaction.commit(); - //TODO(FF): how to handle reusable queries?? (do i have to safe them/check if it is reusable?) - //TODO(prepared Queries): met dem denn values dezue tue - //statement.getDataContext().setParameterTypes(); //döfs erscht bem execute step mache... - //statement.getDataContext().setParameterValues(); //java.lang.RuntimeException: The table 'emps' is provided by a data source which does not support data modification. @@ -255,64 +267,6 @@ public void sendQueryToPolypheny() { } } - - - - /* - //Bsp Crud.java > createTable --> wie rollbacke (?o. exceptions handle oder biedes?) - try { - int a = executeSqlUpdate( transaction, query.toString() ); - result = new Result( a ).setGeneratedQuery( query.toString() ); - transaction.commit(); - } catch ( QueryExecutionException | TransactionException e ) { - log.error( "Caught exception while creating a table", e ); - result = new Result( e ).setGeneratedQuery( query.toString() ); - try { - transaction.rollback(); - } catch ( TransactionException ex ) { - log.error( "Could not rollback CREATE TABLE statement: {}", ex.getMessage(), ex ); - } - } - - //anders biispel us Result.java (för was??) - public Result( Throwable e ) { - this.exception = e; - if ( e.getMessage() != null ) { - this.error = e.getMessage(); - } else { - this.error = e.getClass().getSimpleName(); - } - } - - - //anders biispel: LanguageCrud > anyMongoQuery --> ganz onde de catch block, metem attack_error (aber was das gnau macht?) - - - //anders Biispel: LanguageCrud > commitAndFinish --> alles e chli? --> wie commite - executionTime = System.nanoTime() - executionTime; - String commitStatus; - try { - transaction.commit(); - commitStatus = "Committed"; - } catch ( TransactionException e ) { - log.error( "Caught exception", e ); - results.add( new Result( e ) ); - try { - transaction.rollback(); - commitStatus = "Rolled back"; - } catch ( TransactionException ex ) { - log.error( "Caught exception while rollback", e ); - commitStatus = "Error while rolling back"; - } - } - - if ( queryAnalyzer != null ) { - Crud.attachQueryAnalyzer( queryAnalyzer, executionTime, commitStatus, results.size() ); - } - - */ - - } /** From 6d9a93dcb88da99bc2d20a00116a826c1b4d41e4 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 21 Oct 2022 20:00:54 +0200 Subject: [PATCH 46/57] error message arrives on client side (not perfect, but it works...) --- .../PGInterfaceErrorFieldTypes.java | 42 +++++++++++++++ .../postgresql/PGInterfaceErrorHandler.java | 53 ++++++++++++++++--- .../db/postgresql/PGInterfaceHeaders.java | 17 +----- ...GInterfaceInboundCommunicationHandler.java | 6 +-- .../postgresql/PGInterfaceQueryHandler.java | 8 +-- .../postgresql/PGInterfaceServerWriter.java | 29 ++++++++++ 6 files changed, 128 insertions(+), 27 deletions(-) create mode 100644 postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java new file mode 100644 index 0000000000..19cb52b2d3 --- /dev/null +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +/** + * The Fields which appear in Error and Notice Messages. They are usually followed by a String which contains the field value + * For more information see: https://www.postgresql.org/docs/current/protocol-error-fields.html + */ +public enum PGInterfaceErrorFieldTypes { + + /** + * Severity: the field contents are ERROR, FATAL, or PANIC (in an error message), or WARNING, NOTICE, DEBUG, INFO, + * or LOG (in a notice message), or a localized translation of one of these. Always present. + */ + S, + + /** + * Code: the SQLSTATE code for the error. Not localizable. Always present. + */ + C, + + /** + * Message: the primary human-readable error message. This should be accurate but terse (typically one line). Always present. + */ + M + + +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java index 4fb407bed2..8611a202f1 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -16,22 +16,63 @@ package org.polypheny.db.postgresql; -import lombok.Setter; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; + +import java.util.HashMap; +import java.util.LinkedHashMap; public class PGInterfaceErrorHandler { private String errorMsg; private Throwable exception; + private ChannelHandlerContext ctx; + private PGInterfaceServerWriter serverWriter; + + + public PGInterfaceErrorHandler(ChannelHandlerContext ctx) { + this.ctx = ctx; + } + + public void sendSimpleErrorMessage (String errorMsg) { + //E...n S ERROR. V ERROR. C 42P01. M relation "public.hihi" does not exist. P 15. F parse_relation. c. L 1360. R parserOpenTable. . Z....I + //E...x S ERROR. V ERROR. C 42P01. M relation "public.hihi" does not exist. P 15. F parse_relation. c. L 1360. R parserOpenTable. . Z....I + //header, length, severity, severity (gl wie vorher), SQLSTATE code, Message, (Position, File, column name?, Line, Routine, zerobyte as field) freiwillig + //42P01 - undefined_table$ + //0A000 - feature_not_supported + + //E..._SERROR.VERROR.C42601.Msyntax error at or near "SSELECT".P1.Fscan.l.L1176.Rscanner_yyerror..Z....I + this.errorMsg = errorMsg; + PGInterfaceMessage pgInterfaceMessage = new PGInterfaceMessage(PGInterfaceHeaders.E, "MockBody", 4, true); + this.serverWriter = serverWriter = new PGInterfaceServerWriter("MockType", pgInterfaceMessage, ctx); + + //FIXME(FF): An error occurs because of the errormessage on the clientside. But it doesn't really matter, because the connection would be terminated anyway and the individual message part arrives... + LinkedHashMap errorFields = new LinkedHashMap(); + errorFields.put('S', "ERROR"); + errorFields.put('V', "ERROR"); + errorFields.put('C', "0A000"); + errorFields.put('M', errorMsg); + errorFields.put('P', "notImplemented"); + errorFields.put('F', "polypheny"); + errorFields.put('c', ""); + errorFields.put('L', "1360"); + errorFields.put('R', "parserOpenTable"); - @Setter - private String generatedQuery; - public PGInterfaceErrorHandler(Throwable e ) { - this.exception = e; + ByteBuf buffer = serverWriter.writeSimpleErrorMessage(errorFields); + ctx.writeAndFlush(buffer); + + PGInterfaceInboundCommunicationHandler.sendReadyForQuery("I"); + + } + + + /* + this.exception = e; if ( e.getMessage() != null ) { this.errorMsg = e.getMessage(); } else { this.errorMsg = e.getClass().getSimpleName(); } - } + */ } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java index f1d162f305..376d85864f 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java @@ -22,7 +22,7 @@ * There exist some special cases (as numbers as header, or no header) * For more information look at the Postgresql documentation: https://www.postgresql.org/docs/current/protocol-message-formats.html */ -//TODO: not complete with all commands yet (especially for copy commands, extended query cycle and different authentication methods) +//TODO(FF): not complete with all commands yet (especially for copy commands, extended query cycle and different authentication methods) public enum PGInterfaceHeaders { //----------------------------------------------- server to client ------------------------------------------------ @@ -39,7 +39,7 @@ public enum PGInterfaceHeaders { /** * ErrorResponse - from server to client - message is error - * Execute - from client to server - used in extended query cycle + * Execute - from client to server - used in extended query cycle - Error Field Type not in Headers */ E, @@ -115,16 +115,3 @@ public enum PGInterfaceHeaders { } - - -/* -ONE(1); - - private final int value; - - Headers(final int newVal) { - value = newVal; - } - - public int getValue() { return value; } - */ diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 1866fae875..30cb4b39c6 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -29,7 +29,7 @@ public class PGInterfaceInboundCommunicationHandler { String type; - ChannelHandlerContext ctx; + static ChannelHandlerContext ctx; TransactionManager transactionManager; ArrayList preparedStatementNames = new ArrayList<>(); ArrayList preparedMessages = new ArrayList<>(); @@ -180,7 +180,7 @@ private void executePreparedStatement(String executeString, String statementName preparedMessage.extractAndSetValues(); PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler( preparedMessage, ctx, this, transactionManager ); - //queryHandler.start(); + queryHandler.start(); //send commandComplete according to query type... (oder em query handler... wo au emmer dases gscheckt werd...) ond parse bind ond ready for query... } @@ -257,7 +257,7 @@ private String extractPreparedQueryName(String cleanedQuery) { * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) */ - public void sendReadyForQuery( String msgBody ) { + public static void sendReadyForQuery(String msgBody) { PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx ); ctx.writeAndFlush( readyForQueryWriter.writeOnByteBuf() ); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 5c242870ef..ec6a030916 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -54,6 +54,7 @@ public class PGInterfaceQueryHandler { private TransactionManager transactionManager; private int rowsAffected = 0; //rows affected (changed/deleted/inserted/etc) private List> rows; + private PGInterfaceErrorHandler errorHandler; public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager ) { @@ -61,6 +62,7 @@ public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInter this.ctx = ctx; this.communicationHandler = communicationHandler; this.transactionManager = transactionManager; + this.errorHandler = new PGInterfaceErrorHandler(ctx); } public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager ) { @@ -69,6 +71,7 @@ public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, Chan this.communicationHandler = communicationHandler; this.transactionManager = transactionManager; preparedQueryCycle = true; + this.errorHandler = new PGInterfaceErrorHandler(ctx); } public void start() { @@ -194,12 +197,12 @@ public void sendQueryToPolypheny() { statement = transaction.createStatement(); } catch ( UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e ) { //TODO(FF): Inform client that something went wrong + //add errorhandler at the top... call simpleerrormessage here throw new RuntimeException( "Error while starting transaction", e ); } try { if (preparedQueryCycle) { - //TODO(FF): how to handle reusable queries?? (do i have to safe them/check if it is reusable?) //TODO(prepared Queries): met dem denn values dezue tue Map types = null; List> values = null; @@ -210,6 +213,7 @@ public void sendQueryToPolypheny() { //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); Node sqlNode = sqlProcessor.parse(query).get(0); + errorHandler.sendSimpleErrorMessage("hallo1234567890"); QueryParameters parameters = new QueryParameters(query, Catalog.NamespaceType.RELATIONAL); if (sqlNode.isA(Kind.DDL)) { result = sqlProcessor.prepareDdl(statement, sqlNode, parameters); @@ -256,8 +260,6 @@ public void sendQueryToPolypheny() { //TODO(FF): Rollback and send error to client //log.error( "Caught exception while executing query", e ); String errorMsg = t.getMessage(); - lol.add(new PGInterfaceErrorHandler( t )); - //result = new PGInterfaceErrorHandler( t ).setGeneratedQuery( query ); try { transaction.rollback(); commitStatus = "Rolled back"; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index b60da1c618..fa21e7d828 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -21,6 +21,8 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; /** * Writes the messages that need to be sent to the client byte-wise on the buffer @@ -33,6 +35,7 @@ public class PGInterfaceServerWriter { public PGInterfaceServerWriter( String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx ) { + //TODO(FF): remove type from initialization and pass it through writeOnByteBuf (would be tidier - but works without problem the way it is) this.type = type; this.pgMsg = pgMsg; this.ctx = ctx; @@ -241,6 +244,32 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { return buffer; } + public ByteBuf writeSimpleErrorMessage (LinkedHashMap fields) { + ByteBuf buffer = ctx.alloc().buffer(); + int msgLength = 4 + 1; + + for (String i : fields.values()) { + msgLength += ( i.length() + 1 ); + } + + buffer.writeByte( pgMsg.getHeaderChar() ); + buffer.writeInt( msgLength ); + + for (String i : fields.values()) { + msgLength += ( i.length() + 1 ); + } + + fields.forEach((fieldType, fieldValue) -> { + buffer.writeByte(fieldType); + buffer.writeBytes(fieldValue.getBytes(StandardCharsets.UTF_8)); + buffer.writeByte( 0 ); + }); + + buffer.writeByte( 0 ); + + return buffer; + } + public ByteBuf writeSeveralStrings(int nbrStrings) { ByteBuf buffer = ctx.alloc().buffer(); From 0ab1692f42bec42475976f40680571c7ae3a8480 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Fri, 21 Oct 2022 20:49:01 +0200 Subject: [PATCH 47/57] rudimentary postgres errorHandler implemented. (sends one type of error to client, who can read error message, but the errormessage causes an error. but doesnt really matter because the client would terminate the connection anyway --- .../polypheny/db/postgresql/PGInterface.java | 6 +- .../db/postgresql/PGInterfaceHeaders.java | 1 - ...GInterfaceInboundCommunicationHandler.java | 25 ++- .../db/postgresql/PGInterfaceMessage.java | 7 +- .../postgresql/PGInterfaceQueryHandler.java | 147 ++++++++---------- .../postgresql/PGInterfaceServerHandler.java | 6 +- .../postgresql/PGInterfaceServerWriter.java | 9 +- 7 files changed, 99 insertions(+), 102 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index a97f1574c8..356196ff05 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -138,7 +138,7 @@ public List getAvailableSettings() { @Override public void shutdown() { - //todo: end things from run() + //TODO(FF): end things from run() --> already done?? workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); monitoringPage.remove(); @@ -153,13 +153,13 @@ public String getInterfaceType() { @Override protected void reloadSettings( List updatedSettings ) { - //Todo: if settings are mutable, change it here (can make them mutable) + //TODO(FF): if settings are mutable, change it here (can make them mutable) //nothing in avatica/http interface } private class MonitoringPage { - //TodO: vergliiche met anderne interfaces (zeigt infos em ui aah) + //TODO(FF): vergliiche met anderne interfaces (zeigt infos em ui aah) --> sött glaubs ok sii?? private final InformationPage informationPage; private final InformationGroup informationGroupRequests; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java index 376d85864f..e063196054 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java @@ -22,7 +22,6 @@ * There exist some special cases (as numbers as header, or no header) * For more information look at the Postgresql documentation: https://www.postgresql.org/docs/current/protocol-message-formats.html */ -//TODO(FF): not complete with all commands yet (especially for copy commands, extended query cycle and different authentication methods) public enum PGInterfaceHeaders { //----------------------------------------------- server to client ------------------------------------------------ diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 30cb4b39c6..4aaf1011bf 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -33,12 +33,14 @@ public class PGInterfaceInboundCommunicationHandler { TransactionManager transactionManager; ArrayList preparedStatementNames = new ArrayList<>(); ArrayList preparedMessages = new ArrayList<>(); + private PGInterfaceErrorHandler errorHandler; public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContext ctx, TransactionManager transactionManager ) { this.type = type; this.ctx = ctx; this.transactionManager = transactionManager; + this.errorHandler = new PGInterfaceErrorHandler(ctx); } @@ -54,10 +56,6 @@ public void decideCycle( Object oMsg ) { //TODO(FF): simple query phase is not implemented switch ( wholeMsg.substring( 0, 1 ) ) { - case "C": //TODO(FF):was gnau passiert do?? - PGInterfaceMessage msg = null; - msg.setHeader( PGInterfaceHeaders.C ); - break; case "r": startUpPhase(); break; @@ -111,8 +109,6 @@ public void extendedQueryPhase( String incomingMsg ) { } else if (incomingMsg.substring(2, 9).equals("PREPARE")) { //Prepared Statement - //TODO(FF): was wenn execute ned as ei message metem prepared chonnt... - //set name ond luege öber scho existiert... --> mues also ergendwo en liste met prepared statements speichere String[] query = extractPreparedQuery( incomingMsg ); String prepareString = query[0]; String executeString = query[1]; @@ -138,7 +134,8 @@ public void extendedQueryPhase( String incomingMsg ) { executePreparedStatement(executeString, statementName); } else { String errorMsg = "There does not exist a prepared statement called" + statementName; - //TODO(FF): send error message to client + errorHandler.sendSimpleErrorMessage(errorMsg); + //TODO(FF): stop sending stuff to client... } } else { @@ -146,7 +143,8 @@ public void extendedQueryPhase( String incomingMsg ) { } } else { String errorMsg = "There already exists a prepared statement with the name" + prepareStringQueryName + "which has not yet been executed"; - //TODO(FF): send error message to client + errorHandler.sendSimpleErrorMessage(errorMsg); + //TODO(FF): stop sending stuff to client... } //List lol = preparedMessage.extractValues(); @@ -161,7 +159,9 @@ public void extendedQueryPhase( String incomingMsg ) { executePreparedStatement(executeQuery, statementName); } else { String errorMsg = "There does not exist a prepared statement called" + statementName; - //TODO(FF): send error message to client + //terminateConnection(); + errorHandler.sendSimpleErrorMessage(errorMsg); + //TODO(FF): stop sending stuff to client... } } @@ -209,8 +209,8 @@ public String extractQuery( String incomingMsg ) { if ( idx != -1 ) { query = query.substring( 0, idx - 2 ); } else { - //TODO(FF) something went wrong!! --> trow exception (in polypheny), send errormessage to client - int lol = 2; + errorHandler.sendSimpleErrorMessage("Something went wrong while extracting the query from the incoming stream"); + //TODO(FF): stop sending stuff to client... } return query; @@ -255,7 +255,7 @@ private String extractPreparedQueryName(String cleanedQuery) { * Creates and sends (flushes on ctx) a readyForQuery message with a tag. The tag is choosable (see below for options). * * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), - * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended (TODO: what exactly happens in transaction blocks.) + * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended */ public static void sendReadyForQuery(String msgBody) { PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); @@ -293,7 +293,6 @@ public void sendParseBindComplete() { public void sendNoData() { - //TODO(FF): not entirely sure in which case this would be needed? PGInterfaceMessage noData = new PGInterfaceMessage( PGInterfaceHeaders.n, "0", 4, true ); PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx ); ctx.writeAndFlush( noDataWriter.writeIntHeaderOnByteBuf('n') ); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 77bba51154..f11d2dd14e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -24,6 +24,7 @@ public class PGInterfaceMessage { private int length; //default is 4, if a different length is mentioned in protocol, this is given private boolean defaultLength; private static final char delimiter = '§'; //for the subparts + private PGInterfaceErrorHandler errorHandler; /** @@ -65,7 +66,8 @@ public char getHeaderChar() { return '3'; } } - //TODO(FF): if returns 0, something went wrong --> inform client + //TODO(FF): if returns 0, something went wrong --> inform client (how??) + return 0; } @@ -79,7 +81,8 @@ public int getHeaderInt() { } else if ( headerString.equals( "THREE" ) ) { return 3; } - //TODO(FF): if returns 0, something went wrong + //TODO(FF): if returns 0, something went wrong (how to inform client??) + //TODO(FF): if returns 0, something went wrong (how to inform client??) return 0; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index ec6a030916..d374d0d4da 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -196,8 +196,8 @@ public void sendQueryToPolypheny() { transaction = transactionManager.startTransaction( Catalog.defaultUserId, Catalog.defaultDatabaseId, false, "Index Manager" ); statement = transaction.createStatement(); } catch ( UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e ) { - //TODO(FF): Inform client that something went wrong - //add errorhandler at the top... call simpleerrormessage here + //TODO(FF): stop sending stuff to client... + errorHandler.sendSimpleErrorMessage("Error while starting transaction" + String.valueOf(e)); throw new RuntimeException( "Error while starting transaction", e ); } @@ -213,7 +213,6 @@ public void sendQueryToPolypheny() { //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); Node sqlNode = sqlProcessor.parse(query).get(0); - errorHandler.sendSimpleErrorMessage("hallo1234567890"); QueryParameters parameters = new QueryParameters(query, Catalog.NamespaceType.RELATIONAL); if (sqlNode.isA(Kind.DDL)) { result = sqlProcessor.prepareDdl(statement, sqlNode, parameters); @@ -240,7 +239,6 @@ public void sendQueryToPolypheny() { //type = result.getStatementType().toString(); type = result.getKind().name(); - //FIXME(FF): macht das senn dasmer nome dors transaction.commit() de fähler bechonnt?? transaction.commit(); @@ -257,14 +255,16 @@ public void sendQueryToPolypheny() { } } catch (Throwable t) { //TransactionExeption? List lol = null; - //TODO(FF): Rollback and send error to client + //TODO(FF): stop sending stuff to client... //log.error( "Caught exception while executing query", e ); String errorMsg = t.getMessage(); + errorHandler.sendSimpleErrorMessage(errorMsg); try { transaction.rollback(); commitStatus = "Rolled back"; } catch (TransactionException ex) { //log.error( "Could not rollback CREATE TABLE statement: {}", ex.getMessage(), ex ); + errorHandler.sendSimpleErrorMessage("Error while rolling back"); commitStatus = "Error while rolling back"; } } @@ -345,7 +345,7 @@ private ArrayList getHeader( PolyImplementation result ) { * @return the rows transformed accordingly (right now turned into a string) */ private ArrayList computeResultData( List> rows, ArrayList header ) { - //TODO(FF): bruuch ich de header do öberhaupt? (aso em momänt ned... ) --> hanich sache wonich de chönnt/müesst bruuche? + //TODO(FF): Implement more Datatypes ArrayList data = new ArrayList<>(); for ( List row : rows ) { @@ -355,7 +355,7 @@ private ArrayList computeResultData( List> rows, ArrayLis if ( o == null ) { temp[counter] = null; } else { - switch ( header.get( counter )[0] ) { //TODO(FF): is switch case nessecary?? if yes, get meaningfull header entry (only handling "standard" returns + switch ( header.get( counter )[0] ) { case "TIMESTAMP": break; case "DATE": @@ -393,7 +393,6 @@ private ArrayList computeResultData( List> rows, ArrayLis public void sendResultToClient( String type, ArrayList data, ArrayList header ) { switch ( type ) { case "INSERT": - //TODO(FF): actually do the things in polypheny --> track number of changed rows (if easy, doesnt really matter for client so far) (put it in header?) but not here, done in sendToPolypheny //INSERT oid rows (oid=0, rows = #rows inserted) //1....2....n....C....INSERT 0 1.Z....I @@ -413,18 +412,15 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... break; case "CREATE_TABLE": - //TODO(FF) do things in polypheny (?) --> not here, but check what to do with commits //1....2....n....C....CREATE TABLE.Z....I communicationHandler.sendParseBindComplete(); //communicationHandler.sendCommandCompleteCreateTable(); - //type = "CREATE TABLE"; communicationHandler.sendCommandComplete( type, -1 ); communicationHandler.sendReadyForQuery( "I" ); break; case "SELECT": - int lol = 4; ArrayList valuesPerCol = new ArrayList(); String fieldName = ""; //string - column name (field name) (matters) @@ -435,75 +431,70 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... int typeModifier = -1; //int32 - The value will generally be -1 (doesn't matter to client while sending) int formatCode = 0; //int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) - if ( lol == 3 ) { //data.isEmpty() TODO(FF): das useneh, bzw usefende wenn noData etzt gnau gscheckt werd... Verdacht: eif normal schecke, halt eif alles 0 ond kei date - //noData - //communicationHandler.sendNoData(); //should only be sent when frontend sent no data (?) error when sent here - - communicationHandler.sendParseBindComplete(); - communicationHandler.sendReadyForQuery( "I" ); - } else { - //data - int numberOfFields = header.size(); //int16 - number of fields (cols) (matters) - - for ( String[] head : header ) { - - fieldName = head[0]; - - //TODO(FF): Implement the rest of the cases - switch ( head[1] ) { - case "BIGINT": - case "DOUBLE": - //TODO(FF): head[2] is the number of decimal places, is set to 3 in standard postgres ("dismissed in beginning, not checked what it actually is") - dataTypeSize = 8; //8 bytes signed - formatCode = 0; - break; - case "BOOLEAN": - dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? - break; - case "DATE": - break; - case "DECIMAL": - break; - case "REAL": - case "INTEGER": - //objectIDColDataType = 32; - dataTypeSize = 4; - formatCode = 0; - break; - case "VARCHAR": - //objectIDColDataType = 1043; - typeModifier = Integer.parseInt( head[2] ); - dataTypeSize = Integer.parseInt( head[2] ); //TODO(FF): I just send the length of the varchar here, because the client doesn't complain. - formatCode = 0; - break; - case "SMALLINT": - dataTypeSize = 2; - formatCode = 0; - break; - case "TINYINT": - dataTypeSize = 1; - formatCode = 0; - break; - case "TIMESTAMP": - break; - case "TIME": - break; - case "FILE": - case "IMAGE": - case "SOUND": - case "VIDEO": - break; - } - Object col[] = { fieldName, objectIDTable, attributeNoCol, objectIDColDataType, dataTypeSize, typeModifier, formatCode }; - valuesPerCol.add( col ); - } - communicationHandler.sendParseBindComplete(); - communicationHandler.sendRowDescription( numberOfFields, valuesPerCol ); - communicationHandler.sendDataRow(data); - rowsAffected = data.size(); - communicationHandler.sendCommandComplete( type, rowsAffected ); - communicationHandler.sendReadyForQuery( "I" ); + //data + int numberOfFields = header.size(); //int16 - number of fields (cols) (matters) + + for ( String[] head : header ) { + + fieldName = head[0]; + + //TODO(FF): Implement the rest of the cases - only Integer and varchar tested --> warn client? + switch ( head[1] ) { + case "BIGINT": + case "DOUBLE": + //TODO(FF): head[2] is the number of decimal places, is set to 3 in standard postgres ("dismissed in beginning, not checked what it actually is") + dataTypeSize = 8; //8 bytes signed + formatCode = 0; + break; + case "BOOLEAN": + dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? + break; + case "DATE": + break; + case "DECIMAL": + break; + case "REAL": + case "INTEGER": + //objectIDColDataType = 32; + dataTypeSize = 4; + formatCode = 0; + break; + case "VARCHAR": + //objectIDColDataType = 1043; + typeModifier = Integer.parseInt( head[2] ); + dataTypeSize = Integer.parseInt( head[2] ); //TODO(FF): I just send the length of the varchar here, because the client doesn't complain. + formatCode = 0; + break; + case "SMALLINT": + dataTypeSize = 2; + formatCode = 0; + break; + case "TINYINT": + dataTypeSize = 1; + formatCode = 0; + break; + case "TIMESTAMP": + break; + case "TIME": + break; + case "FILE": + case "IMAGE": + case "SOUND": + case "VIDEO": + break; + } + Object col[] = { fieldName, objectIDTable, attributeNoCol, objectIDColDataType, dataTypeSize, typeModifier, formatCode }; + valuesPerCol.add( col ); } + communicationHandler.sendParseBindComplete(); + communicationHandler.sendRowDescription( numberOfFields, valuesPerCol ); + communicationHandler.sendDataRow(data); + + rowsAffected = data.size(); + communicationHandler.sendCommandComplete( type, rowsAffected ); + communicationHandler.sendReadyForQuery( "I" ); + break; case "DELETE": diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index fdaeb5a3ce..bd8074eb1b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -26,6 +26,7 @@ public class PGInterfaceServerHandler extends ChannelInboundHandlerAdapter { TransactionManager transactionManager; + PGInterfaceErrorHandler errorHandler; public PGInterfaceServerHandler( TransactionManager transactionManager ) { @@ -45,7 +46,10 @@ public void channelRead( ChannelHandlerContext ctx, Object msg ) { @Override public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) { //cause.printStackTrace(); - //Todo: (evtl): error: Eine vorhandene Verbindung wurde vom Remotehost geschlossen --> if client closes connection "not properly" + //this.errorHandler = new PGInterfaceErrorHandler(ctx); + //errorHandler.sendSimpleErrorMessage(cause.getMessage()); + // I don't client would receive msg, because client already closed connection + ctx.close(); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index fa21e7d828..4008d95b47 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -32,6 +32,7 @@ public class PGInterfaceServerWriter { String type; PGInterfaceMessage pgMsg; ChannelHandlerContext ctx; + PGInterfaceErrorHandler errorHandler; public PGInterfaceServerWriter( String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx ) { @@ -39,6 +40,7 @@ public PGInterfaceServerWriter( String type, PGInterfaceMessage pgMsg, ChannelHa this.type = type; this.pgMsg = pgMsg; this.ctx = ctx; + this.errorHandler = new PGInterfaceErrorHandler(ctx); } @@ -85,20 +87,19 @@ public ByteBuf writeOnByteBuf() { try { body = Integer.parseInt( pgMsg.getMsgBody() ); } catch ( NumberFormatException e ) { - e.printStackTrace(); - //TODO(FF): send error-message to client + errorHandler.sendSimpleErrorMessage("couldn't transform int to string in PGInterfaceServerWriter" + e.getMessage()); } buffer.writeInt( body ); break; //write two strings (tag and message) case "ss": - buffer = writeSeveralStrings( 2 ); //TODO(FF): maybe find better solution (switch case(?))?? + buffer = writeSeveralStrings( 2 ); //TODO(FF): maybe find better solution for strings break; //write 3 strings, example, tag with three components case "sss": - buffer = writeSeveralStrings( 3 ); //TODO(FF): maybe find better solution?? + buffer = writeSeveralStrings( 3 ); break; case "ssm": From 8ccaa9936b38a0f3cad02402b1cac8f744e7e697 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 26 Oct 2022 11:56:57 +0200 Subject: [PATCH 48/57] added infrastructure for tests, fixed bug, if two clients execute at the sime time --- .../postgres/PGInterfaceIntegrationTests.java | 123 ++++++++++++++++++ .../polypheny/db/postgresql/PGInterface.java | 1 + .../postgresql/PGInterfaceErrorHandler.java | 8 +- ...GInterfaceInboundCommunicationHandler.java | 61 +++++---- .../PGInterfacePreparedMessage.java | 7 +- .../postgresql/PGInterfaceQueryHandler.java | 21 ++- .../postgresql/PGInterfaceServerHandler.java | 23 +++- .../postgresql/PGInterfaceServerWriter.java | 7 +- 8 files changed, 212 insertions(+), 39 deletions(-) create mode 100644 dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java new file mode 100644 index 0000000000..5fcf16dfa7 --- /dev/null +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019-2022 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgres; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.polypheny.db.TestHelper; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +//import static org.polypheny.db.postgresql.PGInterfaceInboundCommunicationHandler.ctx; + +public class PGInterfaceIntegrationTests { + + //select: SELECT * FROM public.PGInterfaceTestTable + private String dqlQuerySentByClient = "P\u0000\u0000\u00001\u0000SELECT * FROM public.PGInterfaceTestTable\u0000\u0000\u0000B\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0006P\u0000E\u0000\u0000\u0000\t\u0000\u0000\u0000\u0000\u0000S\u0000\u0000\u0000\u0004"; + + //insert: INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3); + private String dmlQuerySentByClient = "P\u0000\u0000\u0000�\u0000INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3)\u0000\u0000\u0000B\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0006P\u0000E\u0000\u0000\u0000\t\u0000\u0000\u0000\u0000\u0001S\u0000\u0000\u0000\u0004"; + + //create table: CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest)) + private String ddlQuerySentByClient = "P\u0000\u0000\u0000�\u0000CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))\u0000\u0000\u0000B\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0006P\u0000E\u0000\u0000\u0000\t\u0000\u0000\u0000\u0000\u0001S\u0000\u0000\u0000\u0004"; + //new Object[]{"REAL'S HOWTO"}; + + private Connection c; + + + @BeforeClass + public static void start() throws SQLException { + // Ensures that Polypheny-DB is running + //noinspection ResultOfMethodCallIgnored + TestHelper.getInstance(); + } + + + + @Test + public int testIfDDLIsExecuted() { + + try { + Statement statement = c.createStatement(); + + /* + System.out.println("executing select"); + ResultSet rs = statement.executeQuery("SELECT * FROM public.emps"); //empid, deptno, name, salary, commission + //ResultSet rs = statement.executeQuery("SELECT * FROM public.Album"); //AlbumId, Title, ArtistId + System.out.println("SQL-part executed successfully"); + + while (rs.next()) { + int empid = rs.getInt("empid"); + int deptno = rs.getInt("deptno"); + String name = rs.getString("name"); + int salary = rs.getInt("salary"); + int commission = rs.getInt("commission"); + + //System.out.printf( "AlbumId = %s , Title = %s, ArtistId = %s ", albumid,title, artistid ); + System.out.printf("LolId = %s \n", empid); + System.out.printf("deptno = %s \n", deptno); + System.out.printf("name = %s \n", name); + System.out.printf("salary = %s \n", salary); + System.out.printf("commission = %s \n", commission); + System.out.println(); + + } + + */ + + int r = statement.executeUpdate("INSERT INTO public.Album(AlbumId, Title, ArtistId) VALUES (3, 'Lisa', 3);"); + + //rs.close(); + statement.close(); + return r; + + } catch (Exception e) { + e.printStackTrace(); + } + + return 0; + } + + /* + + @Test + public void testIfDDLIsExecuted() { + PGInterfaceInboundCommunicationHandler mockInterfaceInboundCommunicationHandler = mock(PGInterfaceInboundCommunicationHandler.class); + mockInterfaceInboundCommunicationHandler.decideCycle( ddlQuerySentByClient ); + + //TODO(FF): look if result was executed in Polypheny + } + + @Test + public void testIfDMLIsExecuted() { + PGInterfaceInboundCommunicationHandler mockInterfaceInboundCommunicationHandler = mock(PGInterfaceInboundCommunicationHandler.class); + mockInterfaceInboundCommunicationHandler.decideCycle( dmlQuerySentByClient ); + + //TODO(FF): look if result was executed in Polypheny + } + + @Test + public void testIfDQLIsExecuted() { + PGInterfaceInboundCommunicationHandler mockInterfaceInboundCommunicationHandler = mock(PGInterfaceInboundCommunicationHandler.class); + mockInterfaceInboundCommunicationHandler.decideCycle( dqlQuerySentByClient ); + + //TODO(FF): look if result was executed in Polypheny + } + + */ +} diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 356196ff05..c470580172 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -103,6 +103,7 @@ public void run() { .childHandler( new ChannelInitializer() { @Override public void initChannel( SocketChannel socketChannel ) throws Exception { + log.error("initChannel"); ChannelPipeline channelPipeline = socketChannel.pipeline(); //Inbound diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java index 8611a202f1..19077b1bf0 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -19,7 +19,6 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import java.util.HashMap; import java.util.LinkedHashMap; public class PGInterfaceErrorHandler { @@ -28,9 +27,10 @@ public class PGInterfaceErrorHandler { private Throwable exception; private ChannelHandlerContext ctx; private PGInterfaceServerWriter serverWriter; + private PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler; - public PGInterfaceErrorHandler(ChannelHandlerContext ctx) { + public PGInterfaceErrorHandler(ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler) { this.ctx = ctx; } @@ -44,7 +44,7 @@ public void sendSimpleErrorMessage (String errorMsg) { //E..._SERROR.VERROR.C42601.Msyntax error at or near "SSELECT".P1.Fscan.l.L1176.Rscanner_yyerror..Z....I this.errorMsg = errorMsg; PGInterfaceMessage pgInterfaceMessage = new PGInterfaceMessage(PGInterfaceHeaders.E, "MockBody", 4, true); - this.serverWriter = serverWriter = new PGInterfaceServerWriter("MockType", pgInterfaceMessage, ctx); + this.serverWriter = serverWriter = new PGInterfaceServerWriter("MockType", pgInterfaceMessage, ctx, pgInterfaceInboundCommunicationHandler); //FIXME(FF): An error occurs because of the errormessage on the clientside. But it doesn't really matter, because the connection would be terminated anyway and the individual message part arrives... LinkedHashMap errorFields = new LinkedHashMap(); @@ -62,7 +62,7 @@ public void sendSimpleErrorMessage (String errorMsg) { ByteBuf buffer = serverWriter.writeSimpleErrorMessage(errorFields); ctx.writeAndFlush(buffer); - PGInterfaceInboundCommunicationHandler.sendReadyForQuery("I"); + pgInterfaceInboundCommunicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 4aaf1011bf..c3f843dd8d 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -21,18 +21,18 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import lombok.extern.slf4j.Slf4j; import org.polypheny.db.transaction.TransactionManager; /** * Manages all incoming communication, not using the netty framework (but being a handler in netty) */ +@Slf4j public class PGInterfaceInboundCommunicationHandler { String type; - static ChannelHandlerContext ctx; + ChannelHandlerContext ctx; TransactionManager transactionManager; - ArrayList preparedStatementNames = new ArrayList<>(); - ArrayList preparedMessages = new ArrayList<>(); private PGInterfaceErrorHandler errorHandler; @@ -40,7 +40,7 @@ public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContex this.type = type; this.ctx = ctx; this.transactionManager = transactionManager; - this.errorHandler = new PGInterfaceErrorHandler(ctx); + this.errorHandler = new PGInterfaceErrorHandler(ctx, this); } @@ -48,9 +48,10 @@ public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContex * Decides in what cycle from postgres the client is (startup-phase, query-phase, etc.) * * @param oMsg the incoming message from the client (unchanged) + * @param pgInterfaceServerHandler * @return */ - public void decideCycle( Object oMsg ) { + public void decideCycle(Object oMsg, PGInterfaceServerHandler pgInterfaceServerHandler) { String msgWithZeroBits = ((String) oMsg); String wholeMsg = msgWithZeroBits.replace( "\u0000", "" ); @@ -60,7 +61,7 @@ public void decideCycle( Object oMsg ) { startUpPhase(); break; case "P": - extendedQueryPhase( wholeMsg ); + extendedQueryPhase( wholeMsg, pgInterfaceServerHandler ); break; case "X": terminateConnection(); @@ -77,12 +78,12 @@ public void decideCycle( Object oMsg ) { public void startUpPhase() { //authenticationOk PGInterfaceMessage authenticationOk = new PGInterfaceMessage( PGInterfaceHeaders.R, "0", 8, false ); - PGInterfaceServerWriter authenticationOkWriter = new PGInterfaceServerWriter( "i", authenticationOk, ctx ); + PGInterfaceServerWriter authenticationOkWriter = new PGInterfaceServerWriter( "i", authenticationOk, ctx, this); ctx.writeAndFlush( authenticationOkWriter.writeOnByteBuf() ); //server_version (Parameter Status message) PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); - PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter( "ss", parameterStatusServerVs, ctx ); + PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter( "ss", parameterStatusServerVs, ctx, this); ctx.writeAndFlush( parameterStatusServerVsWriter.writeOnByteBuf() ); //ReadyForQuery @@ -99,8 +100,9 @@ public void simpleQueryPhase() { /** * Sends necessary responses to client (without really setting anything in backend) and prepares the incoming query for usage. Continues query forward to QueryHandler * @param incomingMsg unchanged incoming message (transformed to string by netty) + * @param pgInterfaceServerHandler */ - public void extendedQueryPhase( String incomingMsg ) { + public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgInterfaceServerHandler) { if ( incomingMsg.substring( 2, 5 ).equals( "SET" ) ) { sendParseBindComplete(); @@ -108,6 +110,8 @@ public void extendedQueryPhase( String incomingMsg ) { sendReadyForQuery( "I" ); } else if (incomingMsg.substring(2, 9).equals("PREPARE")) { + ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); + //Prepared Statement String[] query = extractPreparedQuery( incomingMsg ); String prepareString = query[0]; @@ -118,8 +122,11 @@ public void extendedQueryPhase( String incomingMsg ) { if (preparedStatementNames.isEmpty() || (!preparedStatementNames.contains(prepareStringQueryName))) { PGInterfacePreparedMessage preparedMessage = new PGInterfacePreparedMessage(prepareStringQueryName, prepareString, ctx); preparedMessage.prepareQuery(); - preparedStatementNames.add(prepareStringQueryName); - preparedMessages.add(preparedMessage); + //preparedStatementNames.add(prepareStringQueryName); //proforma, aber wenni alles rechtig ersetzst sötti das eig chönne uselösche... + pgInterfaceServerHandler.addPreparedStatementNames(prepareStringQueryName); + //ctx.channel().attr(attrObj).set(prepareStringQueryName); + //preparedMessages.add(preparedMessage); + pgInterfaceServerHandler.addPreparedMessage(preparedMessage); //safe everything possible and necessary //send: 1....2....n....C....PREPARE sendParseBindComplete(); @@ -131,7 +138,7 @@ public void extendedQueryPhase( String incomingMsg ) { //check if name exists already if (preparedStatementNames.contains(statementName)) { - executePreparedStatement(executeString, statementName); + executePreparedStatement(executeString, statementName, pgInterfaceServerHandler); } else { String errorMsg = "There does not exist a prepared statement called" + statementName; errorHandler.sendSimpleErrorMessage(errorMsg); @@ -150,13 +157,15 @@ public void extendedQueryPhase( String incomingMsg ) { //List lol = preparedMessage.extractValues(); } else if (incomingMsg.substring(2, 9).equals("EXECUTE")) { + ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); + //get execute statement String executeQuery = extractQuery(incomingMsg); String statementName = extractPreparedQueryName(executeQuery); //check if name exists already if (preparedStatementNames.contains(statementName)) { - executePreparedStatement(executeQuery, statementName); + executePreparedStatement(executeQuery, statementName, pgInterfaceServerHandler); } else { String errorMsg = "There does not exist a prepared statement called" + statementName; //terminateConnection(); @@ -173,9 +182,12 @@ public void extendedQueryPhase( String incomingMsg ) { } } - private void executePreparedStatement(String executeString, String statementName) { + private void executePreparedStatement(String executeString, String statementName, PGInterfaceServerHandler pgInterfaceServerHandler) { + ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); + int idx = preparedStatementNames.indexOf(statementName); - PGInterfacePreparedMessage preparedMessage = preparedMessages.get(idx); + //PGInterfacePreparedMessage preparedMessage = preparedMessages.get(idx); + PGInterfacePreparedMessage preparedMessage = pgInterfaceServerHandler.getPreparedMessage(idx); preparedMessage.setExecuteString(executeString); preparedMessage.extractAndSetValues(); @@ -257,9 +269,9 @@ private String extractPreparedQueryName(String cleanedQuery) { * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended */ - public static void sendReadyForQuery(String msgBody) { + public void sendReadyForQuery(String msgBody) { PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); - PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx ); + PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx, this); ctx.writeAndFlush( readyForQueryWriter.writeOnByteBuf() ); } @@ -283,7 +295,7 @@ public void sendParseBindComplete() { ByteBuf buffer = ctx.alloc().buffer(); PGInterfaceMessage mockMessage = new PGInterfaceMessage( PGInterfaceHeaders.ONE, "0", 4, true ); - PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter( "i", mockMessage, ctx ); + PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter( "i", mockMessage, ctx, this); buffer = headerWriter.writeIntHeaderOnByteBuf( '1' ); buffer.writeBytes( headerWriter.writeIntHeaderOnByteBuf( '2' ) ); ctx.writeAndFlush( buffer ); @@ -294,7 +306,7 @@ public void sendParseBindComplete() { public void sendNoData() { PGInterfaceMessage noData = new PGInterfaceMessage( PGInterfaceHeaders.n, "0", 4, true ); - PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx ); + PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx, this); ctx.writeAndFlush( noDataWriter.writeIntHeaderOnByteBuf('n') ); } @@ -317,7 +329,10 @@ public void sendCommandComplete( String command, int rowsAffected ) { } commandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); - commandCompleteWriter = new PGInterfaceServerWriter( "s", commandComplete, ctx ); + commandCompleteWriter = new PGInterfaceServerWriter( "s", commandComplete, ctx, this); + int hash = ctx.hashCode(); + String lol = command + " | " + String.valueOf(hash); + log.error(lol); ctx.writeAndFlush( commandCompleteWriter.writeOnByteBuf() ); } @@ -330,7 +345,7 @@ public void sendCommandComplete( String command, int rowsAffected ) { public void sendRowDescription( int numberOfFields, ArrayList valuesPerCol ) { String body = String.valueOf( numberOfFields ); PGInterfaceMessage rowDescription = new PGInterfaceMessage( PGInterfaceHeaders.T, body, 4, true ); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription - PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "i", rowDescription, ctx ); + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "i", rowDescription, ctx, this); ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); } @@ -340,7 +355,7 @@ public void sendRowDescription( int numberOfFields, ArrayList valuesPe * @param data data that should be sent */ public void sendDataRow( ArrayList data ) { - int noCols = data.size(); //number of rows returned + int noCols = data.size(); //number of rows returned TODO(FF,low priority): rename every occurence String colVal = ""; //The value of the result int colValLength = 0; //length of the colVal - can be 0 and -1 (-1= NULL is colVal) String body = ""; //combination of colVal and colValLength @@ -366,7 +381,7 @@ public void sendDataRow( ArrayList data ) { } } dataRow = new PGInterfaceMessage( PGInterfaceHeaders.D, body, colValLength, false ); - dataRowWriter = new PGInterfaceServerWriter( "dr", dataRow, ctx ); + dataRowWriter = new PGInterfaceServerWriter( "dr", dataRow, ctx, this); ctx.writeAndFlush( dataRowWriter.writeOnByteBuf() ); body = ""; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index 053537df2d..619a310ac5 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -29,6 +29,7 @@ public class PGInterfacePreparedMessage { private String wholePrepareString; private String executeString; private List dataTypes; + private List data; private static final String executeDelimiter = ", "; @@ -57,19 +58,23 @@ public void setWholePrepareString(String wholePrepareString) { private void setDataTypes(List dataTypes) { this.dataTypes = dataTypes; } + private void setData(List data) { this.data = data; } + public static String getExecuteDelimiter() {return executeDelimiter;} public String getQuery() { return query;} public List getDataTypes() { return dataTypes;} + public List getData() { return data;} + public void extractAndSetValues() { //us execute string - seperator: ', ' //bool ersetze... //cut string at ( and ) (remove chlammere) --> denn mach eif. split, ond problem solved... String onlyExecuteValues = executeString.split("\\(|\\)")[1]; List valueList = Arrays.asList(onlyExecuteValues.split(getExecuteDelimiter())); - setDataTypes(valueList); + setData(valueList); //FIXME(FF): setData, ned setDataTypes } public void extractAndSetTypes() { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index d374d0d4da..b3630c0c93 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; +import lombok.extern.slf4j.Slf4j; import org.polypheny.db.PolyImplementation; import org.polypheny.db.algebra.AlgRoot; import org.polypheny.db.algebra.constant.Kind; @@ -43,7 +44,10 @@ import org.polypheny.db.transaction.Transaction; import org.polypheny.db.transaction.TransactionException; import org.polypheny.db.transaction.TransactionManager; +import org.polypheny.db.type.PolyType; + +@Slf4j public class PGInterfaceQueryHandler { private String query; @@ -62,7 +66,7 @@ public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInter this.ctx = ctx; this.communicationHandler = communicationHandler; this.transactionManager = transactionManager; - this.errorHandler = new PGInterfaceErrorHandler(ctx); + this.errorHandler = new PGInterfaceErrorHandler(ctx, communicationHandler); } public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager ) { @@ -71,16 +75,17 @@ public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, Chan this.communicationHandler = communicationHandler; this.transactionManager = transactionManager; preparedQueryCycle = true; - this.errorHandler = new PGInterfaceErrorHandler(ctx); + this.errorHandler = new PGInterfaceErrorHandler(ctx, communicationHandler); } public void start() { //hardcodeResponse(); - if (!preparedQueryCycle) { - sendQueryToPolypheny(); - } else { + if (preparedQueryCycle) { this.query = preparedMessage.getQuery(); } + //int hash = ctx.hashCode(); + + sendQueryToPolypheny(); } @@ -204,8 +209,12 @@ public void sendQueryToPolypheny() { try { if (preparedQueryCycle) { //TODO(prepared Queries): met dem denn values dezue tue + AlgDataType algDataType = statement.getTransaction().getTypeFactory().createPolyType(PolyType.INTEGER); + statement.getTransaction().getTypeFactory().createPolyType(PolyType.VARCHAR, 255); + statement.getTransaction().getTypeFactory().createPolyType(PolyType.BOOLEAN); + statement.getTransaction().getTypeFactory().createPolyType(PolyType.DECIMAL, 3, 3); Map types = null; - List> values = null; + List> values = null; //long index statement.getDataContext().setParameterTypes(types); //döfs erscht bem execute step mache... statement.getDataContext().setParameterValues(values); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index bd8074eb1b..0b696d444f 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -20,6 +20,8 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import org.polypheny.db.transaction.TransactionManager; +import java.util.ArrayList; + /** * Forwards the message from the "netty flow" to the internal structure */ @@ -27,6 +29,8 @@ public class PGInterfaceServerHandler extends ChannelInboundHandlerAdapter { TransactionManager transactionManager; PGInterfaceErrorHandler errorHandler; + ArrayList preparedStatementNames = new ArrayList<>(); //safes it for the whole time polypheny is running... + ArrayList preparedMessages = new ArrayList<>(); public PGInterfaceServerHandler( TransactionManager transactionManager ) { @@ -37,9 +41,10 @@ public PGInterfaceServerHandler( TransactionManager transactionManager ) { @Override public void channelRead( ChannelHandlerContext ctx, Object msg ) { //StatusService.printInfo(String.format("channel read reached...")); + //this.preparedStatementNames= new ArrayList<>(); PGInterfaceInboundCommunicationHandler interfaceInboundCommunicationHandler = new PGInterfaceInboundCommunicationHandler( "", ctx, transactionManager ); - interfaceInboundCommunicationHandler.decideCycle( msg ); + interfaceInboundCommunicationHandler.decideCycle( msg, this ); } @@ -53,5 +58,21 @@ public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) { ctx.close(); } + public void addPreparedStatementNames(String name) { + preparedStatementNames.add(name); + } + + public void addPreparedMessage(PGInterfacePreparedMessage preparedMessage) { + preparedMessages.add(preparedMessage); + } + + public ArrayList getPreparedStatementNames() { + return preparedStatementNames; + } + + public PGInterfacePreparedMessage getPreparedMessage(int idx) { + return preparedMessages.get(idx); + } + } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 4008d95b47..b3563a8d98 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -18,10 +18,9 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import java.nio.charset.Charset; + import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; /** @@ -35,12 +34,12 @@ public class PGInterfaceServerWriter { PGInterfaceErrorHandler errorHandler; - public PGInterfaceServerWriter( String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx ) { + public PGInterfaceServerWriter(String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler) { //TODO(FF): remove type from initialization and pass it through writeOnByteBuf (would be tidier - but works without problem the way it is) this.type = type; this.pgMsg = pgMsg; this.ctx = ctx; - this.errorHandler = new PGInterfaceErrorHandler(ctx); + this.errorHandler = new PGInterfaceErrorHandler(ctx, pgInterfaceInboundCommunicationHandler); } From b5b04507c55a85f69b7b4a6a3194713ca308343e Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 26 Oct 2022 15:46:51 +0200 Subject: [PATCH 49/57] prepared statements seem to work now... yaay --- .../postgresql/PGInterfaceErrorHandler.java | 2 +- ...GInterfaceInboundCommunicationHandler.java | 6 +- .../PGInterfacePreparedMessage.java | 87 ++++++++++++++++++- .../postgresql/PGInterfaceQueryHandler.java | 11 +-- 4 files changed, 90 insertions(+), 16 deletions(-) diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java index 19077b1bf0..9a0d2a658b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -62,7 +62,7 @@ public void sendSimpleErrorMessage (String errorMsg) { ByteBuf buffer = serverWriter.writeSimpleErrorMessage(errorFields); ctx.writeAndFlush(buffer); - pgInterfaceInboundCommunicationHandler.sendReadyForQuery("I"); + //pgInterfaceInboundCommunicationHandler.sendReadyForQuery("I"); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index c3f843dd8d..b17e409e22 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -330,9 +330,9 @@ public void sendCommandComplete( String command, int rowsAffected ) { commandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); commandCompleteWriter = new PGInterfaceServerWriter( "s", commandComplete, ctx, this); - int hash = ctx.hashCode(); - String lol = command + " | " + String.valueOf(hash); - log.error(lol); + //int hash = ctx.hashCode(); + //String lol = command + " | " + String.valueOf(hash); + //log.error(lol); ctx.writeAndFlush( commandCompleteWriter.writeOnByteBuf() ); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index 619a310ac5..70ea43197e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -17,10 +17,12 @@ package org.polypheny.db.postgresql; import io.netty.channel.ChannelHandlerContext; +import org.polypheny.db.adapter.DataContext; +import org.polypheny.db.algebra.type.AlgDataType; +import org.polypheny.db.transaction.Statement; +import org.polypheny.db.type.PolyType; -import java.util.Arrays; -import java.util.List; -import java.util.ListIterator; +import java.util.*; public class PGInterfacePreparedMessage { private String name; @@ -31,6 +33,8 @@ public class PGInterfacePreparedMessage { private List dataTypes; private List data; private static final String executeDelimiter = ", "; + private Map typesPolyphey = new HashMap(); + private List> valuesPolypeny = new ArrayList>(); public PGInterfacePreparedMessage(String name, String wholePrepareString, ChannelHandlerContext ctx) { @@ -119,5 +123,82 @@ public void prepareQuery() { extractAndSetQuery(); } + public void transformDataAndAddParameterValues (Statement statement) { + long idx = 0; + for (String type : dataTypes) { + List o = new ArrayList<>(); + for (String value : data) { + o.add(transformData(value, type)); + } + AlgDataType algDataType = transformToAlgDataType(type, statement); + statement.getDataContext().addParameterValues(idx, algDataType, o); + } + /* + // Add values to data context + //values() chonnt vo map + Map> values = null; + + for(int i=0; ivalFor = values.get(i); + List o = new ArrayList<>(); + for(int j=0; jthe object, which is the value + } + //addParameterValues( long index, AlgDataType type, List data ); + statement.getDataContext().addParameterValues(valFor.get(0).getIndex(), valFor.get(0).getType(), o); + } + + + for ( List values : queryParameterizer.getValues().values() ) { + List o = new ArrayList<>(); + for ( DataContext.ParameterValue v : values ) { + o.add( v.getValue() ); + } + statement.getDataContext().addParameterValues( values.get( 0 ).getIndex(), values.get( 0 ).getType(), o ); + } + + */ + } + + private Object transformData(String value, String type) { + Object o = new Object(); + switch (type) { + case "int": + o = Integer.valueOf(value); + break; + case "text": + o = value; + break; + case "bool": + o = Boolean.parseBoolean(value); + break; + case "numeric": + o = Double.parseDouble(value); + break; + } + return o; + } + + private AlgDataType transformToAlgDataType(String type, Statement statement) { + AlgDataType result = null; + switch (type) { + case "int": + result = statement.getTransaction().getTypeFactory().createPolyType(PolyType.INTEGER); + break; + case "text": + result = statement.getTransaction().getTypeFactory().createPolyType(PolyType.VARCHAR, 255); //TODO(FF): how do I know the precision? + break; + case "bool": + result = statement.getTransaction().getTypeFactory().createPolyType(PolyType.BOOLEAN); + break; + case "numeric": + result = statement.getTransaction().getTypeFactory().createPolyType(PolyType.DECIMAL, 3, 3); + break; + } + + return result; + } + } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index b3630c0c93..a8bd851d0a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -207,16 +207,9 @@ public void sendQueryToPolypheny() { } try { - if (preparedQueryCycle) { + if (preparedQueryCycle) { //TODO: nome be execute döfs do ine!! //TODO(prepared Queries): met dem denn values dezue tue - AlgDataType algDataType = statement.getTransaction().getTypeFactory().createPolyType(PolyType.INTEGER); - statement.getTransaction().getTypeFactory().createPolyType(PolyType.VARCHAR, 255); - statement.getTransaction().getTypeFactory().createPolyType(PolyType.BOOLEAN); - statement.getTransaction().getTypeFactory().createPolyType(PolyType.DECIMAL, 3, 3); - Map types = null; - List> values = null; //long index - statement.getDataContext().setParameterTypes(types); //döfs erscht bem execute step mache... - statement.getDataContext().setParameterValues(values); + preparedMessage.transformDataAndAddParameterValues(statement); } //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) From c62ec9a9d951309f34149943aad79906f87362bc Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 26 Oct 2022 17:30:03 +0200 Subject: [PATCH 50/57] more errorhandling and new answers to client for DROP_TABLE, TRUNCATE and UPDATE --- .../postgres/PGInterfaceIntegrationTests.java | 13 ++++++++++ ...GInterfaceInboundCommunicationHandler.java | 7 ++---- .../db/postgresql/PGInterfaceMessage.java | 7 +++--- .../PGInterfacePreparedMessage.java | 25 ------------------- .../postgresql/PGInterfaceQueryHandler.java | 19 ++++++++------ .../postgresql/PGInterfaceServerHandler.java | 3 ++- 6 files changed, 32 insertions(+), 42 deletions(-) diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index 5fcf16dfa7..ecd3da7c5a 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -16,6 +16,7 @@ package org.polypheny.db.postgres; +import com.google.common.collect.ImmutableList; import org.junit.BeforeClass; import org.junit.Test; import org.polypheny.db.TestHelper; @@ -93,6 +94,18 @@ public int testIfDDLIsExecuted() { return 0; } + @Test + public void basicTest() throws SQLException { + try ( TestHelper.JdbcConnection polyphenyDbConnection = new TestHelper.JdbcConnection( true ) ) { + Connection connection = polyphenyDbConnection.getConnection(); + try ( Statement statement = connection.createStatement() ) { + TestHelper.checkResultSet( + statement.executeQuery( "SELECT ARRAY[1, 2] = ARRAY[1, 2], ARRAY[2, 4] = ARRAY[2, 3]" ), + ImmutableList.of( new Object[]{ true, false } ) ); + } + } + } + /* @Test diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index b17e409e22..9857445670 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -66,6 +66,8 @@ public void decideCycle(Object oMsg, PGInterfaceServerHandler pgInterfaceServerH case "X": terminateConnection(); break; + default: + errorHandler.sendSimpleErrorMessage("The message could not be parsed by the PGInterface."); } } @@ -387,11 +389,6 @@ public void sendDataRow( ArrayList data ) { } } - - private void sendErrorResponse(String error) { - - } - public void terminateConnection() { ctx.close(); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index f11d2dd14e..ffba085c3d 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -66,7 +66,8 @@ public char getHeaderChar() { return '3'; } } - //TODO(FF): if returns 0, something went wrong --> inform client (how??) + //TODO(FF): stop sending data to client + errorHandler.sendSimpleErrorMessage("PGInterface>PGInterfaceMessage>getHeaderChar: This should never be reached."); return 0; } @@ -81,8 +82,8 @@ public int getHeaderInt() { } else if ( headerString.equals( "THREE" ) ) { return 3; } - //TODO(FF): if returns 0, something went wrong (how to inform client??) - //TODO(FF): if returns 0, something went wrong (how to inform client??) + //TODO(FF): stop sending data to client + errorHandler.sendSimpleErrorMessage("PGInterface>PGInterfaceMessage>getHeaderInt: This should never be reached."); return 0; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index 70ea43197e..abb172603b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -133,32 +133,7 @@ public void transformDataAndAddParameterValues (Statement statement) { AlgDataType algDataType = transformToAlgDataType(type, statement); statement.getDataContext().addParameterValues(idx, algDataType, o); } - /* - // Add values to data context - //values() chonnt vo map - Map> values = null; - for(int i=0; ivalFor = values.get(i); - List o = new ArrayList<>(); - for(int j=0; jthe object, which is the value - } - //addParameterValues( long index, AlgDataType type, List data ); - statement.getDataContext().addParameterValues(valFor.get(0).getIndex(), valFor.get(0).getType(), o); - } - - - for ( List values : queryParameterizer.getValues().values() ) { - List o = new ArrayList<>(); - for ( DataContext.ParameterValue v : values ) { - o.add( v.getValue() ); - } - statement.getDataContext().addParameterValues( values.get( 0 ).getIndex(), values.get( 0 ).getType(), o ); - } - - */ } private Object transformData(String value, String type) { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index a8bd851d0a..587b7cbeef 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -395,6 +395,10 @@ private ArrayList computeResultData( List> rows, ArrayLis public void sendResultToClient( String type, ArrayList data, ArrayList header ) { switch ( type ) { case "INSERT": + case "DROP_TABLE": + case "TRUNCATE": + case "UPDATE": + //INSERT oid rows (oid=0, rows = #rows inserted) //1....2....n....C....INSERT 0 1.Z....I @@ -452,8 +456,6 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... case "BOOLEAN": dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? break; - case "DATE": - break; case "DECIMAL": break; case "REAL": @@ -476,14 +478,15 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... dataTypeSize = 1; formatCode = 0; break; + case "DATE": case "TIMESTAMP": - break; case "TIME": - break; case "FILE": case "IMAGE": case "SOUND": case "VIDEO": + default: + errorHandler.sendSimpleErrorMessage("The DataType of the answer is not yet implemented, but there is a high chance that the query was executed in Polypheny"); break; } Object col[] = { fieldName, objectIDTable, attributeNoCol, objectIDColDataType, dataTypeSize, typeModifier, formatCode }; @@ -501,18 +504,18 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... case "DELETE": //DELETE rows (rows = #rows deleted) - break; case "MOVE": //MOVE rows (rows = #rows the cursor's position has been changed by (??)) - break; case "FETCH": //FETCH rows (rows = #rows that have been retrieved from cursor) - break; case "COPY": - //COPY rows (rows = #rows copied --> only on PSQL 8.2 and later) + //COPY rows (rows = #rows copied --> only on PSQL 8.2 and later)$ + + default: + errorHandler.sendSimpleErrorMessage("Answer to client is not yet supported, but there is a high chance that the query was executed in Polypheny"); break; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 0b696d444f..6c1afe74f7 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -51,9 +51,10 @@ public void channelRead( ChannelHandlerContext ctx, Object msg ) { @Override public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) { //cause.printStackTrace(); + + // Client wouldn't receive msg, because client already closed connection //this.errorHandler = new PGInterfaceErrorHandler(ctx); //errorHandler.sendSimpleErrorMessage(cause.getMessage()); - // I don't client would receive msg, because client already closed connection ctx.close(); } From 789e07ef66df72e74e94e14cd34b5ef26cc3665b Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 26 Oct 2022 18:58:41 +0200 Subject: [PATCH 51/57] implemented tests, but no connection can be established as of yet... --- .../postgres/PGInterfaceIntegrationTests.java | 117 ++++++++++-------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index ecd3da7c5a..d6d040c84d 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -17,15 +17,22 @@ package org.polypheny.db.postgres; import com.google.common.collect.ImmutableList; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.polypheny.db.TestHelper; import java.sql.Connection; +import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + //import static org.polypheny.db.postgresql.PGInterfaceInboundCommunicationHandler.ctx; + public class PGInterfaceIntegrationTests { //select: SELECT * FROM public.PGInterfaceTestTable @@ -38,7 +45,6 @@ public class PGInterfaceIntegrationTests { private String ddlQuerySentByClient = "P\u0000\u0000\u0000�\u0000CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))\u0000\u0000\u0000B\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0006P\u0000E\u0000\u0000\u0000\t\u0000\u0000\u0000\u0000\u0001S\u0000\u0000\u0000\u0004"; //new Object[]{"REAL'S HOWTO"}; - private Connection c; @BeforeClass @@ -48,50 +54,54 @@ public static void start() throws SQLException { TestHelper.getInstance(); } + @AfterClass + public static void stop() { + Properties connectionProps = new Properties(); + connectionProps.setProperty("sslmode", "disable"); + String url = "jdbc:postgresql://localhost:5432/"; + try (Connection c = DriverManager.getConnection(url, connectionProps)) { + try(Statement statement = c.createStatement()) { + int status = statement.executeUpdate("DROP TABLE public.PGInterfaceTestTable"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } - @Test - public int testIfDDLIsExecuted() { - - try { - Statement statement = c.createStatement(); - - /* - System.out.println("executing select"); - ResultSet rs = statement.executeQuery("SELECT * FROM public.emps"); //empid, deptno, name, salary, commission - //ResultSet rs = statement.executeQuery("SELECT * FROM public.Album"); //AlbumId, Title, ArtistId - System.out.println("SQL-part executed successfully"); - - while (rs.next()) { - int empid = rs.getInt("empid"); - int deptno = rs.getInt("deptno"); - String name = rs.getString("name"); - int salary = rs.getInt("salary"); - int commission = rs.getInt("commission"); - //System.out.printf( "AlbumId = %s , Title = %s, ArtistId = %s ", albumid,title, artistid ); - System.out.printf("LolId = %s \n", empid); - System.out.printf("deptno = %s \n", deptno); - System.out.printf("name = %s \n", name); - System.out.printf("salary = %s \n", salary); - System.out.printf("commission = %s \n", commission); - System.out.println(); - } + @Test + public void testIfDDLIsExecuted() throws SQLException { - */ + try { + Connection c = null; + Properties connectionProps = new Properties(); + connectionProps.setProperty("sslmode", "disable"); + String url = "jdbc:postgresql://localhost:5444/"; - int r = statement.executeUpdate("INSERT INTO public.Album(AlbumId, Title, ArtistId) VALUES (3, 'Lisa', 3);"); + c = DriverManager.getConnection(url, connectionProps); + Statement statement = c.createStatement(); + int status = statement.executeUpdate("CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - //rs.close(); statement.close(); - return r; + } catch (Exception e) { e.printStackTrace(); } - return 0; + + + Properties connectionProps = new Properties(); + connectionProps.setProperty("sslmode", "disable"); + String url = "jdbc:postgresql://localhost:5432/"; + try (Connection c = DriverManager.getConnection(url, connectionProps)) { + try(Statement statement = c.createStatement()) { + int status = statement.executeUpdate("CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); + assertEquals(0, status); + } + } } @Test @@ -106,31 +116,36 @@ public void basicTest() throws SQLException { } } - /* @Test - public void testIfDDLIsExecuted() { - PGInterfaceInboundCommunicationHandler mockInterfaceInboundCommunicationHandler = mock(PGInterfaceInboundCommunicationHandler.class); - mockInterfaceInboundCommunicationHandler.decideCycle( ddlQuerySentByClient ); - - //TODO(FF): look if result was executed in Polypheny - } - - @Test - public void testIfDMLIsExecuted() { - PGInterfaceInboundCommunicationHandler mockInterfaceInboundCommunicationHandler = mock(PGInterfaceInboundCommunicationHandler.class); - mockInterfaceInboundCommunicationHandler.decideCycle( dmlQuerySentByClient ); - - //TODO(FF): look if result was executed in Polypheny + public void testIfDMLIsExecuted() throws SQLException { + Properties connectionProps = new Properties(); + connectionProps.setProperty("sslmode", "disable"); + String url = "jdbc:postgresql://localhost:5432/"; + try (Connection c = DriverManager.getConnection(url, connectionProps)) { + try(Statement statement = c.createStatement()) { + int status = statement.executeUpdate("INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);"); + assertEquals(0, status); + } + } } @Test - public void testIfDQLIsExecuted() { - PGInterfaceInboundCommunicationHandler mockInterfaceInboundCommunicationHandler = mock(PGInterfaceInboundCommunicationHandler.class); - mockInterfaceInboundCommunicationHandler.decideCycle( dqlQuerySentByClient ); + public void testIfDQLIsExecuted() throws SQLException { + Properties connectionProps = new Properties(); + connectionProps.setProperty("sslmode", "disable"); + String url = "jdbc:postgresql://localhost:5432/"; + try (Connection c = DriverManager.getConnection(url, connectionProps)) { + try (Statement statement = c.createStatement()) { + TestHelper.checkResultSet( + statement.executeQuery("SELECT * FROM PGInterfaceTestTable"), + ImmutableList.of( + new Object[]{1, "Franz", 1}, + new Object[]{2, "Hello", 2}, + new Object[]{3, "By", 3})); - //TODO(FF): look if result was executed in Polypheny + } + } } - */ } From e99981a5d7210fae5d124346c407843daac6894b Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Thu, 27 Oct 2022 17:14:00 +0200 Subject: [PATCH 52/57] test works now, decide cycle is now handled slightly differently, found and added OID of the dataType --- .../postgres/PGInterfaceIntegrationTests.java | 162 +++++++++++------- .../polypheny/db/postgresql/PGInterface.java | 1 - .../postgresql/PGInterfaceErrorHandler.java | 2 + ...GInterfaceInboundCommunicationHandler.java | 25 +-- .../db/postgresql/PGInterfaceMessage.java | 3 + .../PGInterfacePreparedMessage.java | 2 + .../postgresql/PGInterfaceQueryHandler.java | 11 +- .../postgresql/PGInterfaceServerHandler.java | 3 + .../postgresql/PGInterfaceServerWriter.java | 2 + 9 files changed, 131 insertions(+), 80 deletions(-) diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index d6d040c84d..8db22d8adc 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -17,32 +17,28 @@ package org.polypheny.db.postgres; import com.google.common.collect.ImmutableList; +import lombok.extern.slf4j.Slf4j; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.polypheny.db.TestHelper; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; import static org.junit.Assert.assertEquals; //import static org.polypheny.db.postgresql.PGInterfaceInboundCommunicationHandler.ctx; - +@Slf4j public class PGInterfaceIntegrationTests { //select: SELECT * FROM public.PGInterfaceTestTable - private String dqlQuerySentByClient = "P\u0000\u0000\u00001\u0000SELECT * FROM public.PGInterfaceTestTable\u0000\u0000\u0000B\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0006P\u0000E\u0000\u0000\u0000\t\u0000\u0000\u0000\u0000\u0000S\u0000\u0000\u0000\u0004"; //insert: INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3); - private String dmlQuerySentByClient = "P\u0000\u0000\u0000�\u0000INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3)\u0000\u0000\u0000B\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0006P\u0000E\u0000\u0000\u0000\t\u0000\u0000\u0000\u0000\u0001S\u0000\u0000\u0000\u0004"; - //create table: CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest)) - private String ddlQuerySentByClient = "P\u0000\u0000\u0000�\u0000CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))\u0000\u0000\u0000B\u0000\u0000\u0000\f\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0006P\u0000E\u0000\u0000\u0000\t\u0000\u0000\u0000\u0000\u0001S\u0000\u0000\u0000\u0004"; //new Object[]{"REAL'S HOWTO"}; @@ -51,94 +47,91 @@ public class PGInterfaceIntegrationTests { public static void start() throws SQLException { // Ensures that Polypheny-DB is running //noinspection ResultOfMethodCallIgnored + TestHelper.getInstance(); - } - @AfterClass - public static void stop() { - Properties connectionProps = new Properties(); - connectionProps.setProperty("sslmode", "disable"); - String url = "jdbc:postgresql://localhost:5432/"; - try (Connection c = DriverManager.getConnection(url, connectionProps)) { - try(Statement statement = c.createStatement()) { - int status = statement.executeUpdate("DROP TABLE public.PGInterfaceTestTable"); + try ( TestHelper.JdbcConnection polyphenyDbConnection = new TestHelper.JdbcConnection( false ) ) { + Connection connection = polyphenyDbConnection.getConnection(); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate("ALTER INTERFACES ADD \"pgtestinterface\" USING 'org.polypheny.db.postgresql.PGInterface' WITH '{\"port\":\"5433\"}'"); } - } catch (SQLException e) { - e.printStackTrace(); } + //ALTER INTERFACES ADD "sdf" USING 'org.polypheny.db.postgresql.PGInterface' WITH '{"port":"5433"}' } + @AfterClass + public static void stop() throws SQLException { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + Connection connection = psqlJdbcConnection.getConnection(); + try(Statement statement = connection.createStatement()) { + statement.executeUpdate("DROP TABLE public.pginterfacetesttable"); + //statement.executeUpdate( "ALTER INTERFACES DROP pgtestinerface" ); + } + } + } - @Test - public void testIfDDLIsExecuted() throws SQLException { - try { - Connection c = null; - Properties connectionProps = new Properties(); - connectionProps.setProperty("sslmode", "disable"); - String url = "jdbc:postgresql://localhost:5444/"; - c = DriverManager.getConnection(url, connectionProps); - Statement statement = c.createStatement(); - int status = statement.executeUpdate("CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - statement.close(); + @Test + public void testIfDMLIsExecuted() throws SQLException { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + Connection connection = psqlJdbcConnection.getConnection(); + try(Statement statement = connection.createStatement()) { + statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); + statement.executeUpdate("INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);"); + ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); - } catch (Exception e) { - e.printStackTrace(); + TestHelper.checkResultSet( + rs, + ImmutableList.of( + new Object[]{1, "Franz", 1}, + new Object[]{2, "Hello", 2}, + new Object[]{3, "By", 3}) + ); + } } + } +/* - Properties connectionProps = new Properties(); - connectionProps.setProperty("sslmode", "disable"); - String url = "jdbc:postgresql://localhost:5432/"; - try (Connection c = DriverManager.getConnection(url, connectionProps)) { - try(Statement statement = c.createStatement()) { - int status = statement.executeUpdate("CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - assertEquals(0, status); - } - } - } + @Test + public void testIfDDLIsExecuted() throws SQLException { - @Test - public void basicTest() throws SQLException { - try ( TestHelper.JdbcConnection polyphenyDbConnection = new TestHelper.JdbcConnection( true ) ) { - Connection connection = polyphenyDbConnection.getConnection(); - try ( Statement statement = connection.createStatement() ) { - TestHelper.checkResultSet( - statement.executeQuery( "SELECT ARRAY[1, 2] = ARRAY[1, 2], ARRAY[2, 4] = ARRAY[2, 3]" ), - ImmutableList.of( new Object[]{ true, false } ) ); - } + try(Statement statement = connection.createStatement()) { + statement.executeUpdate("CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); + CatalogTable catalogTable = Catalog.getInstance().getTable(Catalog.getInstance().getSchema(Catalog.defaultDatabaseId, "public").id , "PGInterfaceTestTable"); + assertEquals(catalogTable.name, "pginterfacetesttable"); + } catch (UnknownTableException e) { + e.printStackTrace(); + } catch (UnknownSchemaException e) { + e.printStackTrace(); } } + + @Test public void testIfDMLIsExecuted() throws SQLException { - Properties connectionProps = new Properties(); - connectionProps.setProperty("sslmode", "disable"); - String url = "jdbc:postgresql://localhost:5432/"; - try (Connection c = DriverManager.getConnection(url, connectionProps)) { - try(Statement statement = c.createStatement()) { - int status = statement.executeUpdate("INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);"); - assertEquals(0, status); - } + + try(Statement statement = c.createStatement()) { + int status = statement.executeUpdate("INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);"); + assertEquals(0, status); } + } @Test public void testIfDQLIsExecuted() throws SQLException { - Properties connectionProps = new Properties(); - connectionProps.setProperty("sslmode", "disable"); - String url = "jdbc:postgresql://localhost:5432/"; try (Connection c = DriverManager.getConnection(url, connectionProps)) { try (Statement statement = c.createStatement()) { TestHelper.checkResultSet( - statement.executeQuery("SELECT * FROM PGInterfaceTestTable"), + statement.executeQuery("SELECT * FROM PGInterfaceTestTable;"), ImmutableList.of( new Object[]{1, "Franz", 1}, new Object[]{2, "Hello", 2}, @@ -148,4 +141,45 @@ public void testIfDQLIsExecuted() throws SQLException { } } + */ + + + public static class PsqlJdbcConnection implements AutoCloseable { + + private final static String dbHost = "localhost"; + private final static int port = 5433; + + private final Connection conn; + + + public PsqlJdbcConnection(boolean autoCommit ) throws SQLException { + try { + Class.forName( "org.postgresql.Driver" ); + } catch ( ClassNotFoundException e ) { + log.error( "PostgreSQL JDBC Driver not found", e ); + } + final String url = "jdbc:postgresql://" + dbHost + ":" + port + "/"; + log.debug( "Connecting to database @ {}", url ); + + Properties connectionProps = new Properties(); + connectionProps.setProperty("sslmode", "disable"); + conn = DriverManager.getConnection(url, connectionProps); + + //conn.setAutoCommit( autoCommit ); + } + + + public Connection getConnection() { + return conn; + } + + + @Override + public void close() throws SQLException { + //conn.commit(); + conn.close(); + } + + } + } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index c470580172..356196ff05 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -103,7 +103,6 @@ public void run() { .childHandler( new ChannelInitializer() { @Override public void initChannel( SocketChannel socketChannel ) throws Exception { - log.error("initChannel"); ChannelPipeline channelPipeline = socketChannel.pipeline(); //Inbound diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java index 9a0d2a658b..be6117065b 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -18,9 +18,11 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; import java.util.LinkedHashMap; +@Slf4j public class PGInterfaceErrorHandler { private String errorMsg; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 9857445670..363595f82d 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -55,20 +55,21 @@ public void decideCycle(Object oMsg, PGInterfaceServerHandler pgInterfaceServerH String msgWithZeroBits = ((String) oMsg); String wholeMsg = msgWithZeroBits.replace( "\u0000", "" ); + //TODO(FF): simple query phase is not implemented - switch ( wholeMsg.substring( 0, 1 ) ) { - case "r": - startUpPhase(); - break; - case "P": - extendedQueryPhase( wholeMsg, pgInterfaceServerHandler ); - break; - case "X": - terminateConnection(); - break; - default: - errorHandler.sendSimpleErrorMessage("The message could not be parsed by the PGInterface."); + if ( wholeMsg.substring( 2, 6 ).contains("user") ) { + startUpPhase(); + } + + else if ( wholeMsg.substring( 0, 1 ).equals("P") ) { + extendedQueryPhase( wholeMsg, pgInterfaceServerHandler ); + } + else if ( wholeMsg.substring( 0, 1 ).equals("X") ) { + terminateConnection(); + } + else { + errorHandler.sendSimpleErrorMessage("The message could not be parsed by the PGInterface."); } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index ffba085c3d..8c75ee9c25 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -16,7 +16,10 @@ package org.polypheny.db.postgresql; +import lombok.extern.slf4j.Slf4j; + //message sent by client and server (connection-level) +@Slf4j public class PGInterfaceMessage { private PGInterfaceHeaders header; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index abb172603b..d9a4d54eef 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -17,6 +17,7 @@ package org.polypheny.db.postgresql; import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; import org.polypheny.db.adapter.DataContext; import org.polypheny.db.algebra.type.AlgDataType; import org.polypheny.db.transaction.Statement; @@ -24,6 +25,7 @@ import java.util.*; +@Slf4j public class PGInterfacePreparedMessage { private String name; private ChannelHandlerContext ctx; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index 587b7cbeef..b3b9807f56 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -429,6 +429,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... case "SELECT": ArrayList valuesPerCol = new ArrayList(); + //More info about these variables in javadoc for PGInterfaceServerWriter > writeRowDescription String fieldName = ""; //string - column name (field name) (matters) int objectIDTable = 0; //int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) int attributeNoCol = 0; //int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) @@ -452,33 +453,37 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... //TODO(FF): head[2] is the number of decimal places, is set to 3 in standard postgres ("dismissed in beginning, not checked what it actually is") dataTypeSize = 8; //8 bytes signed formatCode = 0; + objectIDColDataType = 20; break; case "BOOLEAN": dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? + objectIDColDataType = 16; break; case "DECIMAL": break; case "REAL": case "INTEGER": - //objectIDColDataType = 32; + objectIDColDataType = 23; dataTypeSize = 4; formatCode = 0; break; case "VARCHAR": - //objectIDColDataType = 1043; + objectIDColDataType = 1043; typeModifier = Integer.parseInt( head[2] ); dataTypeSize = Integer.parseInt( head[2] ); //TODO(FF): I just send the length of the varchar here, because the client doesn't complain. formatCode = 0; break; case "SMALLINT": + objectIDColDataType = 21; dataTypeSize = 2; formatCode = 0; break; case "TINYINT": + objectIDColDataType = 21; //is the same oID as for int2 dataTypeSize = 1; formatCode = 0; break; - case "DATE": + case "DATE": //I did not find a list online for all OID's --> more info in javadoc of PGInterfaceServerWriter > writeRowDescripton case "TIMESTAMP": case "TIME": case "FILE": diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 6c1afe74f7..1b98f6ac30 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -18,6 +18,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import lombok.extern.slf4j.Slf4j; import org.polypheny.db.transaction.TransactionManager; import java.util.ArrayList; @@ -25,6 +26,7 @@ /** * Forwards the message from the "netty flow" to the internal structure */ +@Slf4j public class PGInterfaceServerHandler extends ChannelInboundHandlerAdapter { TransactionManager transactionManager; @@ -56,6 +58,7 @@ public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) { //this.errorHandler = new PGInterfaceErrorHandler(ctx); //errorHandler.sendSimpleErrorMessage(cause.getMessage()); + //log.error(cause.getMessage()); ctx.close(); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index b3563a8d98..d84023e5a7 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -18,6 +18,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -26,6 +27,7 @@ /** * Writes the messages that need to be sent to the client byte-wise on the buffer */ +@Slf4j public class PGInterfaceServerWriter { String type; From 4e170808335eeea251f27930399291a02e47ac29 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Mon, 31 Oct 2022 12:50:04 +0100 Subject: [PATCH 53/57] improved tests --- .../postgres/PGInterfaceIntegrationTests.java | 100 +++++++++++++++--- .../db/postgresql/PGInterfaceMessage.java | 5 - .../PGInterfacePreparedMessage.java | 2 +- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index 8db22d8adc..c4c8450d7a 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -20,8 +20,13 @@ import lombok.extern.slf4j.Slf4j; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.polypheny.db.TestHelper; +import org.polypheny.db.catalog.Catalog; +import org.polypheny.db.catalog.entity.CatalogTable; +import org.polypheny.db.catalog.exceptions.UnknownSchemaException; +import org.polypheny.db.catalog.exceptions.UnknownTableException; import java.sql.*; import java.util.ArrayList; @@ -39,8 +44,6 @@ public class PGInterfaceIntegrationTests { //insert: INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3); //create table: CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest)) - //new Object[]{"REAL'S HOWTO"}; - @BeforeClass @@ -66,21 +69,40 @@ public static void stop() throws SQLException { try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { Connection connection = psqlJdbcConnection.getConnection(); try(Statement statement = connection.createStatement()) { - statement.executeUpdate("DROP TABLE public.pginterfacetesttable"); + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); //statement.executeUpdate( "ALTER INTERFACES DROP pgtestinerface" ); } } } + @Test + public void testIfDDLIsExecuted() throws SQLException { + + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + Connection connection = psqlJdbcConnection.getConnection(); + try(Statement statement = connection.createStatement()) { + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); + CatalogTable catalogTable = Catalog.getInstance().getTable(Catalog.getInstance().getSchema(Catalog.defaultDatabaseId, "public").id , "PGInterfaceTestTable"); + assertEquals(catalogTable.name, "pginterfacetesttable"); + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + } catch (UnknownTableException e) { + e.printStackTrace(); + } catch (UnknownSchemaException e) { + e.printStackTrace(); + } + } + } @Test - public void testIfDMLIsExecuted() throws SQLException { + public void testIfDMLandDDLandDQLIsExecuted() throws SQLException { try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { Connection connection = psqlJdbcConnection.getConnection(); try(Statement statement = connection.createStatement()) { + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); statement.executeUpdate("INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);"); ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); @@ -92,27 +114,75 @@ public void testIfDMLIsExecuted() throws SQLException { new Object[]{2, "Hello", 2}, new Object[]{3, "By", 3}) ); + + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); } } } + @Test + @Ignore + public void testIfPreparedAndExecuteInOneWithTextIsExecuted() throws SQLException { -/* + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + Connection connection = psqlJdbcConnection.getConnection(); + try(Statement statement = connection.createStatement()) { + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - @Test - public void testIfDDLIsExecuted() throws SQLException { + //ResultSet rss = statement.executeQuery("PREPARE lol (int) AS SELECT empid FROM public.emps WHERE empid = $1; EXECUTE lol (100);"); + statement.executeUpdate("PREPARE testPrepare (int, text, int) AS INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES ($1, $2, $3);"); + ResultSet rs = statement.executeQuery("EXECUTE testPrepare (1, 'Franz', 1);"); - try(Statement statement = connection.createStatement()) { - statement.executeUpdate("CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - CatalogTable catalogTable = Catalog.getInstance().getTable(Catalog.getInstance().getSchema(Catalog.defaultDatabaseId, "public").id , "PGInterfaceTestTable"); - assertEquals(catalogTable.name, "pginterfacetesttable"); - } catch (UnknownTableException e) { - e.printStackTrace(); - } catch (UnknownSchemaException e) { - e.printStackTrace(); + TestHelper.checkResultSet( + rs, + ImmutableList.of( + new Object[]{1, "Franz", 1}) + ); + + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + } } } + @Test + @Ignore + public void testIfPreparedAndExecuteInOneNoTextIsExecuted() throws SQLException { + + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + Connection connection = psqlJdbcConnection.getConnection(); + try(Statement statement = connection.createStatement()) { + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL,PRIMARY KEY (PkIdTest))"); + + //public void addParameterValues( long index, AlgDataType type, List data ) { + // if ( parameterTypes.containsKey( index ) ) { + // throw new RuntimeException( "There are already values assigned to this index" ); + // } + //ResultSet rss = statement.executeQuery("PREPARE lol (int) AS SELECT empid FROM public.emps WHERE empid = $1; EXECUTE lol (100);"); + statement.executeUpdate("PREPARE testPrepare2 (int, int) AS INSERT INTO pginterfacetesttable(PkIdTest, IntTest) VALUES ($1);"); + ResultSet rs = statement.executeQuery("EXECUTE testPrepare2 (1);"); + + TestHelper.checkResultSet( + rs, + ImmutableList.of( + new Object[]{1}) + ); + + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + } + } + } + + + + + +/* +prepared: +//PreparedStatement pst = c.prepareStatement("SELECT empid FROM public.emps WHERE empid = ?;"); + //pst.setInt(1, 100); + //pst.execute(); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 8c75ee9c25..ecc83bf7ef 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -106,11 +106,6 @@ public void setLength( int length ) { } - public void setDefaultLength( boolean val ) { - this.defaultLength = val; - } - - public boolean isDefaultLength() { return this.defaultLength; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index d9a4d54eef..5aa4a882f8 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -80,7 +80,7 @@ public void extractAndSetValues() { //cut string at ( and ) (remove chlammere) --> denn mach eif. split, ond problem solved... String onlyExecuteValues = executeString.split("\\(|\\)")[1]; List valueList = Arrays.asList(onlyExecuteValues.split(getExecuteDelimiter())); - setData(valueList); //FIXME(FF): setData, ned setDataTypes + setData(valueList); } public void extractAndSetTypes() { From 126fbdcf1d7a9d5def9ccf5929084617c8b8a305 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Tue, 1 Nov 2022 11:16:44 +0100 Subject: [PATCH 54/57] updated tests for prepare statements, and prepare statements now handle several values --- .../postgres/PGInterfaceIntegrationTests.java | 66 +++++++------------ .../PGInterfacePreparedMessage.java | 18 +++-- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index c4c8450d7a..b4ae679eed 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -121,8 +121,7 @@ public void testIfDMLandDDLandDQLIsExecuted() throws SQLException { } @Test - @Ignore - public void testIfPreparedAndExecuteInOneWithTextIsExecuted() throws SQLException { + public void testPreparedAndExecuteInTwoParts() throws SQLException { try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { Connection connection = psqlJdbcConnection.getConnection(); @@ -132,7 +131,8 @@ public void testIfPreparedAndExecuteInOneWithTextIsExecuted() throws SQLExceptio //ResultSet rss = statement.executeQuery("PREPARE lol (int) AS SELECT empid FROM public.emps WHERE empid = $1; EXECUTE lol (100);"); statement.executeUpdate("PREPARE testPrepare (int, text, int) AS INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES ($1, $2, $3);"); - ResultSet rs = statement.executeQuery("EXECUTE testPrepare (1, 'Franz', 1);"); + statement.executeUpdate("EXECUTE testPrepare (1, 'Franz', 1);"); + ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); TestHelper.checkResultSet( rs, @@ -145,28 +145,24 @@ public void testIfPreparedAndExecuteInOneWithTextIsExecuted() throws SQLExceptio } } + @Test - @Ignore - public void testIfPreparedAndExecuteInOneNoTextIsExecuted() throws SQLException { + public void testPreparedAndExecuteInOnePart() throws SQLException { try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { Connection connection = psqlJdbcConnection.getConnection(); try(Statement statement = connection.createStatement()) { statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); - statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL,PRIMARY KEY (PkIdTest))"); + statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - //public void addParameterValues( long index, AlgDataType type, List data ) { - // if ( parameterTypes.containsKey( index ) ) { - // throw new RuntimeException( "There are already values assigned to this index" ); - // } //ResultSet rss = statement.executeQuery("PREPARE lol (int) AS SELECT empid FROM public.emps WHERE empid = $1; EXECUTE lol (100);"); - statement.executeUpdate("PREPARE testPrepare2 (int, int) AS INSERT INTO pginterfacetesttable(PkIdTest, IntTest) VALUES ($1);"); - ResultSet rs = statement.executeQuery("EXECUTE testPrepare2 (1);"); + statement.executeUpdate("PREPARE testPrepare (int, text, int) AS INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES ($1, $2, $3); EXECUTE testPrepare (1, 'Franz', 1);"); + ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); TestHelper.checkResultSet( rs, ImmutableList.of( - new Object[]{1}) + new Object[]{1, "Franz", 1}) ); statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); @@ -174,45 +170,33 @@ public void testIfPreparedAndExecuteInOneNoTextIsExecuted() throws SQLException } } - - - - -/* -prepared: -//PreparedStatement pst = c.prepareStatement("SELECT empid FROM public.emps WHERE empid = ?;"); - //pst.setInt(1, 100); - //pst.execute(); - - - @Test - public void testIfDMLIsExecuted() throws SQLException { + @Ignore + public void testPreparedUsingJdbc() throws SQLException { + //TODO(FF): Prepared Statements using JDBC not yet supported from PGInterface --> read inserted values from bind command (which is not done currently) - try(Statement statement = c.createStatement()) { - int status = statement.executeUpdate("INSERT INTO public.PGInterfaceTestTable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);"); - assertEquals(0, status); - } + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + Connection connection = psqlJdbcConnection.getConnection(); + try(Statement statement = connection.createStatement()) { + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - } + PreparedStatement pst = connection.prepareStatement("INSERT INTO pginterfacetesttable(PkIdTest, IntTest) VALUES (?, ?)"); + pst.setInt(1, 100); + pst.execute(); + ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); - @Test - public void testIfDQLIsExecuted() throws SQLException { - try (Connection c = DriverManager.getConnection(url, connectionProps)) { - try (Statement statement = c.createStatement()) { TestHelper.checkResultSet( - statement.executeQuery("SELECT * FROM PGInterfaceTestTable;"), + rs, ImmutableList.of( - new Object[]{1, "Franz", 1}, - new Object[]{2, "Hello", 2}, - new Object[]{3, "By", 3})); + new Object[]{1, 100}) + ); + statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); } } } - */ - public static class PsqlJdbcConnection implements AutoCloseable { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index 5aa4a882f8..702b770c6a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -129,11 +129,14 @@ public void transformDataAndAddParameterValues (Statement statement) { long idx = 0; for (String type : dataTypes) { List o = new ArrayList<>(); - for (String value : data) { - o.add(transformData(value, type)); - } + String value = data.get((int) idx); + o.add(transformData(value, type)); + //for (String value : data) { + // o.add(transformData(value, type)); //goht dor alli values e data dore, ond phaltet aber de gliichi typ bii vom 1. mol... + //} AlgDataType algDataType = transformToAlgDataType(type, statement); statement.getDataContext().addParameterValues(idx, algDataType, o); + idx ++; } } @@ -145,7 +148,14 @@ private Object transformData(String value, String type) { o = Integer.valueOf(value); break; case "text": - o = value; + String pureValue = value; + if (value.charAt(0) == '\'') { + pureValue = value.substring(1); + if(value.charAt(value.length()-1) == '\'') { + pureValue = pureValue.substring(0, pureValue.length() - 1); + } + } + o = pureValue; break; case "bool": o = Boolean.parseBoolean(value); From fdba699f46c33f8387e5f492bdeff65468f1e67c Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Tue, 1 Nov 2022 15:06:40 +0100 Subject: [PATCH 55/57] updated and added javadoc --- .../postgres/PGInterfaceIntegrationTests.java | 35 +- .../polypheny/db/postgresql/PGInterface.java | 6 + .../postgresql/PGInterfaceErrorHandler.java | 44 +-- .../db/postgresql/PGInterfaceHeaders.java | 5 + ...GInterfaceInboundCommunicationHandler.java | 96 +++-- .../db/postgresql/PGInterfaceMessage.java | 43 ++- .../PGInterfacePreparedMessage.java | 119 ++++++- .../postgresql/PGInterfaceQueryHandler.java | 333 ++---------------- .../postgresql/PGInterfaceServerHandler.java | 33 +- .../postgresql/PGInterfaceServerWriter.java | 30 +- 10 files changed, 363 insertions(+), 381 deletions(-) diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index b4ae679eed..17ef14c200 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -37,6 +37,9 @@ //import static org.polypheny.db.postgresql.PGInterfaceInboundCommunicationHandler.ctx; +/** + * Tests the implementation of the PGInterface --> simulates a client that connects via JDBC + */ @Slf4j public class PGInterfaceIntegrationTests { @@ -46,6 +49,10 @@ public class PGInterfaceIntegrationTests { //create table: CREATE TABLE public.PGInterfaceTestTable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest)) + /** + * starts an instance of Polypheny and creates a PGInterface, as it does not exist per default + * @throws SQLException + */ @BeforeClass public static void start() throws SQLException { // Ensures that Polypheny-DB is running @@ -60,9 +67,12 @@ public static void start() throws SQLException { } } - //ALTER INTERFACES ADD "sdf" USING 'org.polypheny.db.postgresql.PGInterface' WITH '{"port":"5433"}' } + /** + * Cleans up after the tests + * @throws SQLException + */ @AfterClass public static void stop() throws SQLException { @@ -76,6 +86,10 @@ public static void stop() throws SQLException { } + /** + * Test that executes the ddl command CREATE and checks within the database if a table was created + * @throws SQLException + */ @Test public void testIfDDLIsExecuted() throws SQLException { @@ -96,6 +110,10 @@ public void testIfDDLIsExecuted() throws SQLException { } + /** + * This test executes several SQL-commands via the client, it creates a table, inserts and selects from it. The returned values from the select are tested + * @throws SQLException + */ @Test public void testIfDMLandDDLandDQLIsExecuted() throws SQLException { @@ -120,6 +138,10 @@ public void testIfDMLandDDLandDQLIsExecuted() throws SQLException { } } + /** + * Tests if a prepared statement is correctly executed if the PREPARE and EXECUTE statement are sent seperately + * @throws SQLException + */ @Test public void testPreparedAndExecuteInTwoParts() throws SQLException { @@ -146,6 +168,10 @@ public void testPreparedAndExecuteInTwoParts() throws SQLException { } + /** + * Tests if a prepared statement is correctly executed if the PREPARE and EXECUTE statement are sent together + * @throws SQLException + */ @Test public void testPreparedAndExecuteInOnePart() throws SQLException { @@ -170,6 +196,10 @@ public void testPreparedAndExecuteInOnePart() throws SQLException { } } + /** + * This feature is not yet supported, but it tests if prepared statement are executed correctly using the JDBC framework + * @throws SQLException + */ @Test @Ignore public void testPreparedUsingJdbc() throws SQLException { @@ -198,6 +228,9 @@ public void testPreparedUsingJdbc() throws SQLException { } + /** + * Creates a connection via Postgres-JDBC, autocommit is always enabled, and sslmode disabled + */ public static class PsqlJdbcConnection implements AutoCloseable { private final static String dbHost = "localhost"; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 356196ff05..93f8558aaa 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -48,6 +48,9 @@ import org.polypheny.db.util.Util; +/** + * First point of contact for the PGInterface, setting changes from the UI are handled here + */ @Slf4j public class PGInterface extends QueryInterface { @@ -93,6 +96,9 @@ public PGInterface( TransactionManager transactionManager, Authenticator authent } + /** + * Creates a netty server and its channelPipeline + */ @Override public void run() { diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java index be6117065b..4de1cdf388 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -22,6 +22,9 @@ import java.util.LinkedHashMap; +/** + * Writes and sends error messages to the client + */ @Slf4j public class PGInterfaceErrorHandler { @@ -32,23 +35,36 @@ public class PGInterfaceErrorHandler { private PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler; + /** + * Creates a error handler that can send error messages to the client + * @param ctx Is needed to send the error message to the designated client + * @param pgInterfaceInboundCommunicationHandler Is needed to create PGInterfaceServerWriter to be able to send a error message + */ public PGInterfaceErrorHandler(ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler) { this.ctx = ctx; + this.pgInterfaceInboundCommunicationHandler = pgInterfaceInboundCommunicationHandler; } + /** + * Sends a simple error message to the client. The severity and other error fields are all fixed. + * @param errorMsg The message you want to send + */ public void sendSimpleErrorMessage (String errorMsg) { - //E...n S ERROR. V ERROR. C 42P01. M relation "public.hihi" does not exist. P 15. F parse_relation. c. L 1360. R parserOpenTable. . Z....I - //E...x S ERROR. V ERROR. C 42P01. M relation "public.hihi" does not exist. P 15. F parse_relation. c. L 1360. R parserOpenTable. . Z....I - //header, length, severity, severity (gl wie vorher), SQLSTATE code, Message, (Position, File, column name?, Line, Routine, zerobyte as field) freiwillig - //42P01 - undefined_table$ - //0A000 - feature_not_supported + //Notes on how error messages are sent: + /* + E...n S ERROR. V ERROR. C 42P01. M relation "public.hihi" does not exist. P 15. F parse_relation. c. L 1360. R parserOpenTable. . Z....I + E...x S ERROR. V ERROR. C 42P01. M relation "public.hihi" does not exist. P 15. F parse_relation. c. L 1360. R parserOpenTable. . Z....I + header, length, severity, severity (gl wie vorher), SQLSTATE code, Message, (Position, File, column name?, Line, Routine, zerobyte as field) freiwillig + 42P01 - undefined_table$ + 0A000 - feature_not_supported + E..._SERROR.VERROR.C42601.Msyntax error at or near "SSELECT".P1.Fscan.l.L1176.Rscanner_yyerror..Z....I + */ - //E..._SERROR.VERROR.C42601.Msyntax error at or near "SSELECT".P1.Fscan.l.L1176.Rscanner_yyerror..Z....I this.errorMsg = errorMsg; PGInterfaceMessage pgInterfaceMessage = new PGInterfaceMessage(PGInterfaceHeaders.E, "MockBody", 4, true); - this.serverWriter = serverWriter = new PGInterfaceServerWriter("MockType", pgInterfaceMessage, ctx, pgInterfaceInboundCommunicationHandler); + this.serverWriter = new PGInterfaceServerWriter("MockType", pgInterfaceMessage, ctx, pgInterfaceInboundCommunicationHandler); - //FIXME(FF): An error occurs because of the errormessage on the clientside. But it doesn't really matter, because the connection would be terminated anyway and the individual message part arrives... + //TODO(FF): An error occurs because of the errormessage on the clientside. It doesn't really matter, because the connection would be terminated anyway and the message itself arrives... LinkedHashMap errorFields = new LinkedHashMap(); errorFields.put('S', "ERROR"); errorFields.put('V', "ERROR"); @@ -64,17 +80,5 @@ public void sendSimpleErrorMessage (String errorMsg) { ByteBuf buffer = serverWriter.writeSimpleErrorMessage(errorFields); ctx.writeAndFlush(buffer); - //pgInterfaceInboundCommunicationHandler.sendReadyForQuery("I"); - } - - - /* - this.exception = e; - if ( e.getMessage() != null ) { - this.errorMsg = e.getMessage(); - } else { - this.errorMsg = e.getClass().getSimpleName(); - } - */ } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java index e063196054..967a6d1390 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java @@ -102,6 +102,11 @@ public enum PGInterfaceHeaders { //E - also used from server to client, described there //some messages with no header (StartUpMessage, CancelREquest, and some authentication requests) + /** + * Parse - contains query in the extended query cycle + */ + P, + /** * Simple Query - from client to server - used in simple query cycle */ diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 363595f82d..03a871f867 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -25,7 +25,7 @@ import org.polypheny.db.transaction.TransactionManager; /** - * Manages all incoming communication, not using the netty framework (but being a handler in netty) + * Manages all incoming communication, not a handler from netty, but called by one */ @Slf4j public class PGInterfaceInboundCommunicationHandler { @@ -45,17 +45,14 @@ public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContex /** - * Decides in what cycle from postgres the client is (startup-phase, query-phase, etc.) - * - * @param oMsg the incoming message from the client (unchanged) - * @param pgInterfaceServerHandler - * @return + * Decides in what cycle (from postgres message flow) the client is: startup-phase, query-phase, etc. + * @param oMsg the incoming message from the client (unchanged) - whole message is interpreted as a string from the netty decoder + * @param pgInterfaceServerHandler is needed to access the saved prepared statements for a connection */ public void decideCycle(Object oMsg, PGInterfaceServerHandler pgInterfaceServerHandler) { String msgWithZeroBits = ((String) oMsg); String wholeMsg = msgWithZeroBits.replace( "\u0000", "" ); - //TODO(FF): simple query phase is not implemented if ( wholeMsg.substring( 2, 6 ).contains("user") ) { startUpPhase(); @@ -66,17 +63,21 @@ else if ( wholeMsg.substring( 0, 1 ).equals("P") ) { } else if ( wholeMsg.substring( 0, 1 ).equals("X") ) { + //TODO(FF): (low prio, bcs everything works as inteded, but) seems to never be reached, instead in PGInterfaceServerHandler the exception is reached... maybe client closes connection and netty realizes this and stops handler terminateConnection(); } + else if ( wholeMsg.substring( 0, 1 ).equals("Q")) { + simpleQueryPhase(); + } else { - errorHandler.sendSimpleErrorMessage("The message could not be parsed by the PGInterface."); + errorHandler.sendSimpleErrorMessage("The incoming message could not be parsed by the PGInterface."); } } /** * Performs necessary steps on the first connection with the client (mostly sends necessary replies, but doesn't really set anything on the server side). - * Sends authenticationOk (without checking authentication), sets server version, sends readyForQuery + * Sends authenticationOk (without checking authentication), sets server version 14 (required from jdbc), sends readyForQuery */ public void startUpPhase() { //authenticationOk @@ -94,25 +95,34 @@ public void startUpPhase() { } + /** + * Handles the steps if we are in the simple query phase. + */ public void simpleQueryPhase() { //TODO(FF): (low priority) The simple query phase is handled a bit differently than the extended query phase. The most important difference is that the simple query phase accepts several queries at once and sends some different response messages (e.g. no parse/bindComplete). //Several queries seperated with ";" + + errorHandler.sendSimpleErrorMessage("The simple query phase is not implemented in the PostgreSQL Interface"); + } /** + * Handles the steps if we are in the extended query phase. * Sends necessary responses to client (without really setting anything in backend) and prepares the incoming query for usage. Continues query forward to QueryHandler * @param incomingMsg unchanged incoming message (transformed to string by netty) - * @param pgInterfaceServerHandler + * @param pgInterfaceServerHandler is needed to access the saved prepared statements for a connection */ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgInterfaceServerHandler) { if ( incomingMsg.substring( 2, 5 ).equals( "SET" ) ) { + //TODO(FF): actually handle the SET commands (e.g. SET extra_float_digits = 3) sendParseBindComplete(); sendCommandComplete("SET", -1); sendReadyForQuery( "I" ); } else if (incomingMsg.substring(2, 9).equals("PREPARE")) { + //TODO(FF): Hanlde prepared statements sent via JDBC framework - they don't contain the PREPARE and EXECUTE commands (don't necessarily handle it here) ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); //Prepared Statement @@ -121,22 +131,22 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn String executeString = query[1]; String prepareStringQueryName = extractPreparedQueryName(prepareString); - //check if name already exists --> muesi das öberhaupt?? chamer ned eif es existierends öberschriibe? + //check if name already exists if (preparedStatementNames.isEmpty() || (!preparedStatementNames.contains(prepareStringQueryName))) { PGInterfacePreparedMessage preparedMessage = new PGInterfacePreparedMessage(prepareStringQueryName, prepareString, ctx); preparedMessage.prepareQuery(); - //preparedStatementNames.add(prepareStringQueryName); //proforma, aber wenni alles rechtig ersetzst sötti das eig chönne uselösche... + + //safe prepared messages for the connection pgInterfaceServerHandler.addPreparedStatementNames(prepareStringQueryName); - //ctx.channel().attr(attrObj).set(prepareStringQueryName); - //preparedMessages.add(preparedMessage); pgInterfaceServerHandler.addPreparedMessage(preparedMessage); - //safe everything possible and necessary - //send: 1....2....n....C....PREPARE + + //send response to "prepare" query sendParseBindComplete(); sendNoData(); sendCommandComplete( "PREPARE", -1 ); - if (!executeString.isEmpty()) { //an execute statement was sent along + //check if an execute statement was sent along + if (!executeString.isEmpty()) { String statementName = extractPreparedQueryName(executeString); //check if name exists already @@ -145,7 +155,6 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn } else { String errorMsg = "There does not exist a prepared statement called" + statementName; errorHandler.sendSimpleErrorMessage(errorMsg); - //TODO(FF): stop sending stuff to client... } } else { @@ -154,10 +163,8 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn } else { String errorMsg = "There already exists a prepared statement with the name" + prepareStringQueryName + "which has not yet been executed"; errorHandler.sendSimpleErrorMessage(errorMsg); - //TODO(FF): stop sending stuff to client... } - //List lol = preparedMessage.extractValues(); } else if (incomingMsg.substring(2, 9).equals("EXECUTE")) { ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); @@ -171,9 +178,7 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn executePreparedStatement(executeQuery, statementName, pgInterfaceServerHandler); } else { String errorMsg = "There does not exist a prepared statement called" + statementName; - //terminateConnection(); errorHandler.sendSimpleErrorMessage(errorMsg); - //TODO(FF): stop sending stuff to client... } } @@ -185,18 +190,23 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn } } + /** + * Starts a query handler with the information that the query right now is a prepared query + * @param executeString The string which contains the execute query + * @param statementName The name of the prepared statement + * @param pgInterfaceServerHandler is needed to access the saved prepared statements for a connection + */ private void executePreparedStatement(String executeString, String statementName, PGInterfaceServerHandler pgInterfaceServerHandler) { ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); + // get corresponding prepared message int idx = preparedStatementNames.indexOf(statementName); - //PGInterfacePreparedMessage preparedMessage = preparedMessages.get(idx); PGInterfacePreparedMessage preparedMessage = pgInterfaceServerHandler.getPreparedMessage(idx); preparedMessage.setExecuteString(executeString); preparedMessage.extractAndSetValues(); PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler( preparedMessage, ctx, this, transactionManager ); queryHandler.start(); - //send commandComplete according to query type... (oder em query handler... wo au emmer dases gscheckt werd...) ond parse bind ond ready for query... } @@ -225,13 +235,18 @@ public String extractQuery( String incomingMsg ) { query = query.substring( 0, idx - 2 ); } else { errorHandler.sendSimpleErrorMessage("Something went wrong while extracting the query from the incoming stream"); - //TODO(FF): stop sending stuff to client... + //TODO(FF): does it continue to send stuff to the client? (even though he doesn't receives it anymore?) } return query; } + /** + * extracts the prepared query from the incoming string (cuts all other information/buffer things) + * @param incomingMsg the message from the client + * @return a list of 2 strings. the first element is the prepared query, the second element is empty (if not sent along) or contains the execute query + */ private String[] extractPreparedQuery(String incomingMsg) { String prepareString = extractQuery(incomingMsg); String executeString = new String(); @@ -245,6 +260,11 @@ private String[] extractPreparedQuery(String incomingMsg) { return result; } + /** + * Extracts the execute query if it was sent along with the prepare query + * @param incomingMsg the incoming message from the client + * @return returns the execute query + */ private String extractExecutePart(String incomingMsg) { int idx = incomingMsg.indexOf("EXECUTE"); @@ -255,6 +275,11 @@ private String extractExecutePart(String incomingMsg) { return executeString; } + /** + * Extracts the name of the prepared query (also of the execute query) + * @param cleanedQuery the prepared/execute query without remains from the buffer (zeros in between etc) + * @return the name of the prepare statement as a string + */ private String extractPreparedQueryName(String cleanedQuery) { String startNamePlusQuery = cleanedQuery.substring(8); @@ -264,13 +289,11 @@ private String extractPreparedQueryName(String cleanedQuery) { } - - /** * Creates and sends (flushes on ctx) a readyForQuery message with a tag. The tag is choosable (see below for options). * * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), - * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended + * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended) */ public void sendReadyForQuery(String msgBody) { PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); @@ -279,7 +302,9 @@ public void sendReadyForQuery(String msgBody) { } - + /** + * creates and sends a parseComplete and a bindComplete message to the client. + */ public void sendParseBindComplete() { //TODO(FF): This should work with the normal PGInterfaceServerWriter type "i" (called like in the commented out part), // but it does not --> roundabout solution that works, but try to figure out what went wrong... @@ -306,7 +331,9 @@ public void sendParseBindComplete() { } - + /** + * creates and sends the noData message to the client + */ public void sendNoData() { PGInterfaceMessage noData = new PGInterfaceMessage( PGInterfaceHeaders.n, "0", 4, true ); PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx, this); @@ -317,7 +344,7 @@ public void sendNoData() { /** * Sends CommandComplete to client, with choosable command type * @param command which command is completed (no space afterwards, space is added here) - * @param rowsAffected number of rows affected (if it is not necessary to send a number, put -1) + * @param rowsAffected number of rows affected (if it is not necessary to send a number, put -1, (0 is also possible)) */ public void sendCommandComplete( String command, int rowsAffected ) { String body = ""; @@ -333,9 +360,6 @@ public void sendCommandComplete( String command, int rowsAffected ) { commandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); commandCompleteWriter = new PGInterfaceServerWriter( "s", commandComplete, ctx, this); - //int hash = ctx.hashCode(); - //String lol = command + " | " + String.valueOf(hash); - //log.error(lol); ctx.writeAndFlush( commandCompleteWriter.writeOnByteBuf() ); } @@ -390,6 +414,10 @@ public void sendDataRow( ArrayList data ) { } } + + /** + * Closes the ctx, so nothing more can be sent to the client + */ public void terminateConnection() { ctx.close(); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index ecc83bf7ef..48882a43ca 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -18,7 +18,10 @@ import lombok.extern.slf4j.Slf4j; -//message sent by client and server (connection-level) + +/** + * Contains information for what will be sent to the client, and also methods to handle the information + */ @Slf4j public class PGInterfaceMessage { @@ -45,11 +48,19 @@ public PGInterfaceMessage( PGInterfaceHeaders header, String msgBody, int length } + /** + * get the header of the message + * @return PGInterfaceHeader of the message + */ public PGInterfaceHeaders getHeader() { return this.header; } + /** + * returns the PGInterfaceHeader of the Message as a char + * @return PGInterfaceHeader as a char + */ public char getHeaderChar() { //if header is a single character @@ -69,13 +80,17 @@ public char getHeaderChar() { return '3'; } } - //TODO(FF): stop sending data to client + //TODO(FF): does it continue to send things to the client after the error message? errorHandler.sendSimpleErrorMessage("PGInterface>PGInterfaceMessage>getHeaderChar: This should never be reached."); return 0; } + /** + * Changes the three headers that are a number and not a letter into a number (they are safed as a string in the PGInterfaceHeaders) + * @return 1,2 or 3 - headers which are numbers + */ public int getHeaderInt() { String headerString = header.toString(); if ( headerString.equals( "ONE" ) ) { @@ -85,7 +100,7 @@ public int getHeaderInt() { } else if ( headerString.equals( "THREE" ) ) { return 3; } - //TODO(FF): stop sending data to client + //TODO(FF): does it continue to send things to the client after the error message? errorHandler.sendSimpleErrorMessage("PGInterface>PGInterfaceMessage>getHeaderInt: This should never be reached."); return 0; } @@ -96,33 +111,53 @@ public void setHeader( PGInterfaceHeaders header ) { } + /** + * the length that should be set in the message to the client (default is 4) + * @return length of the message + */ public int getLength() { return this.length; } + /** + * set the length of the message to the client (the default is set to 4) + * @param length length you want to set as the message length + */ public void setLength( int length ) { this.length = length; } + /** + * if the message has the default length (4) + * @return whether the message has the default length + */ public boolean isDefaultLength() { return this.defaultLength; } + /** + * The content of the message that will be sent to the client, can contain several "sub" messages (message fields) which are seperated by the delimiter + * @return message to the client + */ public String getMsgBody() { return msgBody; } + /** + * Set the content of the message that will be sent to the client, can contain several "sub" messages (message fields) which are seperated by the delimiter + * @param msgBody message to the client + */ public void setMsgBody( String msgBody ) { this.msgBody = msgBody; } /** - * Gets the different sub-parts of a message + * Gets the different sub-parts of a message, which are seperated by the delimiter * * @param part the index of the requested part(s), starting at 0 * @return a string array with each requested part diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index 702b770c6a..b561e49fed 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -25,6 +25,9 @@ import java.util.*; +/** + * Contains information for prepared queries, and also methods to handle the information + */ @Slf4j public class PGInterfacePreparedMessage { private String name; @@ -37,43 +40,90 @@ public class PGInterfacePreparedMessage { private static final String executeDelimiter = ", "; private Map typesPolyphey = new HashMap(); private List> valuesPolypeny = new ArrayList>(); + private PGInterfaceErrorHandler errorHandler; + /** + * Creates the message itself + * @param name name of the prepared statement + * @param wholePrepareString the string which contains the prepared statement + * @param ctx channelHandlerContext from the current connection + */ public PGInterfacePreparedMessage(String name, String wholePrepareString, ChannelHandlerContext ctx) { this.name = name; this.wholePrepareString = wholePrepareString; this.ctx = ctx; } + /** + * Creates the message itself + * @param name name of the prepared statement + * @param ctx channelHandlerContext from the current connection + */ public PGInterfacePreparedMessage(String name, ChannelHandlerContext ctx) { this.name = name; this.ctx = ctx; } + /** + * Sets the query itself (without prepare etc) + * @param query The "pure" query + */ public void setQuery(String query) { this.query = query; } + /** + * the "whole" execute query + * @param executeString execute query + */ public void setExecuteString(String executeString) { this.executeString = executeString; } + /** + * the "whole" prepare query + * @param wholePrepareString prepare query + */ public void setWholePrepareString(String wholePrepareString) { this.wholePrepareString = wholePrepareString; } + /** + * the data types from the prepare query + * @param dataTypes a list if all types (in the right order) from the prepare query + */ private void setDataTypes(List dataTypes) { this.dataTypes = dataTypes; } + /** + * The values that will be inserted into the prepare query + * @param data the values that will be inserted into the prepare query as string (since they arrive as string from the connection) + */ private void setData(List data) { this.data = data; } + /** + * The delimiter that seperates the values in the execute query + * @return a string sequence which is the delimiter in the execute query + */ public static String getExecuteDelimiter() {return executeDelimiter;} + /** + * The "pure" query (without prepare etc.) + * @return the query itself (without prepare etc.) + */ public String getQuery() { return query;} public List getDataTypes() { return dataTypes;} + /** + * Gets the values from the execute query + * @return values from the execute query as string + */ public List getData() { return data;} + /** + * From the execute string it extracts the values that will be inserted into the prepare query, sets these values in the message + */ public void extractAndSetValues() { //us execute string - seperator: ', ' //bool ersetze... @@ -83,6 +133,9 @@ public void extractAndSetValues() { setData(valueList); } + /** + * From the prepare string it extracts the data types for the values to be inserted, sets these in the message + */ public void extractAndSetTypes() { String types = wholePrepareString.split("\\(|\\)")[1]; List typeList = Arrays.asList(types.split(getExecuteDelimiter())); @@ -100,6 +153,9 @@ public void extractAndSetTypes() { setDataTypes(typeList); } + /** + * in the prepared query it changes the parameter symbol from $ (from postgres) to ? (for polypheny), sets it in this message + */ public void changeParameterSymbol() { String[] parts = wholePrepareString.split("\\$"); @@ -113,37 +169,79 @@ public void changeParameterSymbol() { } + /** + * extracts the "pure" query from the prepared string (so the query itself without anything else), sets it in this message + */ public void extractAndSetQuery() { String query = wholePrepareString.split("AS ")[1]; setQuery(query); } + /** + * executes steps to prepare a query to be processed by polypheny + * steps include: extract the types from the prepared query, changes the parameter symbol from $ to ?, extracts the query itself + */ public void prepareQuery() { - extractAndSetTypes(); changeParameterSymbol(); extractAndSetTypes(); extractAndSetQuery(); } + /** + * Sets the parameter values (the datatype and the value) to the data context, so polypheny can process the prepared query + * @param statement the statement that was created from the query + */ public void transformDataAndAddParameterValues (Statement statement) { long idx = 0; + //TODO(FF): It doesn't work yet to insert several values (query below) --> tried 2 variants below, but both give same error (see bolow below) + // (PREPARE lol (int, text, int) AS INSERT INTO pginterfacetesttable VALUES ($1, $2, $3), ($4, $5, $6); EXECUTE lol (4, 'HALLO', 4, 5, 'x', 5); + //java.lang.RuntimeException: While executing SQL [INSERT INTO "PUBLIC"."tab5_part1004" ("_EXPR$0", "_EXPR$1", "_EXPR$2") + //SELECT CAST(? AS INTEGER), CAST(? AS VARCHAR(255)), CAST(? AS INTEGER) + //FROM (VALUES (0)) AS "t" ("ZERO") + //UNION ALL + //SELECT CAST(? AS INTEGER), CAST(? AS VARCHAR(255)), CAST(? AS INTEGER) + //FROM (VALUES (0)) AS "t" ("ZERO")] on JDBC sub-schema + + //if o is as long as the number of data types for (String type : dataTypes) { + List o = new ArrayList<>(); + for (int i = 0; i o = new ArrayList<>(); String value = data.get((int) idx); + String type = dataTypes.get(i%dataTypes.size()); o.add(transformData(value, type)); - //for (String value : data) { - // o.add(transformData(value, type)); //goht dor alli values e data dore, ond phaltet aber de gliichi typ bii vom 1. mol... - //} AlgDataType algDataType = transformToAlgDataType(type, statement); statement.getDataContext().addParameterValues(idx, algDataType, o); idx ++; } + */ + } + /** + * Transforms the data from a string into the correct format + * @param value the value that needs to be transformed + * @param type the type the value needs to be transformed into + * @return returns the transformed value as an object + */ private Object transformData(String value, String type) { Object o = new Object(); switch (type) { + //TODO(FF): implement more data types case "int": o = Integer.valueOf(value); break; @@ -163,13 +261,23 @@ private Object transformData(String value, String type) { case "numeric": o = Double.parseDouble(value); break; + default: + errorHandler.sendSimpleErrorMessage("data type from from the prepared query is not yet supported by the postgres interface (transform data)"); + break; } return o; } + /** + * creates a AlgDataType according to the corresponding data type + * @param type the type you want a AlgDataType for (types are the pgTypes) + * @param statement needed to create the AlgDataType + * @return returns the corresponding AlgDataType to the input type + */ private AlgDataType transformToAlgDataType(String type, Statement statement) { AlgDataType result = null; switch (type) { + //TODO(FF): implement more data types case "int": result = statement.getTransaction().getTypeFactory().createPolyType(PolyType.INTEGER); break; @@ -182,6 +290,9 @@ private AlgDataType transformToAlgDataType(String type, Statement statement) { case "numeric": result = statement.getTransaction().getTypeFactory().createPolyType(PolyType.DECIMAL, 3, 3); break; + default: + errorHandler.sendSimpleErrorMessage("data type from from the prepared query is not yet supported by the postgres interface (create AlgDataType)"); + break; } return result; diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index b3b9807f56..a94eeaeaf9 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -44,9 +44,11 @@ import org.polypheny.db.transaction.Transaction; import org.polypheny.db.transaction.TransactionException; import org.polypheny.db.transaction.TransactionManager; -import org.polypheny.db.type.PolyType; +/** + * Handles all queries from the extended query cycle - "sends" them to polypheny and processes answer + */ @Slf4j public class PGInterfaceQueryHandler { @@ -78,111 +80,17 @@ public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, Chan this.errorHandler = new PGInterfaceErrorHandler(ctx, communicationHandler); } + /** + * Depending on how the PGInterfaceQueryHandler was created, it sets the query and starts the process of "sending" the query to polypheny + */ public void start() { - //hardcodeResponse(); if (preparedQueryCycle) { this.query = preparedMessage.getQuery(); } - //int hash = ctx.hashCode(); - sendQueryToPolypheny(); } - private void hardcodeResponse() { - - ByteBuf buffer = ctx.alloc().buffer(); - ByteBuf buffer2 = ctx.alloc().buffer(); - ByteBuf buffer3 = ctx.alloc().buffer(); - ByteBuf buffer4 = ctx.alloc().buffer(); - ByteBuf buffer5 = ctx.alloc().buffer(); - /* - 1....2....T......empid...@...............D..........100C....SELECT 1.Z....I - - 1 ... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I - 31 ... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 - T, 0, 1,40, 1,17,0,4 D, 0d, 0, 1, 3, 100 - */ - - /* - //parseComplete - buffer2.writeByte('1'); - //buffer = writeIntArray(nbrs, buffer); - buffer2.writeInt(4); - //bindComplete - buffer2.writeByte('2'); - //buffer = writeIntArray(nbrs2, buffer); - buffer2.writeInt(4); - ctx.writeAndFlush(buffer2); - */ - communicationHandler.sendParseBindComplete(); - - //RowDescription - buffer.writeBytes("T".getBytes(StandardCharsets.UTF_8)); - //buffer.writeShort(23); - //buffer.writeShort(24+"empid".length() +1); //1e --> egal? - buffer.writeInt(24+"empid".length() +1); //egal? -20, +550... - buffer.writeShort(1); //mues stemme --> nbr of fields? - //buffer = writeIntArray(nbrs3, buffer); - buffer.writeBytes("empid".getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); //mues 0 sii... --> wennmers onde macht, ond int zgross esch, gets en fähler... - buffer.writeInt(1); //@ --> egal: 654, 0, 1111111111 - //buffer.writeByte(64); - buffer.writeShort(25); //1 abst. zvel zwösche 40 ond 0c - //buffer.writeByte(0); //0c --> egal (mer cha au d reihefolg zwösche short ond byte wächsle - //buffer.writeShort(1); //egal - //buffer.writeShort(0); - //buffer.writeShort(23); //17 - buffer.writeInt(23); //17 --> egal: 254, 0 - buffer.writeShort(4); //egal: 400, 0 - //ctx.writeAndFlush(buffer); - //buffer = writeIntArray(nbrs4, buffer); - //buffer.writeShort(2147483647); //ff ff - //buffer.writeShort(2147483647); - buffer.writeInt(-1); //statt 2 short (ff wahrsch. -1?), egal: -1, 20, 2550, 0 - //buffer.writeByte(0); - //buffer.writeByte(0); //short statt 2 bytes - buffer.writeShort(0); //0 (54, 111): chonnt 1111111111 ah | 1: 825307441 - - //DataRow - buffer5.writeBytes("D".getBytes(StandardCharsets.UTF_8)); - buffer5.writeInt(20); //egal? --> 20, 200, 400, 0 - //buffer5.writeShort(0); //egal? --> 20, 200 (short met int ersetzt) - //buffer5.writeShort(13); //0d --> chonnt ned wörklech drufah was dren esch... (donkt mi) --> fonktioniert met 1 ond 200 - buffer5.writeShort(1); //das mues stemme, söscht warted de client - //buffer5.writeShort(0); //usegnoh, ond deför onders of int gwächslet - buffer5.writeInt("1111111111".length()); //length of the datatype --> mues stemme, sösch fähler - //buffer5.writeInt(4); //length of the datatype --> mues stemme, sösch fähler --> för writeInt = 4 - //buffer = writeIntArray(nbrs5, buffer); - buffer5.writeBytes("1111111111".getBytes(StandardCharsets.UTF_8)); - //buffer5.writeInt(1111111111); - - //CommandComplete - buffer4.writeBytes("C".getBytes(StandardCharsets.UTF_8)); - buffer4.writeShort(0); - buffer4.writeShort(13); - //buffer2 = writeIntArray(nbrs6, buffer2); - buffer4.writeBytes("SELECT 1".getBytes(StandardCharsets.UTF_8)); - //buffer2 = writeIntArray(nbrs7, buffer2); - buffer4.writeByte(0); - - //ReadyForQuery - buffer3.writeBytes("Z".getBytes(StandardCharsets.UTF_8)); - //buffer2 = writeIntArray(nbrs8, buffer2); - buffer3.writeShort(0); - buffer3.writeShort(5); - buffer3.writeBytes("I".getBytes(StandardCharsets.UTF_8)); - - - ctx.writeAndFlush( buffer ); - ctx.writeAndFlush( buffer5 ); - //ctx.writeAndFlush( buffer4 ); - communicationHandler.sendCommandComplete( "SELECT", 1 ); - //ctx.writeAndFlush( buffer3 ); - communicationHandler.sendReadyForQuery( "I" ); - - } - /** * Forwards the message to Polypheny, and get result from it @@ -197,25 +105,25 @@ public void sendQueryToPolypheny() { ArrayList header = new ArrayList<>(); try { - //get transaction letze linie + //get transaction and statement transaction = transactionManager.startTransaction( Catalog.defaultUserId, Catalog.defaultDatabaseId, false, "Index Manager" ); statement = transaction.createStatement(); } catch ( UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e ) { - //TODO(FF): stop sending stuff to client... + //TODO(FF): will it continue to send things to the client? errorHandler.sendSimpleErrorMessage("Error while starting transaction" + String.valueOf(e)); throw new RuntimeException( "Error while starting transaction", e ); } try { - if (preparedQueryCycle) { //TODO: nome be execute döfs do ine!! - //TODO(prepared Queries): met dem denn values dezue tue + if (preparedQueryCycle) { preparedMessage.transformDataAndAddParameterValues(statement); - } - //get algRoot --> use it in abstract queryProcessor (prepare query) - example from catalogImpl (461-446) + + //get algRoot Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); Node sqlNode = sqlProcessor.parse(query).get(0); QueryParameters parameters = new QueryParameters(query, Catalog.NamespaceType.RELATIONAL); + if (sqlNode.isA(Kind.DDL)) { result = sqlProcessor.prepareDdl(statement, sqlNode, parameters); type = sqlNode.getKind().name(); @@ -227,14 +135,14 @@ public void sendQueryToPolypheny() { sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, new QueryParameters(query, Catalog.NamespaceType.RELATIONAL)); - //get PolyResult from AlgRoot - use prepareQuery from abstractQueryProcessor (example from findUsages) + //get PolyResult from AlgRoot final QueryProcessor processor = statement.getQueryProcessor(); result = processor.prepareQuery(algRoot, true); - //get type information - from crud.java + //get type information header = getHeader( result ); - //get actual result of query in array - from crud.java + //get actual result of query in array rows = result.getRows( statement, -1 ); data = computeResultData( rows, header ); @@ -242,30 +150,21 @@ public void sendQueryToPolypheny() { type = result.getKind().name(); transaction.commit(); + commitStatus = "Committed"; - - //java.lang.RuntimeException: The table 'emps' is provided by a data source which does not support data modification. - - - //committe of transaction (commitAndFinish (languageCrud) - //transaction.commit(); (try catch --> be catch rollback - - - //handle result, depending on query type sendResultToClient( type, data, header ); - } - } catch (Throwable t) { //TransactionExeption? + + } catch (Throwable t) { List lol = null; - //TODO(FF): stop sending stuff to client... - //log.error( "Caught exception while executing query", e ); + + //TODO(FF): will continue to send things to client after this? String errorMsg = t.getMessage(); errorHandler.sendSimpleErrorMessage(errorMsg); try { transaction.rollback(); commitStatus = "Rolled back"; } catch (TransactionException ex) { - //log.error( "Could not rollback CREATE TABLE statement: {}", ex.getMessage(), ex ); errorHandler.sendSimpleErrorMessage("Error while rolling back"); commitStatus = "Error while rolling back"; } @@ -297,43 +196,6 @@ private ArrayList getHeader( PolyImplementation result ) { } */ - //For each column: If and how it should be sorted - /* - SortState sort; - if ( request.sortState != null && request.sortState.containsKey( columnName ) ) { - sort = request.sortState.get( columnName ); - } else { - sort = new SortState(); - } - */ - - /* - DbColumn dbCol = new DbColumn( - metaData.getName(), - metaData.getType().getPolyType().getTypeName(), - metaData.getType().isNullable() == (ResultSetMetaData.columnNullable == 1), - metaData.getType().getPrecision(), - sort, - filter ); - */ - - //bruuch ich ned wörklech? - /* - // Get column default values - if ( catalogTable != null ) { - try { - if ( catalog.checkIfExistsColumn( catalogTable.id, columnName ) ) { - CatalogColumn catalogColumn = catalog.getColumn( catalogTable.id, columnName ); - if ( catalogColumn.defaultValue != null ) { - dbCol.defaultValue = catalogColumn.defaultValue.value; - } - } - } catch ( UnknownColumnException e ) { - log.error( "Caught exception", e ); - } - } - - */ header.add( new String[]{ columnName, dataType, String.valueOf( precision ) } ); } return header; @@ -341,7 +203,7 @@ private ArrayList getHeader( PolyImplementation result ) { /** - * Transforms the data into Strings. Possble to expand and change it into other datatypes + * Transforms the data into Strings. Possible to expand and change it into other datatypes * @param rows The result-data as object-type * @param header Header-data - additional information about the data (rows) * @return the rows transformed accordingly (right now turned into a string) @@ -393,24 +255,12 @@ private ArrayList computeResultData( List> rows, ArrayLis * @param header Additional information for the data */ public void sendResultToClient( String type, ArrayList data, ArrayList header ) { + //TODO(FF): handle more responses to client switch ( type ) { case "INSERT": case "DROP_TABLE": case "TRUNCATE": case "UPDATE": - - //INSERT oid rows (oid=0, rows = #rows inserted) - //1....2....n....C....INSERT 0 1.Z....I - - //insert into table with several vals (but only 1 row) - /* - client: - P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B............D....P.E... .....S.... - - server: - 1....2....n....C....INSERT 0 1.Z....I - */ - communicationHandler.sendParseBindComplete(); communicationHandler.sendCommandComplete( type, rowsAffected ); communicationHandler.sendReadyForQuery( "I" ); @@ -420,7 +270,6 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... case "CREATE_TABLE": //1....2....n....C....CREATE TABLE.Z....I communicationHandler.sendParseBindComplete(); - //communicationHandler.sendCommandCompleteCreateTable(); communicationHandler.sendCommandComplete( type, -1 ); communicationHandler.sendReadyForQuery( "I" ); @@ -433,11 +282,19 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... String fieldName = ""; //string - column name (field name) (matters) int objectIDTable = 0; //int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) int attributeNoCol = 0; //int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) - int objectIDColDataType = 0; //int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending) + int objectIDColDataType = 0; //int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending, but maybe later) - see comment below int dataTypeSize = 0; //int16 - size of dataType (if formatCode = 1, this needs to be set for colValLength) (doesn't matter to client while sending) int typeModifier = -1; //int32 - The value will generally be -1 (doesn't matter to client while sending) int formatCode = 0; //int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) + /* + There is no list for the OID's of the data types in the postgres documentation. + This list is a hardcoded list from the JDBC driver which contains all values. + One element in the list is a list of these elements: {pgName, OID, sqlType, javaClass, ?} + + private static final Object[][] types = new Object[][]{{"int2", 21, 5, "java.lang.Integer", 1005}, {"int4", 23, 4, "java.lang.Integer", 1007}, {"oid", 26, -5, "java.lang.Long", 1028}, {"int8", 20, -5, "java.lang.Long", 1016}, {"money", 790, 8, "java.lang.Double", 791}, {"numeric", 1700, 2, "java.math.BigDecimal", 1231}, {"float4", 700, 7, "java.lang.Float", 1021}, {"float8", 701, 8, "java.lang.Double", 1022}, {"char", 18, 1, "java.lang.String", 1002}, {"bpchar", 1042, 1, "java.lang.String", 1014}, {"varchar", 1043, 12, "java.lang.String", 1015}, {"text", 25, 12, "java.lang.String", 1009}, {"name", 19, 12, "java.lang.String", 1003}, {"bytea", 17, -2, "[B", 1001}, {"bool", 16, -7, "java.lang.Boolean", 1000}, {"bit", 1560, -7, "java.lang.Boolean", 1561}, {"date", 1082, 91, "java.sql.Date", 1182}, {"time", 1083, 92, "java.sql.Time", 1183}, {"timetz", 1266, 92, "java.sql.Time", 1270}, {"timestamp", 1114, 93, "java.sql.Timestamp", 1115}, {"timestamptz", 1184, 93, "java.sql.Timestamp", 1185}, {"refcursor", 1790, 2012, "java.sql.ResultSet", 2201}, {"json", 114, 1111, "org.postgresql.util.PGobject", 199}, {"point", 600, 1111, "org.postgresql.geometric.PGpoint", 1017}}; + + */ //data int numberOfFields = header.size(); //int16 - number of fields (cols) (matters) @@ -456,7 +313,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... objectIDColDataType = 20; break; case "BOOLEAN": - dataTypeSize = 1; //TODO(FF): wär 1bit --> wie das darstelle?????? + dataTypeSize = 1; //TODO(FF): how exactly is bool sent? acc. to doc. size is 1 bit? objectIDColDataType = 16; break; case "DECIMAL": @@ -483,7 +340,7 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... dataTypeSize = 1; formatCode = 0; break; - case "DATE": //I did not find a list online for all OID's --> more info in javadoc of PGInterfaceServerWriter > writeRowDescripton + case "DATE": //I did not find a list online for all OID's --> more info in comment on init. of oid's case "TIMESTAMP": case "TIME": case "FILE": @@ -525,128 +382,4 @@ P...J.INSERT INTO Album(AlbumId, Title, ArtistId) VALUES (1, 'Hello', 1)...B.... } } - - //(SELECT empid FROM public.emps LIMIT 1) in postgres - /* -1....2....T......empid...@...............D..........100C....SELECT 1.Z....I - -1... . 2... . T ... . . . empid... @ . . . ... . . . . . . . .. D ... . . . ... . 1 0 0 C ... . SELECT 1. Z ... . I -1... 04 32... 04 54 ... 1e . 01 empid... 40 0c . 01 ... 17 . 04 ff ff ff ff .. 44 ... 0d . 01 ... 03 31 30 30 43 ... 0d SELECT 1. 5a ...05 49 - -empid = 65 6d 70 69 64 -SELECT 1 = 53 45 4c 45 43 54 20 31 -(select_abst._1) - */ - - - - //Example of server answer to simple select query (from real server) - /* - 1....2....T......lolid...@...............D..........1D..........2D..........3D..........3D..........3D..........3C... -SELECT 6.Z....I - -(result: 1,2,3,3,3,3) -1: ParseComplete indicator -2: BindComplete indicator -T: RowDescription - specifies the number of fields in a row (can be 0) (as message content!!) - then for each field: - field name (string), lolid - ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 --> kompliziert - attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 - ObjectID of fields data type (Int32), 1 - - Specifies the object ID of the parameter data type. Placing a zero here is equivalent to leaving the type unspecified. - --> apparently specified in parse message (at the end, if 0, then unspecified...) - - data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 --> polypheny website, typedokumentation, mit länge - real and double in polypheny s gliiche --> luege was postgres macht, mind. länge aaluege --> postgresqlStore schauen welche grössen wie gemappt - gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) - - type modifier (meaning of modifier is type-specific) (see pg_attribute.atttypmod) (Int32), 4 - - Format code used for the field (zero(text) or one(binary)) --> if rowDescription is returned from statement variant of DESCRIBE: format code not yet known (always zero) (Int16) - -D: DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: - length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), - value of the col (in format indicated by associated format code) -T: RowDescription - specifies the number of fields in a row (can be 0) (as message content!!) - then for each field: - field name (string), lolid - ObjectID of table (if field can be id'd as col of specific table, otherwise 0) (Int32), 40 --> kompliziert - attributeNbr of col (if field can be id'd as col of specific table, otherwise 0) (Int16), 2 - ObjectID of fields data type (Int32), 1 - - Specifies the object ID of the parameter data type. Placing a zero here is equivalent to leaving the type unspecified. - --> apparently specified in parse message (at the end, if 0, then unspecified...) - - data type size (negative vals = variable-width types) (see pg_type.typlen) (Int16), 17 --> polypheny website, typedokumentation, mit länge - real and double in polypheny s gliiche --> luege was postgres macht, mind. länge aaluege --> postgresqlStore schauen welche grössen wie gemappt - gibt methode um sql type zu holen dort --> luege wies dbms meta macht (avatica generall interface hauptklasse) - - type modifier (meaning of modifier is type-specific) (see pg_attribute.atttypmod) (Int32), 4 - - Format code used for the field (zero(text) or one(binary)) --> if rowDescription is returned from statement variant of DESCRIBE: format code not yet known (always zero) (Int16) - -D: DataRow - length - nbr of col values that follow (possible 0) - then for each column the pair of fields: (int16) - length of the column value (not includes itself) (zero possible, -1: special case - NULL col val (no value bytes follow in the NULL case), (int32) - value of the col (in format indicated by associated format code) (string)00 - -C: CommandComplete - msgBody is commandTag (which sql command was completed) - SET (not in list on website, but "observed in the wild"), - INSERT oid rows (oid=0, rows = #rows inserted), - SELECT rows (rows = #rows retrieved --> used for SELECT and CREATE TABLE AS commands), - UPDATE rows (rows = #rows updated), - DELETE rows (rows = #rows deleted), - MOVE rows (rows = #rows the cursor's position has been changed by (??)), - FETCH rows (rows = #rows that have been retrieved from cursor), - COPY rows (rows = #rows copied --> only on PSQL 8.2 and later) - -Z: Ready for query (tags) - I: idle - - -1....2....T..... lolid...@ . . . ... . . . . . . . ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I -1....2....T.....1 lolid...40 02 . 01 ... 17 . 04 ff ff ff ff ..D..........1D..........2D..........3D..........3D..........3D..........3C...SELECT 6.Z....I -differences from wireshark Data.data (diffs at right position) -ff's format code? - - -from website: -atttypmod int4 -atttypmod records type-specific data supplied at table creation time (for example, the maximum length of a varchar column). -It is passed to type-specific input functions and length coercion functions. The value will generally be -1 for types that do not need atttypmod. - -typlen int2 -For a fixed-size type, typlen is the number of bytes in the internal representation of the type. But for a variable-length type, typlen is negative. --1 indicates a “varlena” type (one that has a length word), -2 indicates a null-terminated C string. - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -1....2....T...S..albumid...@...............title...@...............artistid...@...............D..........1....Hello....1D..........2....Hello....2D..........3....lol....3C...SELECT 3.Z....I -1....2....T...S..albumid...@...............title...@...............artistid...@...............D..........1....Hello....1D..........2....Hello....2D..........3....lol....3C...SELECT 3.Z....I - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -insert: - -P...).INSERT INTO lol(LolId) VALUES (4)...B............D....P.E... .....S.... -1....2....n....C....INSERT 0 1.Z....I -X.... - -n: noData indicator -C: CommandComplete - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -See diary for darstellung with Null (12.10.22) - - r  user flufi database flufi client_encoding UTF8 DateStyle ISO TimeZone Europe/Berlin extra_float_digits 2 - - P " SET extra_float_digits = 3 B E S  - - P 7 SET application_name = 'PostgreSQL JDBC Driver' B E S  - - P ) INSERT INTO lol(LolId) VALUES (3) B D  P E S  - - P  SELECT LolId FROM lol B D P E S  - P  SELECT LolId FROM lol B D P E S  - - - - */ } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 1b98f6ac30..7c7148a059 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -31,7 +31,7 @@ public class PGInterfaceServerHandler extends ChannelInboundHandlerAdapter { TransactionManager transactionManager; PGInterfaceErrorHandler errorHandler; - ArrayList preparedStatementNames = new ArrayList<>(); //safes it for the whole time polypheny is running... + ArrayList preparedStatementNames = new ArrayList<>(); ArrayList preparedMessages = new ArrayList<>(); @@ -40,11 +40,13 @@ public PGInterfaceServerHandler( TransactionManager transactionManager ) { } + /** + * What the handler acutally does - it calls the logic to handle the incoming message + * @param ctx unique for connection + * @param msg incoming message decoded (to string) from decoder + */ @Override public void channelRead( ChannelHandlerContext ctx, Object msg ) { - //StatusService.printInfo(String.format("channel read reached...")); - //this.preparedStatementNames= new ArrayList<>(); - PGInterfaceInboundCommunicationHandler interfaceInboundCommunicationHandler = new PGInterfaceInboundCommunicationHandler( "", ctx, transactionManager ); interfaceInboundCommunicationHandler.decideCycle( msg, this ); } @@ -53,27 +55,38 @@ public void channelRead( ChannelHandlerContext ctx, Object msg ) { @Override public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) { //cause.printStackTrace(); - - // Client wouldn't receive msg, because client already closed connection - //this.errorHandler = new PGInterfaceErrorHandler(ctx); - //errorHandler.sendSimpleErrorMessage(cause.getMessage()); - - //log.error(cause.getMessage()); ctx.close(); } + /** + * adds a name of a prepared statement to the list of names (each name should be unique) + * @param name of the prepared statemnt + */ public void addPreparedStatementNames(String name) { preparedStatementNames.add(name); } + /** + * adds a prepared message (contains info about the prepared message) to the list of prepared messages. The prepared messages are in the same order as the names in the list of names + * @param preparedMessage you want to add to the list + */ public void addPreparedMessage(PGInterfacePreparedMessage preparedMessage) { preparedMessages.add(preparedMessage); } + /** + * returns the list of all names from the prepared statements (each name should be unique) + * @return + */ public ArrayList getPreparedStatementNames() { return preparedStatementNames; } + /** + * gets a prepared message from the list of prepared messages. The prepared messages are in the same order as the names in the list of names + * @param idx the index of the message you want to return + * @return the message from the list at index idx + */ public PGInterfacePreparedMessage getPreparedMessage(int idx) { return preparedMessages.get(idx); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index d84023e5a7..40af36cce9 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -36,6 +36,20 @@ public class PGInterfaceServerWriter { PGInterfaceErrorHandler errorHandler; + /** + * creates a server writer, writes response to client on byteBuf + * @param type what type of message should be written (in method writeOnByteBuf) + * possible types are: + * - s: write 1 string + * - c: write a char (or number) - writeByte + * - i: writes an int32 + * - ss: writes a message with two strings (the strings are safed as one in the msgBody of the pgMsg and are seperated by the delimiter) + * - sss: same as above, but with three strings + * - dr: write dataRow - writes the message dataRow to the client + * @param pgMsg The message object that contains all necessary information to send it to the client + * @param ctx channelHandlerContext specific to the connection + * @param pgInterfaceInboundCommunicationHandler + */ public PGInterfaceServerWriter(String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler) { //TODO(FF): remove type from initialization and pass it through writeOnByteBuf (would be tidier - but works without problem the way it is) this.type = type; @@ -46,7 +60,7 @@ public PGInterfaceServerWriter(String type, PGInterfaceMessage pgMsg, ChannelHan /** - * Handles different cases of writing things on the buffer (e.g. strings, int, etc.) + * Handles different cases of writing things on the buffer (e.g. strings, int, etc. (see in PGInterfaceServerWriter constructor)) * @return The buffer with the message written on it */ public ByteBuf writeOnByteBuf() { @@ -190,13 +204,13 @@ public ByteBuf writeIntHeaderOnByteBuf( char header ) { /** * Special case: write the rowDescription * @param valuesPerCol The values that are needed to be sent in the rowDescription: - * String fieldName, - * int objectIDTable, - * int attributeNoCol, - * int objectIDCol, - * int dataTypeSize, - * int typeModifier, - * int formatCode, + * String fieldName: string - column name (field name) (matters) + * int objectIDTable: int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + * int attributeNoCol: int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + * int objectIDCol: int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending, but maybe later) - see comment where this method is called from + * int dataTypeSize: int16 - size of dataType (if formatCode = 1, this needs to be set for colValLength) (doesn't matter to client while sending) + * int typeModifier: int32 - The value will generally be -1 (doesn't matter to client while sending) + * int formatCode: int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) * @return The buffer with the message written on it */ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { From ad1eb1f25572695cf4a799b940ca515a2583f244 Mon Sep 17 00:00:00 2001 From: Flurina Fischer Date: Wed, 2 Nov 2022 13:39:59 +0100 Subject: [PATCH 56/57] updated codestyle --- .../postgres/PGInterfaceIntegrationTests.java | 131 ++++++------ .../polypheny/db/postgresql/PGInterface.java | 29 ++- .../postgresql/PGInterfaceErrorHandler.java | 38 ++-- ...GInterfaceInboundCommunicationHandler.java | 169 +++++++-------- .../db/postgresql/PGInterfaceMessage.java | 63 +++--- .../PGInterfacePreparedMessage.java | 195 ++++++++++-------- .../postgresql/PGInterfaceQueryHandler.java | 81 ++++---- .../postgresql/PGInterfaceServerHandler.java | 17 +- .../postgresql/PGInterfaceServerWriter.java | 79 +++---- 9 files changed, 405 insertions(+), 397 deletions(-) diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index 17ef14c200..3f133c3853 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -29,8 +29,6 @@ import org.polypheny.db.catalog.exceptions.UnknownTableException; import java.sql.*; -import java.util.ArrayList; -import java.util.List; import java.util.Properties; import static org.junit.Assert.assertEquals; @@ -51,6 +49,7 @@ public class PGInterfaceIntegrationTests { /** * starts an instance of Polypheny and creates a PGInterface, as it does not exist per default + * * @throws SQLException */ @BeforeClass @@ -63,7 +62,7 @@ public static void start() throws SQLException { try ( TestHelper.JdbcConnection polyphenyDbConnection = new TestHelper.JdbcConnection( false ) ) { Connection connection = polyphenyDbConnection.getConnection(); try ( Statement statement = connection.createStatement() ) { - statement.executeUpdate("ALTER INTERFACES ADD \"pgtestinterface\" USING 'org.polypheny.db.postgresql.PGInterface' WITH '{\"port\":\"5433\"}'"); + statement.executeUpdate( "ALTER INTERFACES ADD \"pgtestinterface\" USING 'org.polypheny.db.postgresql.PGInterface' WITH '{\"port\":\"5433\"}'" ); } } @@ -71,15 +70,16 @@ public static void start() throws SQLException { /** * Cleans up after the tests + * * @throws SQLException */ @AfterClass public static void stop() throws SQLException { - try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection( false ) ) { Connection connection = psqlJdbcConnection.getConnection(); - try(Statement statement = connection.createStatement()) { - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); //statement.executeUpdate( "ALTER INTERFACES DROP pgtestinerface" ); } } @@ -88,22 +88,23 @@ public static void stop() throws SQLException { /** * Test that executes the ddl command CREATE and checks within the database if a table was created + * * @throws SQLException */ @Test public void testIfDDLIsExecuted() throws SQLException { - try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection( false ) ) { Connection connection = psqlJdbcConnection.getConnection(); - try(Statement statement = connection.createStatement()) { - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); - statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - CatalogTable catalogTable = Catalog.getInstance().getTable(Catalog.getInstance().getSchema(Catalog.defaultDatabaseId, "public").id , "PGInterfaceTestTable"); - assertEquals(catalogTable.name, "pginterfacetesttable"); - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); - } catch (UnknownTableException e) { + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); + statement.executeUpdate( "CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))" ); + CatalogTable catalogTable = Catalog.getInstance().getTable( Catalog.getInstance().getSchema( Catalog.defaultDatabaseId, "public" ).id, "PGInterfaceTestTable" ); + assertEquals( catalogTable.name, "pginterfacetesttable" ); + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); + } catch ( UnknownTableException e ) { e.printStackTrace(); - } catch (UnknownSchemaException e) { + } catch ( UnknownSchemaException e ) { e.printStackTrace(); } } @@ -112,57 +113,49 @@ public void testIfDDLIsExecuted() throws SQLException { /** * This test executes several SQL-commands via the client, it creates a table, inserts and selects from it. The returned values from the select are tested + * * @throws SQLException */ @Test public void testIfDMLandDDLandDQLIsExecuted() throws SQLException { - try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection( false ) ) { Connection connection = psqlJdbcConnection.getConnection(); - try(Statement statement = connection.createStatement()) { - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); - statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); - statement.executeUpdate("INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);"); - ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); - - TestHelper.checkResultSet( - rs, - ImmutableList.of( - new Object[]{1, "Franz", 1}, - new Object[]{2, "Hello", 2}, - new Object[]{3, "By", 3}) - ); - - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); + statement.executeUpdate( "CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))" ); + statement.executeUpdate( "INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES (1, 'Franz', 1), (2, 'Hello', 2), (3, 'By', 3);" ); + ResultSet rs = statement.executeQuery( "SELECT * FROM pginterfacetesttable;" ); + + TestHelper.checkResultSet( rs, ImmutableList.of( new Object[]{ 1, "Franz", 1 }, new Object[]{ 2, "Hello", 2 }, new Object[]{ 3, "By", 3 } ) ); + + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); } } } /** * Tests if a prepared statement is correctly executed if the PREPARE and EXECUTE statement are sent seperately + * * @throws SQLException */ @Test public void testPreparedAndExecuteInTwoParts() throws SQLException { - try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection( false ) ) { Connection connection = psqlJdbcConnection.getConnection(); - try(Statement statement = connection.createStatement()) { - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); - statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); + statement.executeUpdate( "CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))" ); //ResultSet rss = statement.executeQuery("PREPARE lol (int) AS SELECT empid FROM public.emps WHERE empid = $1; EXECUTE lol (100);"); - statement.executeUpdate("PREPARE testPrepare (int, text, int) AS INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES ($1, $2, $3);"); - statement.executeUpdate("EXECUTE testPrepare (1, 'Franz', 1);"); - ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); + statement.executeUpdate( "PREPARE testPrepare (int, text, int) AS INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES ($1, $2, $3);" ); + statement.executeUpdate( "EXECUTE testPrepare (1, 'Franz', 1);" ); + ResultSet rs = statement.executeQuery( "SELECT * FROM pginterfacetesttable;" ); - TestHelper.checkResultSet( - rs, - ImmutableList.of( - new Object[]{1, "Franz", 1}) - ); + TestHelper.checkResultSet( rs, ImmutableList.of( new Object[]{ 1, "Franz", 1 } ) ); - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); } } } @@ -170,34 +163,32 @@ public void testPreparedAndExecuteInTwoParts() throws SQLException { /** * Tests if a prepared statement is correctly executed if the PREPARE and EXECUTE statement are sent together + * * @throws SQLException */ @Test public void testPreparedAndExecuteInOnePart() throws SQLException { - try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection( false ) ) { Connection connection = psqlJdbcConnection.getConnection(); - try(Statement statement = connection.createStatement()) { - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); - statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))"); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); + statement.executeUpdate( "CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, VarcharTest VARCHAR(255), IntTest INTEGER,PRIMARY KEY (PkIdTest))" ); //ResultSet rss = statement.executeQuery("PREPARE lol (int) AS SELECT empid FROM public.emps WHERE empid = $1; EXECUTE lol (100);"); - statement.executeUpdate("PREPARE testPrepare (int, text, int) AS INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES ($1, $2, $3); EXECUTE testPrepare (1, 'Franz', 1);"); - ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); + statement.executeUpdate( "PREPARE testPrepare (int, text, int) AS INSERT INTO pginterfacetesttable(PkIdTest, VarcharTest, IntTest) VALUES ($1, $2, $3); EXECUTE testPrepare (1, 'Franz', 1);" ); + ResultSet rs = statement.executeQuery( "SELECT * FROM pginterfacetesttable;" ); - TestHelper.checkResultSet( - rs, - ImmutableList.of( - new Object[]{1, "Franz", 1}) - ); + TestHelper.checkResultSet( rs, ImmutableList.of( new Object[]{ 1, "Franz", 1 } ) ); - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); } } } /** * This feature is not yet supported, but it tests if prepared statement are executed correctly using the JDBC framework + * * @throws SQLException */ @Test @@ -205,24 +196,20 @@ public void testPreparedAndExecuteInOnePart() throws SQLException { public void testPreparedUsingJdbc() throws SQLException { //TODO(FF): Prepared Statements using JDBC not yet supported from PGInterface --> read inserted values from bind command (which is not done currently) - try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection(false) ) { + try ( PsqlJdbcConnection psqlJdbcConnection = new PsqlJdbcConnection( false ) ) { Connection connection = psqlJdbcConnection.getConnection(); - try(Statement statement = connection.createStatement()) { - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); - statement.executeUpdate("CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, IntTest INTEGER,PRIMARY KEY (PkIdTest))"); + try ( Statement statement = connection.createStatement() ) { + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); + statement.executeUpdate( "CREATE TABLE pginterfacetesttable(PkIdTest INTEGER NOT NULL, IntTest INTEGER,PRIMARY KEY (PkIdTest))" ); - PreparedStatement pst = connection.prepareStatement("INSERT INTO pginterfacetesttable(PkIdTest, IntTest) VALUES (?, ?)"); - pst.setInt(1, 100); + PreparedStatement pst = connection.prepareStatement( "INSERT INTO pginterfacetesttable(PkIdTest, IntTest) VALUES (?, ?)" ); + pst.setInt( 1, 100 ); pst.execute(); - ResultSet rs = statement.executeQuery("SELECT * FROM pginterfacetesttable;"); + ResultSet rs = statement.executeQuery( "SELECT * FROM pginterfacetesttable;" ); - TestHelper.checkResultSet( - rs, - ImmutableList.of( - new Object[]{1, 100}) - ); + TestHelper.checkResultSet( rs, ImmutableList.of( new Object[]{ 1, 100 } ) ); - statement.executeUpdate("DROP TABLE IF EXISTS public.pginterfacetesttable"); + statement.executeUpdate( "DROP TABLE IF EXISTS public.pginterfacetesttable" ); } } } @@ -239,7 +226,7 @@ public static class PsqlJdbcConnection implements AutoCloseable { private final Connection conn; - public PsqlJdbcConnection(boolean autoCommit ) throws SQLException { + public PsqlJdbcConnection( boolean autoCommit ) throws SQLException { try { Class.forName( "org.postgresql.Driver" ); } catch ( ClassNotFoundException e ) { @@ -249,8 +236,8 @@ public PsqlJdbcConnection(boolean autoCommit ) throws SQLException { log.debug( "Connecting to database @ {}", url ); Properties connectionProps = new Properties(); - connectionProps.setProperty("sslmode", "disable"); - conn = DriverManager.getConnection(url, connectionProps); + connectionProps.setProperty( "sslmode", "disable" ); + conn = DriverManager.getConnection( url, connectionProps ); //conn.setAutoCommit( autoCommit ); } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 93f8558aaa..7612455be3 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -19,22 +19,11 @@ import com.google.common.collect.ImmutableList; import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; +import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.string.StringDecoder; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.StatusService; import org.polypheny.db.catalog.Catalog.QueryLanguage; @@ -47,6 +36,14 @@ import org.polypheny.db.transaction.TransactionManager; import org.polypheny.db.util.Util; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + /** * First point of contact for the PGInterface, setting changes from the UI are handled here @@ -54,12 +51,12 @@ @Slf4j public class PGInterface extends QueryInterface { - @SuppressWarnings("WeakerAccess") + @SuppressWarnings( "WeakerAccess" ) public static final String INTERFACE_NAME = "Postgresql Interface"; - @SuppressWarnings("WeakerAccess") + @SuppressWarnings( "WeakerAccess" ) // TODO: Update description text public static final String INTERFACE_DESCRIPTION = "PostgreSQL-based query interface - in development"; - @SuppressWarnings("WeakerAccess") + @SuppressWarnings( "WeakerAccess" ) public static final List AVAILABLE_SETTINGS = ImmutableList.of( new QueryInterfaceSettingInteger( "port", false, true, false, 5432 ) // new QueryInterfaceSettingInteger( "maxUploadSizeMb", false, true, true, 10000 ), @@ -92,7 +89,7 @@ public PGInterface( TransactionManager transactionManager, Authenticator authent } // Add information page monitoringPage = new MonitoringPage(); - this.transactionManager = transactionManager; + PGInterface.transactionManager = transactionManager; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java index 4de1cdf388..d458b5cfca 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -28,28 +28,30 @@ @Slf4j public class PGInterfaceErrorHandler { + private final ChannelHandlerContext ctx; + private final PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler; private String errorMsg; private Throwable exception; - private ChannelHandlerContext ctx; private PGInterfaceServerWriter serverWriter; - private PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler; /** * Creates a error handler that can send error messages to the client - * @param ctx Is needed to send the error message to the designated client + * + * @param ctx Is needed to send the error message to the designated client * @param pgInterfaceInboundCommunicationHandler Is needed to create PGInterfaceServerWriter to be able to send a error message */ - public PGInterfaceErrorHandler(ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler) { + public PGInterfaceErrorHandler( ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler ) { this.ctx = ctx; this.pgInterfaceInboundCommunicationHandler = pgInterfaceInboundCommunicationHandler; } /** * Sends a simple error message to the client. The severity and other error fields are all fixed. + * * @param errorMsg The message you want to send */ - public void sendSimpleErrorMessage (String errorMsg) { + public void sendSimpleErrorMessage( String errorMsg ) { //Notes on how error messages are sent: /* E...n S ERROR. V ERROR. C 42P01. M relation "public.hihi" does not exist. P 15. F parse_relation. c. L 1360. R parserOpenTable. . Z....I @@ -61,24 +63,24 @@ header, length, severity, severity (gl wie vorher), SQLSTATE code, Message, (Pos */ this.errorMsg = errorMsg; - PGInterfaceMessage pgInterfaceMessage = new PGInterfaceMessage(PGInterfaceHeaders.E, "MockBody", 4, true); - this.serverWriter = new PGInterfaceServerWriter("MockType", pgInterfaceMessage, ctx, pgInterfaceInboundCommunicationHandler); + PGInterfaceMessage pgInterfaceMessage = new PGInterfaceMessage( PGInterfaceHeaders.E, "MockBody", 4, true ); + this.serverWriter = new PGInterfaceServerWriter( "MockType", pgInterfaceMessage, ctx, pgInterfaceInboundCommunicationHandler ); //TODO(FF): An error occurs because of the errormessage on the clientside. It doesn't really matter, because the connection would be terminated anyway and the message itself arrives... LinkedHashMap errorFields = new LinkedHashMap(); - errorFields.put('S', "ERROR"); - errorFields.put('V', "ERROR"); - errorFields.put('C', "0A000"); - errorFields.put('M', errorMsg); - errorFields.put('P', "notImplemented"); - errorFields.put('F', "polypheny"); - errorFields.put('c', ""); - errorFields.put('L', "1360"); - errorFields.put('R', "parserOpenTable"); + errorFields.put( 'S', "ERROR" ); + errorFields.put( 'V', "ERROR" ); + errorFields.put( 'C', "0A000" ); + errorFields.put( 'M', errorMsg ); + errorFields.put( 'P', "notImplemented" ); + errorFields.put( 'F', "polypheny" ); + errorFields.put( 'c', "" ); + errorFields.put( 'L', "1360" ); + errorFields.put( 'R', "parserOpenTable" ); - ByteBuf buffer = serverWriter.writeSimpleErrorMessage(errorFields); - ctx.writeAndFlush(buffer); + ByteBuf buffer = serverWriter.writeSimpleErrorMessage( errorFields ); + ctx.writeAndFlush( buffer ); } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index 03a871f867..ee6f0ea712 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -18,59 +18,54 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; - import lombok.extern.slf4j.Slf4j; import org.polypheny.db.transaction.TransactionManager; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + /** * Manages all incoming communication, not a handler from netty, but called by one */ @Slf4j public class PGInterfaceInboundCommunicationHandler { + private final PGInterfaceErrorHandler errorHandler; String type; ChannelHandlerContext ctx; TransactionManager transactionManager; - private PGInterfaceErrorHandler errorHandler; public PGInterfaceInboundCommunicationHandler( String type, ChannelHandlerContext ctx, TransactionManager transactionManager ) { this.type = type; this.ctx = ctx; this.transactionManager = transactionManager; - this.errorHandler = new PGInterfaceErrorHandler(ctx, this); + this.errorHandler = new PGInterfaceErrorHandler( ctx, this ); } /** * Decides in what cycle (from postgres message flow) the client is: startup-phase, query-phase, etc. - * @param oMsg the incoming message from the client (unchanged) - whole message is interpreted as a string from the netty decoder + * + * @param oMsg the incoming message from the client (unchanged) - whole message is interpreted as a string from the netty decoder * @param pgInterfaceServerHandler is needed to access the saved prepared statements for a connection */ - public void decideCycle(Object oMsg, PGInterfaceServerHandler pgInterfaceServerHandler) { - String msgWithZeroBits = ((String) oMsg); + public void decideCycle( Object oMsg, PGInterfaceServerHandler pgInterfaceServerHandler ) { + String msgWithZeroBits = (( String ) oMsg); String wholeMsg = msgWithZeroBits.replace( "\u0000", "" ); //TODO(FF): simple query phase is not implemented - if ( wholeMsg.substring( 2, 6 ).contains("user") ) { + if ( wholeMsg.substring( 2, 6 ).contains( "user" ) ) { startUpPhase(); - } - - else if ( wholeMsg.substring( 0, 1 ).equals("P") ) { + } else if ( wholeMsg.charAt( 0 ) == 'P' ) { extendedQueryPhase( wholeMsg, pgInterfaceServerHandler ); - } - - else if ( wholeMsg.substring( 0, 1 ).equals("X") ) { + } else if ( wholeMsg.charAt( 0 ) == 'X' ) { //TODO(FF): (low prio, bcs everything works as inteded, but) seems to never be reached, instead in PGInterfaceServerHandler the exception is reached... maybe client closes connection and netty realizes this and stops handler terminateConnection(); - } - else if ( wholeMsg.substring( 0, 1 ).equals("Q")) { + } else if ( wholeMsg.charAt( 0 ) == 'Q' ) { simpleQueryPhase(); - } - else { - errorHandler.sendSimpleErrorMessage("The incoming message could not be parsed by the PGInterface."); + } else { + errorHandler.sendSimpleErrorMessage( "The incoming message could not be parsed by the PGInterface." ); } } @@ -82,12 +77,12 @@ else if ( wholeMsg.substring( 0, 1 ).equals("Q")) { public void startUpPhase() { //authenticationOk PGInterfaceMessage authenticationOk = new PGInterfaceMessage( PGInterfaceHeaders.R, "0", 8, false ); - PGInterfaceServerWriter authenticationOkWriter = new PGInterfaceServerWriter( "i", authenticationOk, ctx, this); + PGInterfaceServerWriter authenticationOkWriter = new PGInterfaceServerWriter( "i", authenticationOk, ctx, this ); ctx.writeAndFlush( authenticationOkWriter.writeOnByteBuf() ); //server_version (Parameter Status message) - PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage(PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true); - PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter( "ss", parameterStatusServerVs, ctx, this); + PGInterfaceMessage parameterStatusServerVs = new PGInterfaceMessage( PGInterfaceHeaders.S, "server_version" + PGInterfaceMessage.getDelimiter() + "14", 4, true ); + PGInterfaceServerWriter parameterStatusServerVsWriter = new PGInterfaceServerWriter( "ss", parameterStatusServerVs, ctx, this ); ctx.writeAndFlush( parameterStatusServerVsWriter.writeOnByteBuf() ); //ReadyForQuery @@ -102,7 +97,7 @@ public void simpleQueryPhase() { //TODO(FF): (low priority) The simple query phase is handled a bit differently than the extended query phase. The most important difference is that the simple query phase accepts several queries at once and sends some different response messages (e.g. no parse/bindComplete). //Several queries seperated with ";" - errorHandler.sendSimpleErrorMessage("The simple query phase is not implemented in the PostgreSQL Interface"); + errorHandler.sendSimpleErrorMessage( "The simple query phase is not implemented in the PostgreSQL Interface" ); } @@ -110,18 +105,19 @@ public void simpleQueryPhase() { /** * Handles the steps if we are in the extended query phase. * Sends necessary responses to client (without really setting anything in backend) and prepares the incoming query for usage. Continues query forward to QueryHandler - * @param incomingMsg unchanged incoming message (transformed to string by netty) + * + * @param incomingMsg unchanged incoming message (transformed to string by netty) * @param pgInterfaceServerHandler is needed to access the saved prepared statements for a connection */ - public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgInterfaceServerHandler) { + public void extendedQueryPhase( String incomingMsg, PGInterfaceServerHandler pgInterfaceServerHandler ) { - if ( incomingMsg.substring( 2, 5 ).equals( "SET" ) ) { + if ( incomingMsg.startsWith( "SET", 2 ) ) { //TODO(FF): actually handle the SET commands (e.g. SET extra_float_digits = 3) sendParseBindComplete(); - sendCommandComplete("SET", -1); + sendCommandComplete( "SET", -1 ); sendReadyForQuery( "I" ); - } else if (incomingMsg.substring(2, 9).equals("PREPARE")) { + } else if ( incomingMsg.startsWith( "PREPARE", 2 ) ) { //TODO(FF): Hanlde prepared statements sent via JDBC framework - they don't contain the PREPARE and EXECUTE commands (don't necessarily handle it here) ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); @@ -129,16 +125,16 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn String[] query = extractPreparedQuery( incomingMsg ); String prepareString = query[0]; String executeString = query[1]; - String prepareStringQueryName = extractPreparedQueryName(prepareString); + String prepareStringQueryName = extractPreparedQueryName( prepareString ); //check if name already exists - if (preparedStatementNames.isEmpty() || (!preparedStatementNames.contains(prepareStringQueryName))) { - PGInterfacePreparedMessage preparedMessage = new PGInterfacePreparedMessage(prepareStringQueryName, prepareString, ctx); + if ( preparedStatementNames.isEmpty() || (!preparedStatementNames.contains( prepareStringQueryName )) ) { + PGInterfacePreparedMessage preparedMessage = new PGInterfacePreparedMessage( prepareStringQueryName, prepareString, ctx ); preparedMessage.prepareQuery(); //safe prepared messages for the connection - pgInterfaceServerHandler.addPreparedStatementNames(prepareStringQueryName); - pgInterfaceServerHandler.addPreparedMessage(preparedMessage); + pgInterfaceServerHandler.addPreparedStatementNames( prepareStringQueryName ); + pgInterfaceServerHandler.addPreparedMessage( preparedMessage ); //send response to "prepare" query sendParseBindComplete(); @@ -146,15 +142,15 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn sendCommandComplete( "PREPARE", -1 ); //check if an execute statement was sent along - if (!executeString.isEmpty()) { - String statementName = extractPreparedQueryName(executeString); + if ( !executeString.isEmpty() ) { + String statementName = extractPreparedQueryName( executeString ); //check if name exists already - if (preparedStatementNames.contains(statementName)) { - executePreparedStatement(executeString, statementName, pgInterfaceServerHandler); + if ( preparedStatementNames.contains( statementName ) ) { + executePreparedStatement( executeString, statementName, pgInterfaceServerHandler ); } else { String errorMsg = "There does not exist a prepared statement called" + statementName; - errorHandler.sendSimpleErrorMessage(errorMsg); + errorHandler.sendSimpleErrorMessage( errorMsg ); } } else { @@ -162,27 +158,25 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn } } else { String errorMsg = "There already exists a prepared statement with the name" + prepareStringQueryName + "which has not yet been executed"; - errorHandler.sendSimpleErrorMessage(errorMsg); + errorHandler.sendSimpleErrorMessage( errorMsg ); } - } else if (incomingMsg.substring(2, 9).equals("EXECUTE")) { + } else if ( incomingMsg.startsWith( "EXECUTE", 2 ) ) { ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); //get execute statement - String executeQuery = extractQuery(incomingMsg); - String statementName = extractPreparedQueryName(executeQuery); + String executeQuery = extractQuery( incomingMsg ); + String statementName = extractPreparedQueryName( executeQuery ); //check if name exists already - if (preparedStatementNames.contains(statementName)) { - executePreparedStatement(executeQuery, statementName, pgInterfaceServerHandler); + if ( preparedStatementNames.contains( statementName ) ) { + executePreparedStatement( executeQuery, statementName, pgInterfaceServerHandler ); } else { String errorMsg = "There does not exist a prepared statement called" + statementName; - errorHandler.sendSimpleErrorMessage(errorMsg); + errorHandler.sendSimpleErrorMessage( errorMsg ); } - } - - else { + } else { //"Normal" query String query = extractQuery( incomingMsg ); PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler( query, ctx, this, transactionManager ); @@ -192,17 +186,18 @@ public void extendedQueryPhase(String incomingMsg, PGInterfaceServerHandler pgIn /** * Starts a query handler with the information that the query right now is a prepared query - * @param executeString The string which contains the execute query - * @param statementName The name of the prepared statement + * + * @param executeString The string which contains the execute query + * @param statementName The name of the prepared statement * @param pgInterfaceServerHandler is needed to access the saved prepared statements for a connection */ - private void executePreparedStatement(String executeString, String statementName, PGInterfaceServerHandler pgInterfaceServerHandler) { + private void executePreparedStatement( String executeString, String statementName, PGInterfaceServerHandler pgInterfaceServerHandler ) { ArrayList preparedStatementNames = pgInterfaceServerHandler.getPreparedStatementNames(); // get corresponding prepared message - int idx = preparedStatementNames.indexOf(statementName); - PGInterfacePreparedMessage preparedMessage = pgInterfaceServerHandler.getPreparedMessage(idx); - preparedMessage.setExecuteString(executeString); + int idx = preparedStatementNames.indexOf( statementName ); + PGInterfacePreparedMessage preparedMessage = pgInterfaceServerHandler.getPreparedMessage( idx ); + preparedMessage.setExecuteString( executeString ); preparedMessage.extractAndSetValues(); PGInterfaceQueryHandler queryHandler = new PGInterfaceQueryHandler( preparedMessage, ctx, this, transactionManager ); @@ -234,7 +229,7 @@ public String extractQuery( String incomingMsg ) { if ( idx != -1 ) { query = query.substring( 0, idx - 2 ); } else { - errorHandler.sendSimpleErrorMessage("Something went wrong while extracting the query from the incoming stream"); + errorHandler.sendSimpleErrorMessage( "Something went wrong while extracting the query from the incoming stream" ); //TODO(FF): does it continue to send stuff to the client? (even though he doesn't receives it anymore?) } @@ -244,32 +239,34 @@ public String extractQuery( String incomingMsg ) { /** * extracts the prepared query from the incoming string (cuts all other information/buffer things) + * * @param incomingMsg the message from the client * @return a list of 2 strings. the first element is the prepared query, the second element is empty (if not sent along) or contains the execute query */ - private String[] extractPreparedQuery(String incomingMsg) { - String prepareString = extractQuery(incomingMsg); - String executeString = new String(); + private String[] extractPreparedQuery( String incomingMsg ) { + String prepareString = extractQuery( incomingMsg ); + String executeString = ""; - if (incomingMsg.contains("EXECUTE")) { - executeString = extractExecutePart(incomingMsg); + if ( incomingMsg.contains( "EXECUTE" ) ) { + executeString = extractExecutePart( incomingMsg ); } - String[] result = {prepareString, executeString}; + String[] result = { prepareString, executeString }; return result; } /** * Extracts the execute query if it was sent along with the prepare query + * * @param incomingMsg the incoming message from the client * @return returns the execute query */ - private String extractExecutePart(String incomingMsg) { + private String extractExecutePart( String incomingMsg ) { - int idx = incomingMsg.indexOf("EXECUTE"); - String executeStringWithBufferStuff = incomingMsg.substring(idx, incomingMsg.length()); - String executeString = executeStringWithBufferStuff.split("\\)")[0]; + int idx = incomingMsg.indexOf( "EXECUTE" ); + String executeStringWithBufferStuff = incomingMsg.substring( idx ); + String executeString = executeStringWithBufferStuff.split( "\\)" )[0]; executeString = executeString + ")"; return executeString; @@ -277,15 +274,16 @@ private String extractExecutePart(String incomingMsg) { /** * Extracts the name of the prepared query (also of the execute query) + * * @param cleanedQuery the prepared/execute query without remains from the buffer (zeros in between etc) * @return the name of the prepare statement as a string */ - private String extractPreparedQueryName(String cleanedQuery) { + private String extractPreparedQueryName( String cleanedQuery ) { - String startNamePlusQuery = cleanedQuery.substring(8); - String name = startNamePlusQuery.split("\\(")[0]; + String startNamePlusQuery = cleanedQuery.substring( 8 ); + String name = startNamePlusQuery.split( "\\(" )[0]; - return name.replace(" ", ""); + return name.replace( " ", "" ); } @@ -293,11 +291,11 @@ private String extractPreparedQueryName(String cleanedQuery) { * Creates and sends (flushes on ctx) a readyForQuery message with a tag. The tag is choosable (see below for options). * * @param msgBody tag - current transaction status indicator (possible vals: I (idle, not in transaction block), - * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended) + * T (in transaction block), E (in failed transaction block, queries will be rejected until block is ended) */ - public void sendReadyForQuery(String msgBody) { + public void sendReadyForQuery( String msgBody ) { PGInterfaceMessage readyForQuery = new PGInterfaceMessage( PGInterfaceHeaders.Z, msgBody, 5, false ); - PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx, this); + PGInterfaceServerWriter readyForQueryWriter = new PGInterfaceServerWriter( "c", readyForQuery, ctx, this ); ctx.writeAndFlush( readyForQueryWriter.writeOnByteBuf() ); } @@ -323,7 +321,7 @@ public void sendParseBindComplete() { ByteBuf buffer = ctx.alloc().buffer(); PGInterfaceMessage mockMessage = new PGInterfaceMessage( PGInterfaceHeaders.ONE, "0", 4, true ); - PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter( "i", mockMessage, ctx, this); + PGInterfaceServerWriter headerWriter = new PGInterfaceServerWriter( "i", mockMessage, ctx, this ); buffer = headerWriter.writeIntHeaderOnByteBuf( '1' ); buffer.writeBytes( headerWriter.writeIntHeaderOnByteBuf( '2' ) ); ctx.writeAndFlush( buffer ); @@ -336,14 +334,15 @@ public void sendParseBindComplete() { */ public void sendNoData() { PGInterfaceMessage noData = new PGInterfaceMessage( PGInterfaceHeaders.n, "0", 4, true ); - PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx, this); - ctx.writeAndFlush( noDataWriter.writeIntHeaderOnByteBuf('n') ); + PGInterfaceServerWriter noDataWriter = new PGInterfaceServerWriter( "i", noData, ctx, this ); + ctx.writeAndFlush( noDataWriter.writeIntHeaderOnByteBuf( 'n' ) ); } /** * Sends CommandComplete to client, with choosable command type - * @param command which command is completed (no space afterwards, space is added here) + * + * @param command which command is completed (no space afterwards, space is added here) * @param rowsAffected number of rows affected (if it is not necessary to send a number, put -1, (0 is also possible)) */ public void sendCommandComplete( String command, int rowsAffected ) { @@ -351,34 +350,36 @@ public void sendCommandComplete( String command, int rowsAffected ) { PGInterfaceMessage commandComplete; PGInterfaceServerWriter commandCompleteWriter; - if ( rowsAffected == -1) { + if ( rowsAffected == -1 ) { body = command; } else { - body = command + " " + String.valueOf( rowsAffected ); + body = command + " " + rowsAffected; } commandComplete = new PGInterfaceMessage( PGInterfaceHeaders.C, body, 4, true ); - commandCompleteWriter = new PGInterfaceServerWriter( "s", commandComplete, ctx, this); + commandCompleteWriter = new PGInterfaceServerWriter( "s", commandComplete, ctx, this ); ctx.writeAndFlush( commandCompleteWriter.writeOnByteBuf() ); } /** * Prepares everything to send rowDescription + * * @param numberOfFields how many fields are in a row of the result - * @param valuesPerCol The values that should be sent for each field (information about each column) + * @param valuesPerCol The values that should be sent for each field (information about each column) */ public void sendRowDescription( int numberOfFields, ArrayList valuesPerCol ) { String body = String.valueOf( numberOfFields ); PGInterfaceMessage rowDescription = new PGInterfaceMessage( PGInterfaceHeaders.T, body, 4, true ); //the length here doesn't really matter, because it is calculated seperately in writeRowDescription - PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "i", rowDescription, ctx, this); - ctx.writeAndFlush(rowDescriptionWriter.writeRowDescription(valuesPerCol)); + PGInterfaceServerWriter rowDescriptionWriter = new PGInterfaceServerWriter( "i", rowDescription, ctx, this ); + ctx.writeAndFlush( rowDescriptionWriter.writeRowDescription( valuesPerCol ) ); } /** * Prepares everything to send DataRows, with its corresponding needed information + * * @param data data that should be sent */ public void sendDataRow( ArrayList data ) { @@ -408,7 +409,7 @@ public void sendDataRow( ArrayList data ) { } } dataRow = new PGInterfaceMessage( PGInterfaceHeaders.D, body, colValLength, false ); - dataRowWriter = new PGInterfaceServerWriter( "dr", dataRow, ctx, this); + dataRowWriter = new PGInterfaceServerWriter( "dr", dataRow, ctx, this ); ctx.writeAndFlush( dataRowWriter.writeOnByteBuf() ); body = ""; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 48882a43ca..28122c7542 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -25,19 +25,20 @@ @Slf4j public class PGInterfaceMessage { + private static final char delimiter = '§'; //for the subparts + private final boolean defaultLength; private PGInterfaceHeaders header; private String msgBody; private int length; //default is 4, if a different length is mentioned in protocol, this is given - private boolean defaultLength; - private static final char delimiter = '§'; //for the subparts private PGInterfaceErrorHandler errorHandler; /** * Creates a PG-Message. It contains all relevant information to send a message to the client - * @param header What header should be sent (depends on message-type) - * @param msgBody The message itself - * @param length The length of the message (the length itself is included) + * + * @param header What header should be sent (depends on message-type) + * @param msgBody The message itself + * @param length The length of the message (the length itself is included) * @param defaultLength The length of the length sent (which is included). Length is 4 */ public PGInterfaceMessage( PGInterfaceHeaders header, String msgBody, int length, boolean defaultLength ) { @@ -47,18 +48,32 @@ public PGInterfaceMessage( PGInterfaceHeaders header, String msgBody, int length this.defaultLength = defaultLength; } + /** + * Get what delimiter is currently set + * + * @return the current delimiter as string + */ + public static String getDelimiter() { + String del = String.valueOf( delimiter ); + return del; + } /** * get the header of the message + * * @return PGInterfaceHeader of the message */ public PGInterfaceHeaders getHeader() { return this.header; } + public void setHeader( PGInterfaceHeaders header ) { + this.header = header; + } /** * returns the PGInterfaceHeader of the Message as a char + * * @return PGInterfaceHeader as a char */ public char getHeaderChar() { @@ -81,15 +96,15 @@ public char getHeaderChar() { } } //TODO(FF): does it continue to send things to the client after the error message? - errorHandler.sendSimpleErrorMessage("PGInterface>PGInterfaceMessage>getHeaderChar: This should never be reached."); + errorHandler.sendSimpleErrorMessage( "PGInterface>PGInterfaceMessage>getHeaderChar: This should never be reached." ); return 0; } - /** * Changes the three headers that are a number and not a letter into a number (they are safed as a string in the PGInterfaceHeaders) - * @return 1,2 or 3 - headers which are numbers + * + * @return 1, 2 or 3 - headers which are numbers */ public int getHeaderInt() { String headerString = header.toString(); @@ -101,61 +116,55 @@ public int getHeaderInt() { return 3; } //TODO(FF): does it continue to send things to the client after the error message? - errorHandler.sendSimpleErrorMessage("PGInterface>PGInterfaceMessage>getHeaderInt: This should never be reached."); + errorHandler.sendSimpleErrorMessage( "PGInterface>PGInterfaceMessage>getHeaderInt: This should never be reached." ); return 0; } - - public void setHeader( PGInterfaceHeaders header ) { - this.header = header; - } - - /** * the length that should be set in the message to the client (default is 4) + * * @return length of the message */ public int getLength() { return this.length; } - /** * set the length of the message to the client (the default is set to 4) + * * @param length length you want to set as the message length */ public void setLength( int length ) { this.length = length; } - /** * if the message has the default length (4) + * * @return whether the message has the default length */ public boolean isDefaultLength() { return this.defaultLength; } - /** * The content of the message that will be sent to the client, can contain several "sub" messages (message fields) which are seperated by the delimiter + * * @return message to the client */ public String getMsgBody() { return msgBody; } - /** * Set the content of the message that will be sent to the client, can contain several "sub" messages (message fields) which are seperated by the delimiter + * * @param msgBody message to the client */ public void setMsgBody( String msgBody ) { this.msgBody = msgBody; } - /** * Gets the different sub-parts of a message, which are seperated by the delimiter * @@ -163,8 +172,8 @@ public void setMsgBody( String msgBody ) { * @return a string array with each requested part */ public String[] getMsgPart( int[] part ) { - String subStrings[] = msgBody.split( getDelimiter() ); - String result[] = new String[part.length]; + String[] subStrings = msgBody.split( getDelimiter() ); + String[] result = new String[part.length]; for ( int i = 0; i < (part.length); i++ ) { result[i] = subStrings[i]; @@ -172,14 +181,4 @@ public String[] getMsgPart( int[] part ) { return result; } - - /** - * Get what delimiter is currently set - * @return the current delimiter as string - */ - public static String getDelimiter() { - String del = String.valueOf( delimiter ); - return del; - } - } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index b561e49fed..cb55173d28 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -18,7 +18,6 @@ import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; -import org.polypheny.db.adapter.DataContext; import org.polypheny.db.algebra.type.AlgDataType; import org.polypheny.db.transaction.Statement; import org.polypheny.db.type.PolyType; @@ -30,26 +29,27 @@ */ @Slf4j public class PGInterfacePreparedMessage { - private String name; - private ChannelHandlerContext ctx; + private static final String executeDelimiter = ", "; + private final String name; + private final ChannelHandlerContext ctx; + private final Map typesPolyphey = new HashMap(); + private final List> valuesPolypeny = new ArrayList>(); private String query; private String wholePrepareString; private String executeString; private List dataTypes; private List data; - private static final String executeDelimiter = ", "; - private Map typesPolyphey = new HashMap(); - private List> valuesPolypeny = new ArrayList>(); private PGInterfaceErrorHandler errorHandler; /** * Creates the message itself - * @param name name of the prepared statement + * + * @param name name of the prepared statement * @param wholePrepareString the string which contains the prepared statement - * @param ctx channelHandlerContext from the current connection + * @param ctx channelHandlerContext from the current connection */ - public PGInterfacePreparedMessage(String name, String wholePrepareString, ChannelHandlerContext ctx) { + public PGInterfacePreparedMessage( String name, String wholePrepareString, ChannelHandlerContext ctx ) { this.name = name; this.wholePrepareString = wholePrepareString; this.ctx = ctx; @@ -57,100 +57,118 @@ public PGInterfacePreparedMessage(String name, String wholePrepareString, Channe /** * Creates the message itself + * * @param name name of the prepared statement - * @param ctx channelHandlerContext from the current connection + * @param ctx channelHandlerContext from the current connection */ - public PGInterfacePreparedMessage(String name, ChannelHandlerContext ctx) { + public PGInterfacePreparedMessage( String name, ChannelHandlerContext ctx ) { this.name = name; this.ctx = ctx; } /** - * Sets the query itself (without prepare etc) - * @param query The "pure" query + * The delimiter that seperates the values in the execute query + * + * @return a string sequence which is the delimiter in the execute query */ - public void setQuery(String query) { - this.query = query; + public static String getExecuteDelimiter() { + return executeDelimiter; } /** * the "whole" execute query + * * @param executeString execute query */ - public void setExecuteString(String executeString) { + public void setExecuteString( String executeString ) { this.executeString = executeString; } /** * the "whole" prepare query + * * @param wholePrepareString prepare query */ - public void setWholePrepareString(String wholePrepareString) { + public void setWholePrepareString( String wholePrepareString ) { this.wholePrepareString = wholePrepareString; } /** - * the data types from the prepare query - * @param dataTypes a list if all types (in the right order) from the prepare query + * The "pure" query (without prepare etc.) + * + * @return the query itself (without prepare etc.) */ - private void setDataTypes(List dataTypes) { this.dataTypes = dataTypes; } + public String getQuery() { + return query; + } /** - * The values that will be inserted into the prepare query - * @param data the values that will be inserted into the prepare query as string (since they arrive as string from the connection) + * Sets the query itself (without prepare etc) + * + * @param query The "pure" query */ - private void setData(List data) { this.data = data; } + public void setQuery( String query ) { + this.query = query; + } - /** - * The delimiter that seperates the values in the execute query - * @return a string sequence which is the delimiter in the execute query - */ - public static String getExecuteDelimiter() {return executeDelimiter;} + public List getDataTypes() { + return dataTypes; + } /** - * The "pure" query (without prepare etc.) - * @return the query itself (without prepare etc.) + * the data types from the prepare query + * + * @param dataTypes a list if all types (in the right order) from the prepare query */ - public String getQuery() { return query;} - - public List getDataTypes() { return dataTypes;} + private void setDataTypes( List dataTypes ) { + this.dataTypes = dataTypes; + } /** * Gets the values from the execute query + * * @return values from the execute query as string */ - public List getData() { return data;} + public List getData() { + return data; + } + + /** + * The values that will be inserted into the prepare query + * + * @param data the values that will be inserted into the prepare query as string (since they arrive as string from the connection) + */ + private void setData( List data ) { + this.data = data; + } /** * From the execute string it extracts the values that will be inserted into the prepare query, sets these values in the message */ public void extractAndSetValues() { - //us execute string - seperator: ', ' - //bool ersetze... - //cut string at ( and ) (remove chlammere) --> denn mach eif. split, ond problem solved... - String onlyExecuteValues = executeString.split("\\(|\\)")[1]; - List valueList = Arrays.asList(onlyExecuteValues.split(getExecuteDelimiter())); - setData(valueList); + String onlyExecuteValues = executeString.split( "\\(|\\)" )[1]; + List valueList = Arrays.asList( onlyExecuteValues.split( getExecuteDelimiter() ) ); + setData( valueList ); } /** * From the prepare string it extracts the data types for the values to be inserted, sets these in the message */ public void extractAndSetTypes() { - String types = wholePrepareString.split("\\(|\\)")[1]; - List typeList = Arrays.asList(types.split(getExecuteDelimiter())); + String types = wholePrepareString.split( "\\(|\\)" )[1]; + List typeList = Arrays.asList( types.split( getExecuteDelimiter() ) ); //replace all bool with boolean to match polypheny dt - if (typeList.contains("bool") || typeList.contains("BOOL")) { + if ( typeList.contains( "bool" ) || typeList.contains( "BOOL" ) ) { ListIterator iterator = typeList.listIterator(); - while (iterator.hasNext()) { + while ( iterator.hasNext() ) { String next = iterator.next(); - if (next.equals("bool")) { - typeList.set(iterator.nextIndex()-1, "BOOLEAN"); + if ( next.equals( "bool" ) ) { + typeList.set( iterator.nextIndex() - 1, "BOOLEAN" ); } } } - setDataTypes(typeList); + setDataTypes( typeList ); } /** @@ -158,14 +176,14 @@ public void extractAndSetTypes() { */ public void changeParameterSymbol() { - String[] parts = wholePrepareString.split("\\$"); - String newPrepareString = new String(); + String[] parts = wholePrepareString.split( "\\$" ); + String newPrepareString = ""; - for (int i = 1; i tried 2 variants below, but both give same error (see bolow below) - // (PREPARE lol (int, text, int) AS INSERT INTO pginterfacetesttable VALUES ($1, $2, $3), ($4, $5, $6); EXECUTE lol (4, 'HALLO', 4, 5, 'x', 5); - //java.lang.RuntimeException: While executing SQL [INSERT INTO "PUBLIC"."tab5_part1004" ("_EXPR$0", "_EXPR$1", "_EXPR$2") - //SELECT CAST(? AS INTEGER), CAST(? AS VARCHAR(255)), CAST(? AS INTEGER) - //FROM (VALUES (0)) AS "t" ("ZERO") - //UNION ALL - //SELECT CAST(? AS INTEGER), CAST(? AS VARCHAR(255)), CAST(? AS INTEGER) - //FROM (VALUES (0)) AS "t" ("ZERO")] on JDBC sub-schema //if o is as long as the number of data types - for (String type : dataTypes) { + for ( String type : dataTypes ) { List o = new ArrayList<>(); - for (int i = 0; i> rows; - private PGInterfaceErrorHandler errorHandler; + private final PGInterfaceErrorHandler errorHandler; public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager ) { @@ -68,7 +64,7 @@ public PGInterfaceQueryHandler( String query, ChannelHandlerContext ctx, PGInter this.ctx = ctx; this.communicationHandler = communicationHandler; this.transactionManager = transactionManager; - this.errorHandler = new PGInterfaceErrorHandler(ctx, communicationHandler); + this.errorHandler = new PGInterfaceErrorHandler( ctx, communicationHandler ); } public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler communicationHandler, TransactionManager transactionManager ) { @@ -77,14 +73,14 @@ public PGInterfaceQueryHandler( PGInterfacePreparedMessage preparedMessage, Chan this.communicationHandler = communicationHandler; this.transactionManager = transactionManager; preparedQueryCycle = true; - this.errorHandler = new PGInterfaceErrorHandler(ctx, communicationHandler); + this.errorHandler = new PGInterfaceErrorHandler( ctx, communicationHandler ); } /** * Depending on how the PGInterfaceQueryHandler was created, it sets the query and starts the process of "sending" the query to polypheny */ public void start() { - if (preparedQueryCycle) { + if ( preparedQueryCycle ) { this.query = preparedMessage.getQuery(); } sendQueryToPolypheny(); @@ -110,34 +106,34 @@ public void sendQueryToPolypheny() { statement = transaction.createStatement(); } catch ( UnknownDatabaseException | GenericCatalogException | UnknownUserException | UnknownSchemaException e ) { //TODO(FF): will it continue to send things to the client? - errorHandler.sendSimpleErrorMessage("Error while starting transaction" + String.valueOf(e)); + errorHandler.sendSimpleErrorMessage( "Error while starting transaction" + e ); throw new RuntimeException( "Error while starting transaction", e ); } try { - if (preparedQueryCycle) { - preparedMessage.transformDataAndAddParameterValues(statement); + if ( preparedQueryCycle ) { + preparedMessage.transformDataAndAddParameterValues( statement ); } //get algRoot - Processor sqlProcessor = statement.getTransaction().getProcessor(Catalog.QueryLanguage.SQL); - Node sqlNode = sqlProcessor.parse(query).get(0); - QueryParameters parameters = new QueryParameters(query, Catalog.NamespaceType.RELATIONAL); + Processor sqlProcessor = statement.getTransaction().getProcessor( Catalog.QueryLanguage.SQL ); + Node sqlNode = sqlProcessor.parse( query ).get( 0 ); + QueryParameters parameters = new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ); - if (sqlNode.isA(Kind.DDL)) { - result = sqlProcessor.prepareDdl(statement, sqlNode, parameters); + if ( sqlNode.isA( Kind.DDL ) ) { + result = sqlProcessor.prepareDdl( statement, sqlNode, parameters ); type = sqlNode.getKind().name(); sendResultToClient( type, data, header ); } else { AlgRoot algRoot = sqlProcessor.translate( statement, - sqlProcessor.validate(statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean()).left, - new QueryParameters(query, Catalog.NamespaceType.RELATIONAL)); + sqlProcessor.validate( statement.getTransaction(), sqlNode, RuntimeConfig.ADD_DEFAULT_VALUES_IN_INSERTS.getBoolean() ).left, + new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ) ); //get PolyResult from AlgRoot final QueryProcessor processor = statement.getQueryProcessor(); - result = processor.prepareQuery(algRoot, true); + result = processor.prepareQuery( algRoot, true ); //get type information header = getHeader( result ); @@ -155,17 +151,17 @@ public void sendQueryToPolypheny() { sendResultToClient( type, data, header ); } - } catch (Throwable t) { - List lol = null; + } catch ( Throwable t ) { + List lol = null; //TODO(FF): will continue to send things to client after this? String errorMsg = t.getMessage(); - errorHandler.sendSimpleErrorMessage(errorMsg); + errorHandler.sendSimpleErrorMessage( errorMsg ); try { transaction.rollback(); commitStatus = "Rolled back"; - } catch (TransactionException ex) { - errorHandler.sendSimpleErrorMessage("Error while rolling back"); + } catch ( TransactionException ex ) { + errorHandler.sendSimpleErrorMessage( "Error while rolling back" ); commitStatus = "Error while rolling back"; } } @@ -174,11 +170,12 @@ public void sendQueryToPolypheny() { /** * Gets the information for the header - Information for each column + * * @param result the PolyImplementation the additional information is needed for * @return a list with array, where: - * - array[0] = columnName - * - array[1] = columnType - * - array[2] = precision + * - array[0] = columnName + * - array[1] = columnType + * - array[2] = precision */ private ArrayList getHeader( PolyImplementation result ) { ArrayList header = new ArrayList<>(); @@ -204,7 +201,8 @@ private ArrayList getHeader( PolyImplementation result ) { /** * Transforms the data into Strings. Possible to expand and change it into other datatypes - * @param rows The result-data as object-type + * + * @param rows The result-data as object-type * @param header Header-data - additional information about the data (rows) * @return the rows transformed accordingly (right now turned into a string) */ @@ -250,8 +248,9 @@ private ArrayList computeResultData( List> rows, ArrayLis /** * Prepares according to the query from the client what (and how) should be sent as a response - * @param type Type of the query (e.g.: Select, Insert, Create Table, etc.) - * @param data The data that needs to be sent to the client + * + * @param type Type of the query (e.g.: Select, Insert, Create Table, etc.) + * @param data The data that needs to be sent to the client * @param header Additional information for the data */ public void sendResultToClient( String type, ArrayList data, ArrayList header ) { @@ -348,15 +347,15 @@ public void sendResultToClient( String type, ArrayList data, ArrayList case "SOUND": case "VIDEO": default: - errorHandler.sendSimpleErrorMessage("The DataType of the answer is not yet implemented, but there is a high chance that the query was executed in Polypheny"); + errorHandler.sendSimpleErrorMessage( "The DataType of the answer is not yet implemented, but there is a high chance that the query was executed in Polypheny" ); break; } - Object col[] = { fieldName, objectIDTable, attributeNoCol, objectIDColDataType, dataTypeSize, typeModifier, formatCode }; + Object[] col = { fieldName, objectIDTable, attributeNoCol, objectIDColDataType, dataTypeSize, typeModifier, formatCode }; valuesPerCol.add( col ); } communicationHandler.sendParseBindComplete(); communicationHandler.sendRowDescription( numberOfFields, valuesPerCol ); - communicationHandler.sendDataRow(data); + communicationHandler.sendDataRow( data ); rowsAffected = data.size(); communicationHandler.sendCommandComplete( type, rowsAffected ); @@ -377,7 +376,7 @@ public void sendResultToClient( String type, ArrayList data, ArrayList //COPY rows (rows = #rows copied --> only on PSQL 8.2 and later)$ default: - errorHandler.sendSimpleErrorMessage("Answer to client is not yet supported, but there is a high chance that the query was executed in Polypheny"); + errorHandler.sendSimpleErrorMessage( "Answer to client is not yet supported, but there is a high chance that the query was executed in Polypheny" ); break; } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 7c7148a059..2e179a64c9 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -42,6 +42,7 @@ public PGInterfaceServerHandler( TransactionManager transactionManager ) { /** * What the handler acutally does - it calls the logic to handle the incoming message + * * @param ctx unique for connection * @param msg incoming message decoded (to string) from decoder */ @@ -60,22 +61,25 @@ public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) { /** * adds a name of a prepared statement to the list of names (each name should be unique) + * * @param name of the prepared statemnt */ - public void addPreparedStatementNames(String name) { - preparedStatementNames.add(name); + public void addPreparedStatementNames( String name ) { + preparedStatementNames.add( name ); } /** * adds a prepared message (contains info about the prepared message) to the list of prepared messages. The prepared messages are in the same order as the names in the list of names + * * @param preparedMessage you want to add to the list */ - public void addPreparedMessage(PGInterfacePreparedMessage preparedMessage) { - preparedMessages.add(preparedMessage); + public void addPreparedMessage( PGInterfacePreparedMessage preparedMessage ) { + preparedMessages.add( preparedMessage ); } /** * returns the list of all names from the prepared statements (each name should be unique) + * * @return */ public ArrayList getPreparedStatementNames() { @@ -84,11 +88,12 @@ public ArrayList getPreparedStatementNames() { /** * gets a prepared message from the list of prepared messages. The prepared messages are in the same order as the names in the list of names + * * @param idx the index of the message you want to return * @return the message from the list at index idx */ - public PGInterfacePreparedMessage getPreparedMessage(int idx) { - return preparedMessages.get(idx); + public PGInterfacePreparedMessage getPreparedMessage( int idx ) { + return preparedMessages.get( idx ); } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 40af36cce9..481c29eabb 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -38,29 +38,31 @@ public class PGInterfaceServerWriter { /** * creates a server writer, writes response to client on byteBuf - * @param type what type of message should be written (in method writeOnByteBuf) - * possible types are: - * - s: write 1 string - * - c: write a char (or number) - writeByte - * - i: writes an int32 - * - ss: writes a message with two strings (the strings are safed as one in the msgBody of the pgMsg and are seperated by the delimiter) - * - sss: same as above, but with three strings - * - dr: write dataRow - writes the message dataRow to the client - * @param pgMsg The message object that contains all necessary information to send it to the client - * @param ctx channelHandlerContext specific to the connection + * + * @param type what type of message should be written (in method writeOnByteBuf) + * possible types are: + * - s: write 1 string + * - c: write a char (or number) - writeByte + * - i: writes an int32 + * - ss: writes a message with two strings (the strings are safed as one in the msgBody of the pgMsg and are seperated by the delimiter) + * - sss: same as above, but with three strings + * - dr: write dataRow - writes the message dataRow to the client + * @param pgMsg The message object that contains all necessary information to send it to the client + * @param ctx channelHandlerContext specific to the connection * @param pgInterfaceInboundCommunicationHandler */ - public PGInterfaceServerWriter(String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler) { + public PGInterfaceServerWriter( String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler ) { //TODO(FF): remove type from initialization and pass it through writeOnByteBuf (would be tidier - but works without problem the way it is) this.type = type; this.pgMsg = pgMsg; this.ctx = ctx; - this.errorHandler = new PGInterfaceErrorHandler(ctx, pgInterfaceInboundCommunicationHandler); + this.errorHandler = new PGInterfaceErrorHandler( ctx, pgInterfaceInboundCommunicationHandler ); } /** * Handles different cases of writing things on the buffer (e.g. strings, int, etc. (see in PGInterfaceServerWriter constructor)) + * * @return The buffer with the message written on it */ public ByteBuf writeOnByteBuf() { @@ -102,7 +104,7 @@ public ByteBuf writeOnByteBuf() { try { body = Integer.parseInt( pgMsg.getMsgBody() ); } catch ( NumberFormatException e ) { - errorHandler.sendSimpleErrorMessage("couldn't transform int to string in PGInterfaceServerWriter" + e.getMessage()); + errorHandler.sendSimpleErrorMessage( "couldn't transform int to string in PGInterfaceServerWriter" + e.getMessage() ); } buffer.writeInt( body ); break; @@ -147,7 +149,7 @@ public ByteBuf writeOnByteBuf() { for ( int i = 0; i < ((nbrCol * 2) - 1); i++ ) { buffer.writeInt( Integer.parseInt( msgParts[i] ) ); - buffer.writeBytes(msgParts[i+1].getBytes(StandardCharsets.UTF_8)); + buffer.writeBytes( msgParts[i + 1].getBytes( StandardCharsets.UTF_8 ) ); i++; } @@ -159,6 +161,7 @@ public ByteBuf writeOnByteBuf() { /** * If there are several Strings that need to be written on the buffer (for example message and tag(s)) - The Strings are in the msgBody, seperated by the delimiter + * * @param nbrStrings How many elements are in the msgBody (seperated by the delimiter) * @return The buffer with the message written on it */ @@ -186,6 +189,7 @@ public ByteBuf writeSeveralStrings( int nbrStrings ) { /** * If the header is a number and not a letter, use this method to write the message (messages with a number as headers don't have a msgBody) + * * @param header The header you want to write on the buffer * @return The buffer with the message written on it */ @@ -203,14 +207,15 @@ public ByteBuf writeIntHeaderOnByteBuf( char header ) { /** * Special case: write the rowDescription + * * @param valuesPerCol The values that are needed to be sent in the rowDescription: - * String fieldName: string - column name (field name) (matters) - * int objectIDTable: int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) - * int attributeNoCol: int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) - * int objectIDCol: int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending, but maybe later) - see comment where this method is called from - * int dataTypeSize: int16 - size of dataType (if formatCode = 1, this needs to be set for colValLength) (doesn't matter to client while sending) - * int typeModifier: int32 - The value will generally be -1 (doesn't matter to client while sending) - * int formatCode: int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) + * String fieldName: string - column name (field name) (matters) + * int objectIDTable: int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + * int attributeNoCol: int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + * int objectIDCol: int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending, but maybe later) - see comment where this method is called from + * int dataTypeSize: int16 - size of dataType (if formatCode = 1, this needs to be set for colValLength) (doesn't matter to client while sending) + * int typeModifier: int32 - The value will generally be -1 (doesn't matter to client while sending) + * int formatCode: int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) * @return The buffer with the message written on it */ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { @@ -233,17 +238,17 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { } buffer.writeInt( pgMsg.getLength() + messageLength ); - buffer.writeShort(Integer.parseInt(pgMsg.getMsgBody())); + buffer.writeShort( Integer.parseInt( pgMsg.getMsgBody() ) ); for ( Object[] oneCol : valuesPerCol ) { ByteBuf bufferTemp = ctx.alloc().buffer(); fieldName = oneCol[0].toString(); - objectIDTable = (Integer) oneCol[1]; - attributeNoCol = (Integer) oneCol[2]; - objectIDCol = (Integer) oneCol[3]; - dataTypeSize = (Integer) oneCol[4]; - typeModifier = (Integer) oneCol[5]; - formatCode = (Integer) oneCol[6]; + objectIDTable = ( Integer ) oneCol[1]; + attributeNoCol = ( Integer ) oneCol[2]; + objectIDCol = ( Integer ) oneCol[3]; + dataTypeSize = ( Integer ) oneCol[4]; + typeModifier = ( Integer ) oneCol[5]; + formatCode = ( Integer ) oneCol[6]; bufferTemp.writeBytes( fieldName.getBytes( StandardCharsets.UTF_8 ) ); bufferTemp.writeByte( 0 ); @@ -260,26 +265,26 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { return buffer; } - public ByteBuf writeSimpleErrorMessage (LinkedHashMap fields) { + public ByteBuf writeSimpleErrorMessage( LinkedHashMap fields ) { ByteBuf buffer = ctx.alloc().buffer(); int msgLength = 4 + 1; - for (String i : fields.values()) { - msgLength += ( i.length() + 1 ); + for ( String i : fields.values() ) { + msgLength += (i.length() + 1); } buffer.writeByte( pgMsg.getHeaderChar() ); buffer.writeInt( msgLength ); - for (String i : fields.values()) { - msgLength += ( i.length() + 1 ); + for ( String i : fields.values() ) { + msgLength += (i.length() + 1); } - fields.forEach((fieldType, fieldValue) -> { - buffer.writeByte(fieldType); - buffer.writeBytes(fieldValue.getBytes(StandardCharsets.UTF_8)); + fields.forEach( ( fieldType, fieldValue ) -> { + buffer.writeByte( fieldType ); + buffer.writeBytes( fieldValue.getBytes( StandardCharsets.UTF_8 ) ); buffer.writeByte( 0 ); - }); + } ); buffer.writeByte( 0 ); From d14f78ec4c13bc70e401bb1c3b33a2af2b7d7a1f Mon Sep 17 00:00:00 2001 From: datomo Date: Thu, 9 Feb 2023 23:47:30 +0100 Subject: [PATCH 57/57] updated to plugin architecture, minor reformatting and adjustment of header files --- .../postgres/PGInterfaceIntegrationTests.java | 20 ++- .../postgresql-interface}/build.gradle | 30 +--- .../postgresql-interface/gradle.properties | 27 ++++ .../polypheny/db/postgresql/PGInterface.java | 33 ++-- .../PGInterfaceErrorFieldTypes.java | 2 +- .../postgresql/PGInterfaceErrorHandler.java | 5 +- .../db/postgresql/PGInterfaceHeaders.java | 2 +- ...GInterfaceInboundCommunicationHandler.java | 7 +- .../db/postgresql/PGInterfaceMessage.java | 2 +- .../PGInterfacePreparedMessage.java | 10 +- .../postgresql/PGInterfaceQueryHandler.java | 12 +- .../postgresql/PGInterfaceServerHandler.java | 5 +- .../postgresql/PGInterfaceServerWriter.java | 142 ++++-------------- .../postgresql/PostgresqlInterfacePlugin.java | 48 ++++++ .../src/main/resources/log4j2.xml | 0 postgresql-interface/lombok.config | 4 - .../polypheny/db/restapi/HttpRestServer.java | 0 17 files changed, 165 insertions(+), 184 deletions(-) rename {postgresql-interface => plugins/postgresql-interface}/build.gradle (53%) create mode 100644 plugins/postgresql-interface/gradle.properties rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterface.java (93%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java (96%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java (98%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java (98%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java (99%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java (99%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java (98%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java (99%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java (98%) rename {postgresql-interface => plugins/postgresql-interface}/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java (63%) create mode 100644 plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterfacePlugin.java rename {postgresql-interface => plugins/postgresql-interface}/src/main/resources/log4j2.xml (100%) delete mode 100644 postgresql-interface/lombok.config delete mode 100644 rest-interface/src/main/java/org/polypheny/db/restapi/HttpRestServer.java diff --git a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java index 3f133c3853..2aea385095 100644 --- a/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java +++ b/dbms/src/test/java/org/polypheny/db/postgres/PGInterfaceIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,16 @@ package org.polypheny.db.postgres; +import static org.junit.Assert.assertEquals; + import com.google.common.collect.ImmutableList; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; import lombok.extern.slf4j.Slf4j; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -28,13 +37,9 @@ import org.polypheny.db.catalog.exceptions.UnknownSchemaException; import org.polypheny.db.catalog.exceptions.UnknownTableException; -import java.sql.*; -import java.util.Properties; - -import static org.junit.Assert.assertEquals; - //import static org.polypheny.db.postgresql.PGInterfaceInboundCommunicationHandler.ctx; + /** * Tests the implementation of the PGInterface --> simulates a client that connects via JDBC */ @@ -68,6 +73,7 @@ public static void start() throws SQLException { } + /** * Cleans up after the tests * @@ -134,6 +140,7 @@ public void testIfDMLandDDLandDQLIsExecuted() throws SQLException { } } + /** * Tests if a prepared statement is correctly executed if the PREPARE and EXECUTE statement are sent seperately * @@ -186,6 +193,7 @@ public void testPreparedAndExecuteInOnePart() throws SQLException { } } + /** * This feature is not yet supported, but it tests if prepared statement are executed correctly using the JDBC framework * diff --git a/postgresql-interface/build.gradle b/plugins/postgresql-interface/build.gradle similarity index 53% rename from postgresql-interface/build.gradle rename to plugins/postgresql-interface/build.gradle index 0413dddda5..6d5adbd8af 100644 --- a/postgresql-interface/build.gradle +++ b/plugins/postgresql-interface/build.gradle @@ -8,8 +8,8 @@ configurations { } dependencies { - implementation project(":core") - implementation project(":monitoring") + compileOnly project(":core") + compileOnly project(":monitoring") ////// NETTY // https://mvnrepository.com/artifact/io.netty/netty-all @@ -23,28 +23,6 @@ dependencies { } -sourceSets { - main { - java { - srcDirs = ["src/main/java"] - outputDir = file(project.buildDir.absolutePath + "/classes") - } - resources { - srcDirs = ["src/main/resources"] - } - output.resourcesDir = file(project.buildDir.absolutePath + "/classes") - } - test { - java { - srcDirs = ["src/test/java"] - outputDir = file(project.buildDir.absolutePath + "/test-classes") - } - resources { - srcDirs = ["src/test/resources"] - } - output.resourcesDir = file(project.buildDir.absolutePath + "/test-classes") - } -} /** @@ -68,3 +46,7 @@ java { withJavadocJar() withSourcesJar() } + +licensee { + allow('Apache-2.0') +} diff --git a/plugins/postgresql-interface/gradle.properties b/plugins/postgresql-interface/gradle.properties new file mode 100644 index 0000000000..fa142a538a --- /dev/null +++ b/plugins/postgresql-interface/gradle.properties @@ -0,0 +1,27 @@ +# +# Copyright 2019-2023 The Polypheny Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +pluginVersion = 0.0.1 + +pluginId = postgres-interface +pluginClass = org.polypheny.db.postgresql.PostgresqlInterfacePlugin +pluginProvider = The Polypheny Project +pluginDependencies = +pluginUrlPath = +pluginCategories = interface +pluginPolyDependencies = +pluginIsSystemComponent = false +pluginIsUiVisible = true \ No newline at end of file diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java similarity index 93% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java index 7612455be3..3914c4bcc3 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterface.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,31 +19,34 @@ import com.google.common.collect.ImmutableList; import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.*; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.string.StringDecoder; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.StatusService; -import org.polypheny.db.catalog.Catalog.QueryLanguage; import org.polypheny.db.iface.Authenticator; import org.polypheny.db.iface.QueryInterface; import org.polypheny.db.information.InformationGroup; import org.polypheny.db.information.InformationManager; import org.polypheny.db.information.InformationPage; import org.polypheny.db.information.InformationTable; +import org.polypheny.db.languages.QueryLanguage; import org.polypheny.db.transaction.TransactionManager; import org.polypheny.db.util.Util; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - /** * First point of contact for the PGInterface, setting changes from the UI are handled here @@ -161,6 +164,12 @@ protected void reloadSettings( List updatedSettings ) { } + @Override + public void languageChange() { + + } + + private class MonitoringPage { //TODO(FF): vergliiche met anderne interfaces (zeigt infos em ui aah) --> sött glaubs ok sii?? @@ -201,7 +210,7 @@ public void update() { DecimalFormat df = new DecimalFormat( "0.0", symbols ); statementsTable.reset(); for ( Map.Entry entry : statementCounters.entrySet() ) { - statementsTable.addRow( entry.getKey().name(), df.format( total == 0 ? 0 : (entry.getValue().longValue() / total) * 100 ) + " %", entry.getValue().longValue() ); + statementsTable.addRow( entry.getKey().getSerializedName(), df.format( total == 0 ? 0 : (entry.getValue().longValue() / total) * 100 ) + " %", entry.getValue().longValue() ); } } diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java similarity index 96% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java index 19cb52b2d3..0e88a68d7e 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorFieldTypes.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java similarity index 98% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java index d458b5cfca..d799a7fef9 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,8 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import lombok.extern.slf4j.Slf4j; - import java.util.LinkedHashMap; +import lombok.extern.slf4j.Slf4j; /** * Writes and sends error messages to the client diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java similarity index 98% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java index 967a6d1390..a8a91f58a1 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java similarity index 99% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java index ee6f0ea712..dd7dcf7006 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceInboundCommunicationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,10 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import lombok.extern.slf4j.Slf4j; -import org.polypheny.db.transaction.TransactionManager; - import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import lombok.extern.slf4j.Slf4j; +import org.polypheny.db.transaction.TransactionManager; /** * Manages all incoming communication, not a handler from netty, but called by one diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java similarity index 99% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java index 28122c7542..1e5c2cb027 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java similarity index 98% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java index cb55173d28..e0d1913d05 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfacePreparedMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +17,17 @@ package org.polypheny.db.postgresql; import io.netty.channel.ChannelHandlerContext; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.algebra.type.AlgDataType; import org.polypheny.db.transaction.Statement; import org.polypheny.db.type.PolyType; -import java.util.*; - /** * Contains information for prepared queries, and also methods to handle the information */ diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java similarity index 99% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java index fbe34c9119..96db8f24f1 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceQueryHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,9 @@ package org.polypheny.db.postgresql; import io.netty.channel.ChannelHandlerContext; +import java.sql.ResultSetMetaData; +import java.util.ArrayList; +import java.util.List; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.PolyImplementation; import org.polypheny.db.algebra.AlgRoot; @@ -28,6 +31,7 @@ import org.polypheny.db.catalog.exceptions.UnknownSchemaException; import org.polypheny.db.catalog.exceptions.UnknownUserException; import org.polypheny.db.config.RuntimeConfig; +import org.polypheny.db.languages.QueryLanguage; import org.polypheny.db.languages.QueryParameters; import org.polypheny.db.nodes.Node; import org.polypheny.db.processing.Processor; @@ -37,10 +41,6 @@ import org.polypheny.db.transaction.TransactionException; import org.polypheny.db.transaction.TransactionManager; -import java.sql.ResultSetMetaData; -import java.util.ArrayList; -import java.util.List; - /** * Handles all queries from the extended query cycle - "sends" them to polypheny and processes answer @@ -116,7 +116,7 @@ public void sendQueryToPolypheny() { } //get algRoot - Processor sqlProcessor = statement.getTransaction().getProcessor( Catalog.QueryLanguage.SQL ); + Processor sqlProcessor = statement.getTransaction().getProcessor( QueryLanguage.from( "sql" ) ); Node sqlNode = sqlProcessor.parse( query ).get( 0 ); QueryParameters parameters = new QueryParameters( query, Catalog.NamespaceType.RELATIONAL ); diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java similarity index 98% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java index 2e179a64c9..b4f46ace58 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,10 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; +import java.util.ArrayList; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.transaction.TransactionManager; -import java.util.ArrayList; - /** * Forwards the message from the "netty flow" to the internal structure */ diff --git a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java similarity index 63% rename from postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java rename to plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java index 481c29eabb..1fd5ec082a 100644 --- a/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PGInterfaceServerWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 The Polypheny Project + * Copyright 2019-2023 The Polypheny Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,10 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import lombok.extern.slf4j.Slf4j; - import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.LinkedHashMap; +import lombok.extern.slf4j.Slf4j; /** * Writes the messages that need to be sent to the client byte-wise on the buffer @@ -39,16 +38,16 @@ public class PGInterfaceServerWriter { /** * creates a server writer, writes response to client on byteBuf * - * @param type what type of message should be written (in method writeOnByteBuf) - * possible types are: - * - s: write 1 string - * - c: write a char (or number) - writeByte - * - i: writes an int32 - * - ss: writes a message with two strings (the strings are safed as one in the msgBody of the pgMsg and are seperated by the delimiter) - * - sss: same as above, but with three strings - * - dr: write dataRow - writes the message dataRow to the client - * @param pgMsg The message object that contains all necessary information to send it to the client - * @param ctx channelHandlerContext specific to the connection + * @param type what type of message should be written (in method writeOnByteBuf) + * possible types are: + * - s: write 1 string + * - c: write a char (or number) - writeByte + * - i: writes an int32 + * - ss: writes a message with two strings (the strings are safed as one in the msgBody of the pgMsg and are seperated by the delimiter) + * - sss: same as above, but with three strings + * - dr: write dataRow - writes the message dataRow to the client + * @param pgMsg The message object that contains all necessary information to send it to the client + * @param ctx channelHandlerContext specific to the connection * @param pgInterfaceInboundCommunicationHandler */ public PGInterfaceServerWriter( String type, PGInterfaceMessage pgMsg, ChannelHandlerContext ctx, PGInterfaceInboundCommunicationHandler pgInterfaceInboundCommunicationHandler ) { @@ -209,13 +208,13 @@ public ByteBuf writeIntHeaderOnByteBuf( char header ) { * Special case: write the rowDescription * * @param valuesPerCol The values that are needed to be sent in the rowDescription: - * String fieldName: string - column name (field name) (matters) - * int objectIDTable: int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) - * int attributeNoCol: int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) - * int objectIDCol: int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending, but maybe later) - see comment where this method is called from - * int dataTypeSize: int16 - size of dataType (if formatCode = 1, this needs to be set for colValLength) (doesn't matter to client while sending) - * int typeModifier: int32 - The value will generally be -1 (doesn't matter to client while sending) - * int formatCode: int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) + * String fieldName: string - column name (field name) (matters) + * int objectIDTable: int32 - ObjectID of table (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + * int attributeNoCol: int16 - attr.no of col (if col can be id'd to table) --> otherwise 0 (doesn't matter to client while sending) + * int objectIDCol: int32 - objectID of parameter datatype --> 0 = unspecified (doesn't matter to client while sending, but maybe later) - see comment where this method is called from + * int dataTypeSize: int16 - size of dataType (if formatCode = 1, this needs to be set for colValLength) (doesn't matter to client while sending) + * int typeModifier: int32 - The value will generally be -1 (doesn't matter to client while sending) + * int formatCode: int16 - 0: Text | 1: Binary --> sends everything with writeBytes(formatCode = 0), if sent with writeInt it needs to be 1 (matters) * @return The buffer with the message written on it */ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { @@ -243,12 +242,12 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { for ( Object[] oneCol : valuesPerCol ) { ByteBuf bufferTemp = ctx.alloc().buffer(); fieldName = oneCol[0].toString(); - objectIDTable = ( Integer ) oneCol[1]; - attributeNoCol = ( Integer ) oneCol[2]; - objectIDCol = ( Integer ) oneCol[3]; - dataTypeSize = ( Integer ) oneCol[4]; - typeModifier = ( Integer ) oneCol[5]; - formatCode = ( Integer ) oneCol[6]; + objectIDTable = (Integer) oneCol[1]; + attributeNoCol = (Integer) oneCol[2]; + objectIDCol = (Integer) oneCol[3]; + dataTypeSize = (Integer) oneCol[4]; + typeModifier = (Integer) oneCol[5]; + formatCode = (Integer) oneCol[6]; bufferTemp.writeBytes( fieldName.getBytes( StandardCharsets.UTF_8 ) ); bufferTemp.writeByte( 0 ); @@ -265,6 +264,7 @@ public ByteBuf writeRowDescription( ArrayList valuesPerCol ) { return buffer; } + public ByteBuf writeSimpleErrorMessage( LinkedHashMap fields ) { ByteBuf buffer = ctx.alloc().buffer(); int msgLength = 4 + 1; @@ -291,95 +291,5 @@ public ByteBuf writeSimpleErrorMessage( LinkedHashMap fields return buffer; } - public ByteBuf writeSeveralStrings(int nbrStrings) { - ByteBuf buffer = ctx.alloc().buffer(); - - buffer.writeByte(pgMsg.getHeaderChar()); - if (pgMsg.isDefaultLength()) { - buffer.writeInt(pgMsg.getLength() + pgMsg.getMsgBody().length() - (nbrStrings -1)); - } - else { - buffer.writeInt(pgMsg.getLength()); - } - - int[] idx = new int[nbrStrings]; - String[] msgParts = pgMsg.getMsgPart(idx); - - for (int i = 0; i < nbrStrings; i++) { - buffer.writeBytes(msgParts[i].getBytes(StandardCharsets.UTF_8)); - buffer.writeByte(0); - } - - return buffer; - } - - public ByteBuf writeIntHeaderOnByteBuf(char header) { - //write a int header... ("i" (for char headers) doesn't work TODO(FF): Figure out a way to do this with case "i" - //since headers with numbers are always indicators, don't I don't check for not standard lengths - ByteBuf buffer = ctx.alloc().buffer(); - - buffer.writeByte(header); - buffer.writeInt(4); // size excluding char - - return buffer; - } - - public ByteBuf writeRowDescription(ArrayList valuesPerCol) { - //I don't check for length, bcs rowDescription is always the same - ByteBuf buffer = ctx.alloc().buffer(); - //ByteBuf bufferTemp = ctx.alloc().buffer(); - String fieldName; - int objectIDTable; - int attributeNoCol; - int objectIDCol; - int dataTypeSize; - int typeModifier; - int formatCode; - - int messageLength = 0; - buffer.writeByte(pgMsg.getHeaderChar()); - - for (int i = 0; i( oder au ned? werom 8????? - - for(Object[] oneCol : valuesPerCol) { - ByteBuf bufferTemp = ctx.alloc().buffer(); - fieldName = oneCol[0].toString(); - objectIDTable = (Integer) oneCol[1]; - attributeNoCol = (Integer) oneCol[2]; - objectIDCol = (Integer) oneCol[3]; - dataTypeSize = (Integer) oneCol[4]; - typeModifier = (Integer) oneCol[5]; - formatCode = (Integer) oneCol[6]; - - //messageLength += (fieldName.length() + 6); - - bufferTemp.writeBytes(fieldName.getBytes(StandardCharsets.UTF_8)); - bufferTemp.writeByte(0); - bufferTemp.writeInt(objectIDTable); - bufferTemp.writeByte(0); - bufferTemp.writeShort(attributeNoCol); - bufferTemp.writeByte(0); - bufferTemp.writeInt(objectIDCol); //objectId of datatype? - bufferTemp.writeByte(0); - bufferTemp.writeShort(dataTypeSize); - bufferTemp.writeByte(0); - bufferTemp.writeInt(typeModifier); - bufferTemp.writeByte(0); - bufferTemp.writeShort(formatCode); //aber bem 4. esch denn do dezwösche en fähler cho, vorem nöchste flushl... werom au emmer??? --> be comission - - buffer.writeBytes(bufferTemp); //die erste 3x gohts ohni fähler - } - - //return buffer.writeBytes(bufferTemp); - //String bla = new String(buffer.array(), Charset.defaultCharset()); - String bla = buffer.toString(Charset.defaultCharset()); - return buffer; - } } diff --git a/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterfacePlugin.java b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterfacePlugin.java new file mode 100644 index 0000000000..bccf3292c0 --- /dev/null +++ b/plugins/postgresql-interface/src/main/java/org/polypheny/db/postgresql/PostgresqlInterfacePlugin.java @@ -0,0 +1,48 @@ +/* + * Copyright 2019-2023 The Polypheny Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.polypheny.db.postgresql; + +import java.util.HashMap; +import java.util.Map; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.polypheny.db.iface.QueryInterfaceManager; + +public class PostgresqlInterfacePlugin extends Plugin { + + /** + * Constructor to be used by plugin manager for plugin instantiation. + * Your plugins have to provide constructor with this exact signature to + * be successfully loaded by manager. + * + * @param wrapper + */ + public PostgresqlInterfacePlugin( PluginWrapper wrapper ) { + super( wrapper ); + } + + + @Override + public void start() { + // Add HTTP interface + Map httpSettings = new HashMap<>(); + httpSettings.put( "port", "5432" ); + httpSettings.put( "maxUploadSizeMb", "10000" ); + QueryInterfaceManager.addInterfaceType( "postgres", PGInterface.class, httpSettings ); + } + +} diff --git a/postgresql-interface/src/main/resources/log4j2.xml b/plugins/postgresql-interface/src/main/resources/log4j2.xml similarity index 100% rename from postgresql-interface/src/main/resources/log4j2.xml rename to plugins/postgresql-interface/src/main/resources/log4j2.xml diff --git a/postgresql-interface/lombok.config b/postgresql-interface/lombok.config deleted file mode 100644 index b034fcb60e..0000000000 --- a/postgresql-interface/lombok.config +++ /dev/null @@ -1,4 +0,0 @@ -# This file is generated by the 'io.freefair.lombok' Gradle plugin -config.stopBubbling = true -lombok.val.flagUsage = error -lombok.var.flagUsage = error diff --git a/rest-interface/src/main/java/org/polypheny/db/restapi/HttpRestServer.java b/rest-interface/src/main/java/org/polypheny/db/restapi/HttpRestServer.java deleted file mode 100644 index e69de29bb2..0000000000