/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ #include "postgres.h" #include "nodes/readfuncs.h" #include "nodes/cypher_readfuncs.h" #include "nodes/cypher_nodes.h" /* * Copied From Postgres * * Macros for declaring appropriate local variables. */ // Declare the extensible node and local fields for the pg_strtok #define READ_LOCALS(nodeTypeName) \ nodeTypeName *local_node = (nodeTypeName *)node; \ char *token; \ int length; /* * The READ_*_FIELD defines first skips the :fildname token (key) part of the string * and then converts the next token (value) to the correct data type. * * pg_strtok will split the passed string by whitespace, skipping whitespace in * strings. We do not setup pg_strtok. That is for the the caller to do. By default * that is the responsibility of Postgres' nodeRead function. We assume that was setup * correctly. */ // Read an integer field (anything written as ":fldname %d") #define READ_INT_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = atoi(token) // Read an unsigned integer field (anything written as ":fldname %u") #define READ_UINT_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = atoui(token) // Read an unsigned integer field (anything written using UINT64_FORMAT) #define READ_UINT64_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = pg_strtouint64(token, NULL, 10) // Read a long integer field (anything written as ":fldname %ld") #define READ_LONG_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = atol(token) // Read an OID field (don't hard-wire assumption that OID is same as uint) #define READ_OID_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = atooid(token) // Read a char field (ie, one ascii character) #define READ_CHAR_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ /* avoid overhead of calling debackslash() for one char */ \ local_node->fldname = (length == 0) ? '\0' : (token[0] == '\\' ? token[1] : token[0]) // Read an enumerated-type field that was written as an integer code #define READ_ENUM_FIELD(fldname, enumtype) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = (enumtype) atoi(token) // Read a float field #define READ_FLOAT_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = atof(token) // Read a boolean field #define READ_BOOL_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = strtobool(token) // Read a character-string field #define READ_STRING_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ local_node->fldname = non_nullable_string(token, length) // Read a parse location field (and throw away the value, per notes above) #define READ_LOCATION_FIELD(fldname) \ token = pg_strtok(&length); \ token = pg_strtok(&length); \ (void) token; \ local_node->fldname = -1 // Read a Node field #define READ_NODE_FIELD(fldname) \ token = pg_strtok(&length); \ (void) token; \ local_node->fldname = nodeRead(NULL, 0) // Read a bitmapset field #define READ_BITMAPSET_FIELD(fldname) \ token = pg_strtok(&length); \ (void) token; \ local_node->fldname = _readBitmapset() // Read an attribute number array #define READ_ATTRNUMBER_ARRAY(fldname, len) \ token = pg_strtok(&length); \ local_node->fldname = readAttrNumberCols(len); // Read an oid array #define READ_OID_ARRAY(fldname, len) \ token = pg_strtok(&length); \ local_node->fldname = readOidCols(len); // Read an int array #define READ_INT_ARRAY(fldname, len) \ token = pg_strtok(&length); \ local_node->fldname = readIntCols(len); // Read a bool array #define READ_BOOL_ARRAY(fldname, len) \ token = pg_strtok(&length); \ local_node->fldname = readBoolCols(len); /* * NOTE: use atoi() to read values written with %d, or atoui() to read * values written with %u in outfuncs.c. An exception is OID values, * for which use atooid(). (As of 7.1, outfuncs.c writes OIDs as %u, * but this will probably change in the future.) */ #define atoui(x) ((unsigned int) strtoul((x), NULL, 10)) #define strtobool(x) ((*(x) == 't') ? true : false) #define nullable_string(token,length) \ ((length) == 0 ? NULL : debackslash(token, length)) #define non_nullable_string(token,length) \ ((length) == 0 ? "" : debackslash(token, length)) /* * Default read function for cypher nodes. For most nodes, we don't expect * the node to ever be read (deserialized). So throw an error. */ void read_ag_node(ExtensibleNode *node) { ereport(ERROR, (errmsg("unexpected parseNodeString() for ag_node"))); } /* * Deserialize a string representing the cypher_create_target_nodes * data structure. */ void read_cypher_create_target_nodes(struct ExtensibleNode *node) { READ_LOCALS(cypher_create_target_nodes); READ_NODE_FIELD(paths); READ_INT_FIELD(flags); READ_OID_FIELD(graph_oid); } /* * Deserialize a string representing the cypher_create_path * data structure. */ void read_cypher_create_path(struct ExtensibleNode *node) { READ_LOCALS(cypher_create_path); READ_NODE_FIELD(target_nodes); READ_INT_FIELD(path_attr_num); READ_STRING_FIELD(var_name); } /* * Deserialize a string representing the cypher_target_node * data structure. */ void read_cypher_target_node(struct ExtensibleNode *node) { READ_LOCALS(cypher_target_node); READ_CHAR_FIELD(type); READ_INT_FIELD(flags); READ_ENUM_FIELD(dir, cypher_rel_dir); READ_NODE_FIELD(id_expr); READ_NODE_FIELD(id_expr_state); READ_NODE_FIELD(prop_expr); READ_NODE_FIELD(prop_expr_state); READ_INT_FIELD(prop_attr_num); READ_NODE_FIELD(resultRelInfo); READ_NODE_FIELD(elemTupleSlot); READ_OID_FIELD(relid); READ_STRING_FIELD(label_name); READ_STRING_FIELD(variable_name); READ_INT_FIELD(tuple_position); } /* * Deserialize a string representing the cypher_update_information * data structure. */ void read_cypher_update_information(struct ExtensibleNode *node) { READ_LOCALS(cypher_update_information); READ_NODE_FIELD(set_items); READ_INT_FIELD(flags); READ_INT_FIELD(tuple_position); READ_STRING_FIELD(graph_name); READ_STRING_FIELD(clause_name); } /* * Deserialize a string representing the cypher_update_item * data structure. */ void read_cypher_update_item(struct ExtensibleNode *node) { READ_LOCALS(cypher_update_item); READ_INT_FIELD(prop_position); READ_INT_FIELD(entity_position); READ_STRING_FIELD(var_name); READ_STRING_FIELD(prop_name); READ_NODE_FIELD(qualified_name); READ_BOOL_FIELD(remove_item); } /* * Deserialize a string representing the cypher_delete_information * data structure. */ void read_cypher_delete_information(struct ExtensibleNode *node) { READ_LOCALS(cypher_delete_information); READ_NODE_FIELD(delete_items); READ_INT_FIELD(flags); READ_STRING_FIELD(graph_name); READ_OID_FIELD(graph_oid); READ_BOOL_FIELD(detach); } /* * Deserialize a string representing the cypher_delete_item * data structure. */ void read_cypher_delete_item(struct ExtensibleNode *node) { READ_LOCALS(cypher_delete_item); READ_NODE_FIELD(entity_position); READ_STRING_FIELD(var_name); } /* * Deserialize a string representing the cypher_merge_information * data structure. */ void read_cypher_merge_information(struct ExtensibleNode *node) { READ_LOCALS(cypher_merge_information); READ_INT_FIELD(flags); READ_OID_FIELD(graph_oid); READ_INT_FIELD(merge_function_attr); READ_NODE_FIELD(path); }